Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b7f046e71 | ||
|
|
fe63704508 | ||
|
|
c39279f677 | ||
|
|
4206f5025d | ||
|
|
0260a4e861 | ||
|
|
244adf0dc3 | ||
|
|
dc6b98d009 | ||
|
|
b20fc5a20b | ||
|
|
f59ad5fd60 | ||
|
|
06ef41e372 | ||
|
|
e215a2db99 | ||
|
|
5e247e88c9 | ||
|
|
8e1e27c868 | ||
|
|
4648a5be8b |
@@ -204,5 +204,6 @@ ENCRYPTION_KEY="0000000000000000000000000000000000000000000000000000000000000000
|
||||
# LANGFUSE_LOG_LEVEL=
|
||||
# LANGFUSE_LEGACY_INGESTION_WORKER_CONCURRENCY=
|
||||
# LANGFUSE_ASYNC_INGESTION_PROCESSING="true"
|
||||
# QUEUE_CONSUMER_LEGACY_INGESTION_QUEUE_IS_ENABLED="true"
|
||||
|
||||
## END Langfuse V3 Ingestion
|
||||
@@ -111,6 +111,10 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }}
|
||||
|
||||
- name: Start Langfuse
|
||||
run: (pnpm run start&)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "langfuse",
|
||||
"version": "2.75.2",
|
||||
"version": "2.76.0",
|
||||
"author": "engineering@langfuse.com",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
"devDependencies": {
|
||||
"@repo/eslint-config": "workspace:*",
|
||||
"@repo/typescript-config": "workspace:*",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/lodash": "^4.17.7",
|
||||
"@types/node": "^20.11.29",
|
||||
"@types/nodemailer": "^6.4.15",
|
||||
"@types/pg": "^8.11.6",
|
||||
|
||||
@@ -2,28 +2,32 @@ import { Queue } from "bullmq";
|
||||
import { QueueName, TQueueJobTypes } from "../queues";
|
||||
import { createNewRedisInstance } from "./redis";
|
||||
|
||||
let legacyIngestionQueue: Queue<
|
||||
TQueueJobTypes[QueueName.LegacyIngestionQueue]
|
||||
> | null = null;
|
||||
export class LegacyIngestionQueue {
|
||||
private static instance: Queue<
|
||||
TQueueJobTypes[QueueName.LegacyIngestionQueue]
|
||||
> | null = null;
|
||||
|
||||
export const getLegacyIngestionQueue = () => {
|
||||
if (legacyIngestionQueue) return legacyIngestionQueue;
|
||||
public static getInstance(): Queue<
|
||||
TQueueJobTypes[QueueName.LegacyIngestionQueue]
|
||||
> | null {
|
||||
if (LegacyIngestionQueue.instance) return LegacyIngestionQueue.instance;
|
||||
|
||||
const newRedis = createNewRedisInstance();
|
||||
const newRedis = createNewRedisInstance({ enableOfflineQueue: false });
|
||||
|
||||
legacyIngestionQueue = newRedis
|
||||
? new Queue<TQueueJobTypes[QueueName.LegacyIngestionQueue]>(
|
||||
QueueName.LegacyIngestionQueue,
|
||||
{
|
||||
connection: newRedis,
|
||||
defaultJobOptions: {
|
||||
removeOnComplete: true,
|
||||
removeOnFail: 100,
|
||||
attempts: 5,
|
||||
LegacyIngestionQueue.instance = newRedis
|
||||
? new Queue<TQueueJobTypes[QueueName.LegacyIngestionQueue]>(
|
||||
QueueName.LegacyIngestionQueue,
|
||||
{
|
||||
connection: newRedis,
|
||||
defaultJobOptions: {
|
||||
removeOnComplete: true,
|
||||
removeOnFail: 100,
|
||||
attempts: 5,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
: null;
|
||||
)
|
||||
: null;
|
||||
|
||||
return legacyIngestionQueue;
|
||||
};
|
||||
return LegacyIngestionQueue.instance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import Redis from "ioredis";
|
||||
import Redis, { RedisOptions } from "ioredis";
|
||||
import { env } from "../../env";
|
||||
|
||||
export const createNewRedisInstance = () => {
|
||||
export const createNewRedisInstance = (
|
||||
additionalOptions: Partial<RedisOptions> = {},
|
||||
) => {
|
||||
return env.REDIS_CONNECTION_STRING
|
||||
? new Redis(env.REDIS_CONNECTION_STRING, {
|
||||
maxRetriesPerRequest: null,
|
||||
enableAutoPipelining: env.REDIS_ENABLE_AUTO_PIPELINING === "true",
|
||||
...additionalOptions,
|
||||
})
|
||||
: env.REDIS_HOST
|
||||
? new Redis({
|
||||
@@ -14,6 +17,7 @@ export const createNewRedisInstance = () => {
|
||||
password: String(env.REDIS_AUTH),
|
||||
maxRetriesPerRequest: null, // Set to `null` to disable retrying
|
||||
enableAutoPipelining: env.REDIS_ENABLE_AUTO_PIPELINING === "true",
|
||||
...additionalOptions,
|
||||
})
|
||||
: null;
|
||||
};
|
||||
|
||||
Generated
+100
-119
@@ -214,8 +214,8 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../config-typescript
|
||||
'@types/lodash':
|
||||
specifier: ^4.17.5
|
||||
version: 4.17.5
|
||||
specifier: ^4.17.7
|
||||
version: 4.17.7
|
||||
'@types/node':
|
||||
specifier: ^20.11.29
|
||||
version: 20.11.29
|
||||
@@ -296,7 +296,7 @@ importers:
|
||||
version: 1.7.18(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@headlessui/tailwindcss':
|
||||
specifier: 0.2.1
|
||||
version: 0.2.1(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
version: 0.2.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
'@heroicons/react':
|
||||
specifier: ^2.1.3
|
||||
version: 2.1.3(react@18.2.0)
|
||||
@@ -452,7 +452,7 @@ importers:
|
||||
version: 0.10.1(typescript@5.4.5)(zod@3.23.8)
|
||||
'@tailwindcss/container-queries':
|
||||
specifier: ^0.1.1
|
||||
version: 0.1.1(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
version: 0.1.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
'@tanstack/react-query':
|
||||
specifier: ^4.36.1
|
||||
version: 4.36.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
@@ -461,7 +461,7 @@ importers:
|
||||
version: 8.13.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@tremor/react':
|
||||
specifier: 3.16.2
|
||||
version: 3.16.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
version: 3.16.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
'@trpc/client':
|
||||
specifier: ^10.45.0
|
||||
version: 10.45.2(@trpc/server@10.45.2)
|
||||
@@ -541,8 +541,8 @@ importers:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
lucide-react:
|
||||
specifier: ^0.429.0
|
||||
version: 0.429.0(react@18.2.0)
|
||||
specifier: ^0.436.0
|
||||
version: 0.436.0(react@18.2.0)
|
||||
next:
|
||||
specifier: ^14.2.6
|
||||
version: 14.2.6(@babel/core@7.24.3)(@opentelemetry/api@1.8.0)(@playwright/test@1.43.1)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
@@ -620,7 +620,7 @@ importers:
|
||||
version: 2.5.2
|
||||
tailwindcss-animate:
|
||||
specifier: ^1.0.7
|
||||
version: 1.0.7(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
version: 1.0.7(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
use-query-params:
|
||||
specifier: ^2.2.1
|
||||
version: 2.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
@@ -649,7 +649,7 @@ importers:
|
||||
version: 1.43.1
|
||||
'@tailwindcss/forms':
|
||||
specifier: ^0.5.7
|
||||
version: 0.5.7(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
version: 0.5.7(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
'@testing-library/jest-dom':
|
||||
specifier: ^6.4.6
|
||||
version: 6.4.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.10.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))(vitest@1.5.3(@types/node@20.10.5)(jsdom@20.0.3))
|
||||
@@ -672,8 +672,8 @@ importers:
|
||||
specifier: ^29.5.12
|
||||
version: 29.5.12
|
||||
'@types/lodash':
|
||||
specifier: ^4.17.5
|
||||
version: 4.17.5
|
||||
specifier: ^4.17.7
|
||||
version: 4.17.7
|
||||
'@types/node':
|
||||
specifier: 20.10.5
|
||||
version: 20.10.5
|
||||
@@ -726,8 +726,8 @@ importers:
|
||||
specifier: ^0.6.6
|
||||
version: 0.6.6(prettier@3.2.5)
|
||||
tailwindcss:
|
||||
specifier: ^3.4.4
|
||||
version: 3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
specifier: ^3.4.10
|
||||
version: 3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@20.10.5)(typescript@5.4.5)
|
||||
@@ -735,8 +735,8 @@ importers:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
tsx:
|
||||
specifier: ^4.18.0
|
||||
version: 4.18.0
|
||||
specifier: ^4.19.0
|
||||
version: 4.19.0
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
@@ -843,8 +843,8 @@ importers:
|
||||
specifier: ^10.2.0
|
||||
version: 10.2.0
|
||||
pino-pretty:
|
||||
specifier: ^10.3.1
|
||||
version: 10.3.1
|
||||
specifier: ^11.2.2
|
||||
version: 11.2.2
|
||||
stripe:
|
||||
specifier: ^16.8.0
|
||||
version: 16.8.0
|
||||
@@ -874,8 +874,8 @@ importers:
|
||||
specifier: ^4.19.3
|
||||
version: 4.19.3
|
||||
'@types/lodash':
|
||||
specifier: ^4.17.5
|
||||
version: 4.17.5
|
||||
specifier: ^4.17.7
|
||||
version: 4.17.7
|
||||
'@types/node':
|
||||
specifier: ^20.11.19
|
||||
version: 20.11.29
|
||||
@@ -904,8 +904,8 @@ importers:
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0(kysely@0.27.4)(pg@8.11.5)
|
||||
msw:
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1(typescript@5.4.5)
|
||||
specifier: ^2.4.1
|
||||
version: 2.4.1(graphql@16.9.0)(typescript@5.4.5)
|
||||
nodemon:
|
||||
specifier: ^3.1.3
|
||||
version: 3.1.3
|
||||
@@ -919,8 +919,8 @@ importers:
|
||||
specifier: ^6.2.0
|
||||
version: 6.2.0(typescript@5.4.5)
|
||||
tsx:
|
||||
specifier: ^4.18.0
|
||||
version: 4.18.0
|
||||
specifier: ^4.19.0
|
||||
version: 4.19.0
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
@@ -1399,6 +1399,9 @@ packages:
|
||||
'@bundled-es-modules/statuses@1.0.1':
|
||||
resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==}
|
||||
|
||||
'@bundled-es-modules/tough-cookie@0.1.6':
|
||||
resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==}
|
||||
|
||||
'@chevrotain/cst-dts-gen@10.5.0':
|
||||
resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==}
|
||||
|
||||
@@ -2233,10 +2236,6 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@mswjs/cookies@1.1.0':
|
||||
resolution: {integrity: sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@mswjs/interceptors@0.29.1':
|
||||
resolution: {integrity: sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -4882,8 +4881,8 @@ packages:
|
||||
'@types/koa__router@12.0.3':
|
||||
resolution: {integrity: sha512-5YUJVv6NwM1z7m6FuYpKfNLTZ932Z6EF6xy2BbtpJSyn13DKNQEkXVffFVSnJHxvwwWh2SAeumpjAYUELqgjyw==}
|
||||
|
||||
'@types/lodash@4.17.5':
|
||||
resolution: {integrity: sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==}
|
||||
'@types/lodash@4.17.7':
|
||||
resolution: {integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==}
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
|
||||
@@ -6638,10 +6637,6 @@ packages:
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
escalade@3.1.2:
|
||||
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
escalade@3.2.0:
|
||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -7245,9 +7240,6 @@ packages:
|
||||
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-tsconfig@4.7.6:
|
||||
resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==}
|
||||
|
||||
get-tsconfig@4.8.0:
|
||||
resolution: {integrity: sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==}
|
||||
|
||||
@@ -8551,8 +8543,8 @@ packages:
|
||||
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
lucide-react@0.429.0:
|
||||
resolution: {integrity: sha512-548DahFy7Ey+0OPlOyZ6ipnbGJzewv8gq2DxDrnAzWZ4RN4+3XyIwQXhD4AQvuREFjS1EnbAgOMaYB0VQyaK1g==}
|
||||
lucide-react@0.436.0:
|
||||
resolution: {integrity: sha512-N292bIxoqm1aObAg0MzFtvhYwgQE6qnIOWx/GLj5ONgcTPH6N0fD9bVq/GfdeC9ZORBXozt/XeEKDpiB3x3vlQ==}
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
|
||||
|
||||
@@ -8900,13 +8892,16 @@ packages:
|
||||
msgpackr@1.10.1:
|
||||
resolution: {integrity: sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==}
|
||||
|
||||
msw@2.3.1:
|
||||
resolution: {integrity: sha512-ocgvBCLn/5l3jpl1lssIb3cniuACJLoOfZu01e3n5dbJrpA5PeeWn28jCLgQDNt6d7QT8tF2fYRzm9JoEHtiig==}
|
||||
msw@2.4.1:
|
||||
resolution: {integrity: sha512-HXcoQPzYTwEmVk+BGIcRa0vLabBT+J20SSSeYh/QfajaK5ceA6dlD4ZZjfz2dqGEq4vRNCPLP6eXsB94KllPFg==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
graphql: '>= 16.8.x'
|
||||
typescript: '>= 4.7.x'
|
||||
peerDependenciesMeta:
|
||||
graphql:
|
||||
optional: true
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
@@ -9467,17 +9462,14 @@ packages:
|
||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
pino-abstract-transport@1.1.0:
|
||||
resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==}
|
||||
|
||||
pino-abstract-transport@1.2.0:
|
||||
resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==}
|
||||
|
||||
pino-http@10.2.0:
|
||||
resolution: {integrity: sha512-am03BxnV3Ckx68OkbH0iZs3indsrH78wncQ6w1w51KroIbvJZNImBKX2X1wjdY8lSyaJ0UrX/dnO2DY3cTeCRw==}
|
||||
|
||||
pino-pretty@10.3.1:
|
||||
resolution: {integrity: sha512-az8JbIYeN/1iLj2t0jR9DV48/LQ3RC6hZPpapKPkb84Q+yTidMCpgWxIT3N0flnBDilyBQ1luWNpOeJptjdp/g==}
|
||||
pino-pretty@11.2.2:
|
||||
resolution: {integrity: sha512-2FnyGir8nAJAqD3srROdrF1J5BIcMT4nwj7hHSc60El6Uxlym00UbCCd8pYIterstVBFlMyF1yFV8XdGIPbj4A==}
|
||||
hasBin: true
|
||||
|
||||
pino-std-serializers@7.0.0:
|
||||
@@ -10407,9 +10399,6 @@ packages:
|
||||
solid-js: ^1.2
|
||||
swr-store: ^0.10
|
||||
|
||||
sonic-boom@3.8.0:
|
||||
resolution: {integrity: sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==}
|
||||
|
||||
sonic-boom@4.0.1:
|
||||
resolution: {integrity: sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==}
|
||||
|
||||
@@ -10715,8 +10704,8 @@ packages:
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || insiders'
|
||||
|
||||
tailwindcss@3.4.4:
|
||||
resolution: {integrity: sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==}
|
||||
tailwindcss@3.4.10:
|
||||
resolution: {integrity: sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -10835,6 +10824,10 @@ packages:
|
||||
resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tough-cookie@4.1.4:
|
||||
resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
|
||||
@@ -10903,8 +10896,8 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
|
||||
|
||||
tsx@4.18.0:
|
||||
resolution: {integrity: sha512-a1jaKBSVQkd6yEc1/NI7G6yHFfefIcuf3QJST7ZEyn4oQnxLYrZR5uZAM8UrwUa3Ge8suiZHcNS1gNrEvmobqg==}
|
||||
tsx@4.19.0:
|
||||
resolution: {integrity: sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -11479,11 +11472,6 @@ packages:
|
||||
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
yaml@2.4.1:
|
||||
resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==}
|
||||
engines: {node: '>= 14'}
|
||||
hasBin: true
|
||||
|
||||
yaml@2.4.5:
|
||||
resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -12422,6 +12410,11 @@ snapshots:
|
||||
dependencies:
|
||||
statuses: 2.0.1
|
||||
|
||||
'@bundled-es-modules/tough-cookie@0.1.6':
|
||||
dependencies:
|
||||
'@types/tough-cookie': 4.0.5
|
||||
tough-cookie: 4.1.4
|
||||
|
||||
'@chevrotain/cst-dts-gen@10.5.0':
|
||||
dependencies:
|
||||
'@chevrotain/gast': 10.5.0
|
||||
@@ -12936,9 +12929,9 @@ snapshots:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
|
||||
'@headlessui/tailwindcss@0.2.1(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))':
|
||||
'@headlessui/tailwindcss@0.2.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))':
|
||||
dependencies:
|
||||
tailwindcss: 3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
tailwindcss: 3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
|
||||
'@heroicons/react@2.1.3(react@18.2.0)':
|
||||
dependencies:
|
||||
@@ -13211,7 +13204,7 @@ snapshots:
|
||||
'@jridgewell/gen-mapping@0.3.5':
|
||||
dependencies:
|
||||
'@jridgewell/set-array': 1.2.1
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
|
||||
'@jridgewell/resolve-uri@3.1.2': {}
|
||||
@@ -13230,7 +13223,7 @@ snapshots:
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.9':
|
||||
dependencies:
|
||||
@@ -13549,8 +13542,6 @@ snapshots:
|
||||
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
|
||||
optional: true
|
||||
|
||||
'@mswjs/cookies@1.1.0': {}
|
||||
|
||||
'@mswjs/interceptors@0.29.1':
|
||||
dependencies:
|
||||
'@open-draft/deferred-promise': 2.2.0
|
||||
@@ -16527,14 +16518,14 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.4.5
|
||||
|
||||
'@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))':
|
||||
'@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))':
|
||||
dependencies:
|
||||
tailwindcss: 3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
tailwindcss: 3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
|
||||
'@tailwindcss/forms@0.5.7(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))':
|
||||
'@tailwindcss/forms@0.5.7(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))':
|
||||
dependencies:
|
||||
mini-svg-data-uri: 1.4.4
|
||||
tailwindcss: 3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
tailwindcss: 3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
|
||||
'@tanstack/query-core@4.36.1': {}
|
||||
|
||||
@@ -16603,11 +16594,11 @@ snapshots:
|
||||
|
||||
'@tootallnate/quickjs-emscripten@0.23.0': {}
|
||||
|
||||
'@tremor/react@3.16.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))':
|
||||
'@tremor/react@3.16.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))':
|
||||
dependencies:
|
||||
'@floating-ui/react': 0.19.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@headlessui/react': 1.7.19(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@headlessui/tailwindcss': 0.2.1(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
'@headlessui/tailwindcss': 0.2.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
date-fns: 2.30.0
|
||||
react: 18.2.0
|
||||
react-day-picker: 8.10.1(date-fns@2.30.0)(react@18.2.0)
|
||||
@@ -16877,7 +16868,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/koa': 2.14.0
|
||||
|
||||
'@types/lodash@4.17.5': {}
|
||||
'@types/lodash@4.17.7': {}
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
dependencies:
|
||||
@@ -19044,8 +19035,6 @@ snapshots:
|
||||
'@esbuild/win32-ia32': 0.23.1
|
||||
'@esbuild/win32-x64': 0.23.1
|
||||
|
||||
escalade@3.1.2: {}
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-goat@4.0.0: {}
|
||||
@@ -19127,7 +19116,7 @@ snapshots:
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.7.6
|
||||
get-tsconfig: 4.8.0
|
||||
is-core-module: 2.15.1
|
||||
is-glob: 4.0.3
|
||||
transitivePeerDependencies:
|
||||
@@ -19144,7 +19133,7 @@ snapshots:
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.7.6
|
||||
get-tsconfig: 4.8.0
|
||||
is-core-module: 2.15.1
|
||||
is-glob: 4.0.3
|
||||
transitivePeerDependencies:
|
||||
@@ -19805,10 +19794,6 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.2.4
|
||||
|
||||
get-tsconfig@4.7.6:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
|
||||
get-tsconfig@4.8.0:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
@@ -21426,7 +21411,7 @@ snapshots:
|
||||
|
||||
lru-cache@7.18.3: {}
|
||||
|
||||
lucide-react@0.429.0(react@18.2.0):
|
||||
lucide-react@0.436.0(react@18.2.0):
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
|
||||
@@ -21981,18 +21966,17 @@ snapshots:
|
||||
optionalDependencies:
|
||||
msgpackr-extract: 3.0.3
|
||||
|
||||
msw@2.3.1(typescript@5.4.5):
|
||||
msw@2.4.1(graphql@16.9.0)(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@bundled-es-modules/cookie': 2.0.0
|
||||
'@bundled-es-modules/statuses': 1.0.1
|
||||
'@bundled-es-modules/tough-cookie': 0.1.6
|
||||
'@inquirer/confirm': 3.1.6
|
||||
'@mswjs/cookies': 1.1.0
|
||||
'@mswjs/interceptors': 0.29.1
|
||||
'@open-draft/until': 2.1.0
|
||||
'@types/cookie': 0.6.0
|
||||
'@types/statuses': 2.0.5
|
||||
chalk: 4.1.2
|
||||
graphql: 16.9.0
|
||||
headers-polyfill: 4.0.3
|
||||
is-node-process: 1.2.0
|
||||
outvariant: 1.4.2
|
||||
@@ -22001,6 +21985,7 @@ snapshots:
|
||||
type-fest: 4.18.2
|
||||
yargs: 17.7.2
|
||||
optionalDependencies:
|
||||
graphql: 16.9.0
|
||||
typescript: 5.4.5
|
||||
|
||||
mustache@4.2.0: {}
|
||||
@@ -22603,11 +22588,6 @@ snapshots:
|
||||
|
||||
pify@2.3.0: {}
|
||||
|
||||
pino-abstract-transport@1.1.0:
|
||||
dependencies:
|
||||
readable-stream: 4.5.2
|
||||
split2: 4.2.0
|
||||
|
||||
pino-abstract-transport@1.2.0:
|
||||
dependencies:
|
||||
readable-stream: 4.5.2
|
||||
@@ -22620,7 +22600,7 @@ snapshots:
|
||||
pino-std-serializers: 7.0.0
|
||||
process-warning: 3.0.0
|
||||
|
||||
pino-pretty@10.3.1:
|
||||
pino-pretty@11.2.2:
|
||||
dependencies:
|
||||
colorette: 2.0.20
|
||||
dateformat: 4.6.3
|
||||
@@ -22630,11 +22610,11 @@ snapshots:
|
||||
joycon: 3.1.1
|
||||
minimist: 1.2.8
|
||||
on-exit-leak-free: 2.1.2
|
||||
pino-abstract-transport: 1.1.0
|
||||
pino-abstract-transport: 1.2.0
|
||||
pump: 3.0.0
|
||||
readable-stream: 4.5.2
|
||||
secure-json-parse: 2.7.0
|
||||
sonic-boom: 3.8.0
|
||||
sonic-boom: 4.0.1
|
||||
strip-json-comments: 3.1.1
|
||||
|
||||
pino-std-serializers@7.0.0: {}
|
||||
@@ -22677,29 +22657,29 @@ snapshots:
|
||||
|
||||
possible-typed-array-names@1.0.0: {}
|
||||
|
||||
postcss-import@15.1.0(postcss@8.4.38):
|
||||
postcss-import@15.1.0(postcss@8.4.41):
|
||||
dependencies:
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.41
|
||||
postcss-value-parser: 4.2.0
|
||||
read-cache: 1.0.0
|
||||
resolve: 1.22.8
|
||||
|
||||
postcss-js@4.0.1(postcss@8.4.38):
|
||||
postcss-js@4.0.1(postcss@8.4.41):
|
||||
dependencies:
|
||||
camelcase-css: 2.0.1
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.41
|
||||
|
||||
postcss-load-config@4.0.2(postcss@8.4.38)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)):
|
||||
postcss-load-config@4.0.2(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)):
|
||||
dependencies:
|
||||
lilconfig: 3.1.1
|
||||
yaml: 2.4.1
|
||||
yaml: 2.4.5
|
||||
optionalDependencies:
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.41
|
||||
ts-node: 10.9.2(@types/node@20.10.5)(typescript@5.4.5)
|
||||
|
||||
postcss-nested@6.0.1(postcss@8.4.38):
|
||||
postcss-nested@6.0.1(postcss@8.4.41):
|
||||
dependencies:
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.41
|
||||
postcss-selector-parser: 6.0.16
|
||||
|
||||
postcss-selector-parser@6.0.16:
|
||||
@@ -23669,10 +23649,6 @@ snapshots:
|
||||
solid-js: 1.8.18
|
||||
swr-store: 0.10.6
|
||||
|
||||
sonic-boom@3.8.0:
|
||||
dependencies:
|
||||
atomic-sleep: 1.0.0
|
||||
|
||||
sonic-boom@4.0.1:
|
||||
dependencies:
|
||||
atomic-sleep: 1.0.0
|
||||
@@ -23906,7 +23882,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
commander: 4.1.1
|
||||
glob: 10.3.12
|
||||
glob: 10.4.5
|
||||
lines-and-columns: 1.2.4
|
||||
mz: 2.7.0
|
||||
pirates: 4.0.6
|
||||
@@ -23985,11 +23961,11 @@ snapshots:
|
||||
|
||||
tailwind-merge@2.5.2: {}
|
||||
|
||||
tailwindcss-animate@1.0.7(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))):
|
||||
tailwindcss-animate@1.0.7(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))):
|
||||
dependencies:
|
||||
tailwindcss: 3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
tailwindcss: 3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
|
||||
tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)):
|
||||
tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)):
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
arg: 5.0.2
|
||||
@@ -24005,11 +23981,11 @@ snapshots:
|
||||
normalize-path: 3.0.0
|
||||
object-hash: 3.0.0
|
||||
picocolors: 1.0.1
|
||||
postcss: 8.4.38
|
||||
postcss-import: 15.1.0(postcss@8.4.38)
|
||||
postcss-js: 4.0.1(postcss@8.4.38)
|
||||
postcss-load-config: 4.0.2(postcss@8.4.38)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
postcss-nested: 6.0.1(postcss@8.4.38)
|
||||
postcss: 8.4.41
|
||||
postcss-import: 15.1.0(postcss@8.4.41)
|
||||
postcss-js: 4.0.1(postcss@8.4.41)
|
||||
postcss-load-config: 4.0.2(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
postcss-nested: 6.0.1(postcss@8.4.41)
|
||||
postcss-selector-parser: 6.0.16
|
||||
resolve: 1.22.8
|
||||
sucrase: 3.35.0
|
||||
@@ -24127,6 +24103,13 @@ snapshots:
|
||||
universalify: 0.2.0
|
||||
url-parse: 1.5.10
|
||||
|
||||
tough-cookie@4.1.4:
|
||||
dependencies:
|
||||
psl: 1.9.0
|
||||
punycode: 2.3.1
|
||||
universalify: 0.2.0
|
||||
url-parse: 1.5.10
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
tr46@3.0.0:
|
||||
@@ -24213,10 +24196,10 @@ snapshots:
|
||||
tslib: 1.14.1
|
||||
typescript: 5.4.5
|
||||
|
||||
tsx@4.18.0:
|
||||
tsx@4.19.0:
|
||||
dependencies:
|
||||
esbuild: 0.23.1
|
||||
get-tsconfig: 4.7.6
|
||||
get-tsconfig: 4.8.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
@@ -24401,7 +24384,7 @@ snapshots:
|
||||
update-browserslist-db@1.0.13(browserslist@4.23.0):
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
escalade: 3.1.2
|
||||
escalade: 3.2.0
|
||||
picocolors: 1.0.1
|
||||
|
||||
update-browserslist-db@1.1.0(browserslist@4.23.3):
|
||||
@@ -24872,8 +24855,6 @@ snapshots:
|
||||
|
||||
yaml@1.10.2: {}
|
||||
|
||||
yaml@2.4.1: {}
|
||||
|
||||
yaml@2.4.5: {}
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
@@ -24881,7 +24862,7 @@ snapshots:
|
||||
yargs@17.7.1:
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
escalade: 3.1.2
|
||||
escalade: 3.2.0
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
string-width: 4.2.3
|
||||
@@ -24891,7 +24872,7 @@ snapshots:
|
||||
yargs@17.7.2:
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
escalade: 3.1.2
|
||||
escalade: 3.2.0
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
string-width: 4.2.3
|
||||
|
||||
+31
-26
@@ -149,39 +149,44 @@ const nextConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
const sentryOptions = {
|
||||
// Additional config options for the Sentry Webpack plugin. Keep in mind that
|
||||
// the following options are set automatically, and overriding them is not
|
||||
// recommended:
|
||||
// release, url, authToken, configFile, stripPrefix,
|
||||
// urlPrefix, include, ignore
|
||||
export default withSentryConfig(nextConfig, {
|
||||
// For all available options, see:
|
||||
// https://github.com/getsentry/sentry-webpack-plugin#options
|
||||
|
||||
org: process.env.SENTRY_ORG,
|
||||
project: process.env.SENTRY_PROJECT,
|
||||
|
||||
silent: true, // Suppresses all logs
|
||||
authToken: env.SENTRY_AUTH_TOKEN,
|
||||
|
||||
// Only print logs for uploading source maps in CI
|
||||
silent: !process.env.CI,
|
||||
|
||||
// For all available options, see:
|
||||
// https://github.com/getsentry/sentry-webpack-plugin#options.
|
||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
||||
|
||||
// See the sections below for information on the following options:
|
||||
// 'Configure Source Maps':
|
||||
// - disableServerWebpackPlugin
|
||||
// - disableClientWebpackPlugin
|
||||
// - hideSourceMaps
|
||||
hideSourceMaps: true,
|
||||
// - widenClientFileUpload
|
||||
// 'Configure Legacy Browser Support':
|
||||
// - transpileClientSDK
|
||||
// 'Configure Serverside Auto-instrumentation':
|
||||
// - autoInstrumentServerFunctions
|
||||
// - excludeServerRoutes
|
||||
// 'Configure Tunneling':
|
||||
// - tunnelRoute
|
||||
// Upload a larger set of source maps for prettier stack traces (increases build time)
|
||||
widenClientFileUpload: true,
|
||||
|
||||
// An auth token is required for uploading source maps.
|
||||
authToken: env.SENTRY_AUTH_TOKEN,
|
||||
// Automatically annotate React components to show their full name in breadcrumbs and session replay
|
||||
reactComponentAnnotation: {
|
||||
enabled: true,
|
||||
},
|
||||
|
||||
// Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
|
||||
// This can increase your server load as well as your hosting bill.
|
||||
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
|
||||
// side errors will fail.
|
||||
tunnelRoute: "/api/monitoring-tunnel",
|
||||
};
|
||||
|
||||
export default withSentryConfig(nextConfig, sentryOptions);
|
||||
// Hides source maps from generated client bundles
|
||||
hideSourceMaps: true,
|
||||
|
||||
// Automatically tree-shake Sentry logger statements to reduce bundle size
|
||||
disableLogger: true,
|
||||
|
||||
// Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
|
||||
// See the following for more information:
|
||||
// https://docs.sentry.io/product/crons/
|
||||
// https://vercel.com/docs/cron-jobs
|
||||
automaticVercelMonitors: false,
|
||||
});
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "2.75.2",
|
||||
"version": "2.76.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -110,7 +110,7 @@
|
||||
"kysely": "^0.27.4",
|
||||
"langchain": "^0.2.6",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.429.0",
|
||||
"lucide-react": "^0.436.0",
|
||||
"next": "^14.2.6",
|
||||
"next-auth": "^4.24.7",
|
||||
"next-query-params": "^5.0.0",
|
||||
@@ -154,7 +154,7 @@
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/eslint": "^8.56.7",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/lodash": "^4.17.7",
|
||||
"@types/node": "20.10.5",
|
||||
"@types/react": "^18.2.79",
|
||||
"@types/react-dom": "^18.2.25",
|
||||
@@ -172,10 +172,10 @@
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-tailwindcss": "^0.6.6",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsx": "^4.18.0",
|
||||
"tsx": "^4.19.0",
|
||||
"typescript": "^5.4.5",
|
||||
"wait-for-expect": "^3.0.2"
|
||||
},
|
||||
|
||||
@@ -548,6 +548,167 @@ describe("Authenticate API calls", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("invalidates api keys in redis", () => {
|
||||
const redis = new Redis("redis://:myredissecret@127.0.0.1:6379", {
|
||||
maxRetriesPerRequest: null,
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// if we do not remove the key, it will remain in the cache and
|
||||
// calling the test twice will not add the key to the cache
|
||||
|
||||
const keys = await redis.keys("api-key*");
|
||||
console.log("before each deleting keys", keys);
|
||||
if (keys.length > 0) {
|
||||
console.log("before each deleting keys. actually deleting", keys);
|
||||
await redis.del(keys);
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// if we do not remove the key, it will remain in the cache and
|
||||
// calling the test twice will not add the key to the cache
|
||||
|
||||
const keys = await redis.keys("api-key*");
|
||||
console.log("after each deleting keys", keys);
|
||||
if (keys.length > 0) {
|
||||
await redis.del(keys);
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
redis.disconnect();
|
||||
});
|
||||
|
||||
it("should invalidate organization API keys in redis", async () => {
|
||||
await createAPIKey();
|
||||
|
||||
// put keys into cache
|
||||
await new ApiAuthService(prisma, redis).verifyAuthHeaderAndReturnScope(
|
||||
"Basic cGstbGYtMTIzNDU2Nzg5MDpzay1sZi0xMjM0NTY3ODkw",
|
||||
);
|
||||
|
||||
await new ApiAuthService(prisma, redis).verifyAuthHeaderAndReturnScope(
|
||||
"Basic cGstbGYtMTIzNDU2Nzg5MDpzay1sZi0xMjM0NTY3ODkw",
|
||||
);
|
||||
|
||||
const apiKey = await prisma.apiKey.findUnique({
|
||||
where: { publicKey: "pk-lf-1234567890" },
|
||||
});
|
||||
expect(apiKey).not.toBeNull();
|
||||
|
||||
const cachedKey = await redis.get(
|
||||
`api-key:${apiKey?.fastHashedSecretKey}`,
|
||||
);
|
||||
expect(cachedKey).not.toBeNull();
|
||||
|
||||
await new ApiAuthService(prisma, redis).invalidateOrgApiKeys(
|
||||
"seed-org-id",
|
||||
);
|
||||
|
||||
const invalidatedCachedKey = await redis.get(
|
||||
`api-key:${apiKey?.fastHashedSecretKey}`,
|
||||
);
|
||||
expect(invalidatedCachedKey).toBeNull();
|
||||
});
|
||||
|
||||
it("if no keys in redis, invalidating org keys should do nothing", async () => {
|
||||
await createAPIKey();
|
||||
|
||||
await prisma.apiKey.update({
|
||||
where: { publicKey: "pk-lf-1234567890" },
|
||||
data: {
|
||||
fastHashedSecretKey: Math.random().toString(36).substring(2, 15),
|
||||
},
|
||||
});
|
||||
|
||||
await new ApiAuthService(prisma, redis).invalidateOrgApiKeys(
|
||||
"seed-org-id",
|
||||
);
|
||||
|
||||
const keys = await redis.keys("api-key*");
|
||||
expect(keys.length).toBe(0);
|
||||
});
|
||||
|
||||
it("if no keys in redis, invalidating org keys without fast hash should do nothing", async () => {
|
||||
await createAPIKey();
|
||||
|
||||
await new ApiAuthService(prisma, redis).invalidateOrgApiKeys(
|
||||
"seed-org-id",
|
||||
);
|
||||
|
||||
const keys = await redis.keys("api-key*");
|
||||
expect(keys.length).toBe(0);
|
||||
});
|
||||
|
||||
it("should invalidate project API keys in redis", async () => {
|
||||
await createAPIKey();
|
||||
|
||||
// put keys into cache
|
||||
await new ApiAuthService(prisma, redis).verifyAuthHeaderAndReturnScope(
|
||||
"Basic cGstbGYtMTIzNDU2Nzg5MDpzay1sZi0xMjM0NTY3ODkw",
|
||||
);
|
||||
await new ApiAuthService(prisma, redis).verifyAuthHeaderAndReturnScope(
|
||||
"Basic cGstbGYtMTIzNDU2Nzg5MDpzay1sZi0xMjM0NTY3ODkw",
|
||||
);
|
||||
|
||||
const apiKey = await prisma.apiKey.findUnique({
|
||||
where: { publicKey: "pk-lf-1234567890" },
|
||||
});
|
||||
expect(apiKey).not.toBeNull();
|
||||
|
||||
const cachedKey = await redis.get(
|
||||
`api-key:${apiKey?.fastHashedSecretKey}`,
|
||||
);
|
||||
expect(cachedKey).not.toBeNull();
|
||||
|
||||
await new ApiAuthService(prisma, redis).invalidateProjectApiKeys(
|
||||
"7a88fb47-b4e2-43b8-a06c-a5ce950dc53a",
|
||||
);
|
||||
|
||||
const invalidatedCachedKey = await redis.get(
|
||||
`api-key:${apiKey?.fastHashedSecretKey}`,
|
||||
);
|
||||
expect(invalidatedCachedKey).toBeNull();
|
||||
});
|
||||
|
||||
it("if no keys in redis, invalidating project keys should do nothing", async () => {
|
||||
await createAPIKey();
|
||||
|
||||
await prisma.apiKey.update({
|
||||
where: { publicKey: "pk-lf-1234567890" },
|
||||
data: {
|
||||
fastHashedSecretKey: Math.random().toString(36).substring(2, 15),
|
||||
},
|
||||
});
|
||||
|
||||
await new ApiAuthService(prisma, redis).invalidateProjectApiKeys(
|
||||
"7a88fb47-b4e2-43b8-a06c-a5ce950dc53a",
|
||||
);
|
||||
|
||||
const keys = await redis.keys("api-key*");
|
||||
expect(keys.length).toBe(0);
|
||||
});
|
||||
|
||||
it("if no keys in redis, invalidating project keys without fast hash should do nothing", async () => {
|
||||
await createAPIKey();
|
||||
|
||||
await prisma.apiKey.update({
|
||||
where: { publicKey: "pk-lf-1234567890" },
|
||||
data: {
|
||||
fastHashedSecretKey: Math.random().toString(36).substring(2, 15),
|
||||
},
|
||||
});
|
||||
|
||||
await new ApiAuthService(prisma, redis).invalidateProjectApiKeys(
|
||||
"7a88fb47-b4e2-43b8-a06c-a5ce950dc53a",
|
||||
);
|
||||
|
||||
const keys = await redis.keys("api-key*");
|
||||
expect(keys.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
const createAPIKey = async () => {
|
||||
const seedApiKey = {
|
||||
id: "seed-api-key",
|
||||
|
||||
@@ -186,7 +186,6 @@ export const ObservationPreview = (props: {
|
||||
source="generation"
|
||||
generation={observationWithInputAndOutput.data}
|
||||
analyticsEventName="trace_detail:test_in_playground_button_click"
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
{observationWithInputAndOutput.data ? (
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v2.75.2";
|
||||
export const VERSION = "v2.76.0";
|
||||
|
||||
@@ -83,7 +83,7 @@ const OrganizationUsageChart = () => {
|
||||
<>
|
||||
<Text>
|
||||
{usage.data.billingPeriod
|
||||
? `Observations in billing period`
|
||||
? `Observations in current billing period`
|
||||
: "Observations / last 30d"}
|
||||
</Text>
|
||||
<Metric>{numberFormatter(usage.data.countObservations, 0)}</Metric>
|
||||
|
||||
@@ -214,18 +214,6 @@ export const cloudBillingRouter = createTRPCRouter({
|
||||
session: ctx.session,
|
||||
});
|
||||
|
||||
const thirtyDaysAgo = new Date();
|
||||
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
||||
thirtyDaysAgo.setHours(0, 0, 0, 0);
|
||||
let billingPeriod: {
|
||||
start: Date;
|
||||
end: Date;
|
||||
} | null = null;
|
||||
let upcomingInvoice: {
|
||||
usdAmount: number;
|
||||
date: Date;
|
||||
} | null = null;
|
||||
|
||||
const organization = await ctx.prisma.organization.findUnique({
|
||||
where: {
|
||||
id: input.orgId,
|
||||
@@ -249,35 +237,49 @@ export const cloudBillingRouter = createTRPCRouter({
|
||||
parsedOrg.cloudConfig.stripe.activeSubscriptionId,
|
||||
);
|
||||
if (subscription) {
|
||||
billingPeriod = {
|
||||
const billingPeriod = {
|
||||
start: new Date(subscription.current_period_start * 1000),
|
||||
end: new Date(subscription.current_period_end * 1000),
|
||||
};
|
||||
const stripeInvoice = await stripeClient.invoices.retrieveUpcoming({
|
||||
subscription: parsedOrg.cloudConfig.stripe.activeSubscriptionId,
|
||||
});
|
||||
upcomingInvoice = {
|
||||
const upcomingInvoice = {
|
||||
usdAmount: stripeInvoice.amount_due / 100,
|
||||
date: new Date(stripeInvoice.period_end * 1000),
|
||||
};
|
||||
const usage = stripeInvoice.lines.data.reduce((acc, line) => {
|
||||
if (line.quantity) {
|
||||
return acc + line.quantity;
|
||||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
return {
|
||||
countObservations: usage,
|
||||
billingPeriod,
|
||||
upcomingInvoice,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// For non-Stripe subscriptions, we can only get usage from the LangFuse API
|
||||
const thirtyDaysAgo = new Date();
|
||||
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
||||
thirtyDaysAgo.setHours(0, 0, 0, 0);
|
||||
|
||||
const usage = await ctx.prisma.observation.count({
|
||||
where: {
|
||||
project: {
|
||||
orgId: input.orgId,
|
||||
},
|
||||
startTime: {
|
||||
gte: billingPeriod?.start ?? thirtyDaysAgo,
|
||||
gte: thirtyDaysAgo,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
countObservations: usage,
|
||||
billingPeriod,
|
||||
upcomingInvoice,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ type JumpToPlaygroundButtonProps = (
|
||||
analyticsEventName: "trace_detail:test_in_playground_button_click";
|
||||
}
|
||||
) & {
|
||||
fullWidth?: boolean;
|
||||
variant?: "outline" | "secondary";
|
||||
};
|
||||
|
||||
export const JumpToPlaygroundButton: React.FC<JumpToPlaygroundButtonProps> = (
|
||||
@@ -61,17 +61,14 @@ export const JumpToPlaygroundButton: React.FC<JumpToPlaygroundButtonProps> = (
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant={props.fullWidth ? "secondary" : "outline"}
|
||||
variant={props.variant ?? "secondary"}
|
||||
title="Test in LLM playground"
|
||||
size={!props.fullWidth ? "icon" : undefined}
|
||||
onClick={handleClick}
|
||||
asChild
|
||||
>
|
||||
<Link href={`/project/${projectId}/playground`}>
|
||||
<Terminal className="h-4 w-4" />
|
||||
{props.fullWidth ? (
|
||||
<span className="ml-2">Test in playground</span>
|
||||
) : null}
|
||||
<span className="ml-2">Test in playground</span>
|
||||
</Link>
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -150,7 +150,7 @@ export const EditDatasetItem = ({
|
||||
field.onChange(v);
|
||||
}}
|
||||
editable={hasAccess}
|
||||
className="max-h-[600px] overflow-y-auto"
|
||||
className="max-h-[500px] overflow-y-auto"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -171,7 +171,7 @@ export const EditDatasetItem = ({
|
||||
field.onChange(v);
|
||||
}}
|
||||
editable={hasAccess}
|
||||
className="max-h-[600px] overflow-y-auto"
|
||||
className="max-h-[500px] overflow-y-auto"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -193,7 +193,7 @@ export const EditDatasetItem = ({
|
||||
field.onChange(v);
|
||||
}}
|
||||
editable={hasAccess}
|
||||
className="max-h-[300px] overflow-y-auto"
|
||||
className="max-h-[200px] overflow-y-auto"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
|
||||
@@ -83,8 +83,6 @@ export function SetPromptVersionLabels({ prompt }: { prompt: Prompt }) {
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
if (!hasAccess) return null;
|
||||
|
||||
return (
|
||||
<Popover
|
||||
key={prompt.id}
|
||||
@@ -98,8 +96,10 @@ export function SetPromptVersionLabels({ prompt }: { prompt: Prompt }) {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-7 w-7 px-0"
|
||||
aria-label="Set prompt labels"
|
||||
title="Set prompt labels"
|
||||
disabled={!hasAccess}
|
||||
>
|
||||
<TagIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
@@ -160,7 +160,7 @@ export function SetPromptVersionLabels({ prompt }: { prompt: Prompt }) {
|
||||
) : (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="mt-2 w-full justify-start px-2 py-1 text-sm font-normal"
|
||||
className="mt-2 w-full justify-start px-2 py-1 text-sm font-normal"
|
||||
onClick={() => setIsAddingLabel(true)}
|
||||
>
|
||||
<PlusIcon className="mr-2 h-4 w-4" />
|
||||
|
||||
@@ -62,6 +62,7 @@ export function DeletePromptVersion({
|
||||
variant="outline"
|
||||
type="button"
|
||||
size="icon"
|
||||
className="h-7 w-7 px-0"
|
||||
disabled={!hasAccess}
|
||||
>
|
||||
<Trash className="h-4 w-4" />
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Pencil } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { NumberParam, useQueryParam } from "use-query-params";
|
||||
@@ -7,10 +6,8 @@ import Header from "@/src/components/layouts/header";
|
||||
import { OpenAiMessageView } from "@/src/components/trace/IOPreview";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/src/components/ui/tabs";
|
||||
import { Badge } from "@/src/components/ui/badge";
|
||||
import { Button } from "@/src/components/ui/button";
|
||||
import { CodeView, JSONView } from "@/src/components/ui/CodeJsonViewer";
|
||||
import { DetailPageNav } from "@/src/features/navigate-detail-pages/DetailPageNav";
|
||||
import { DeletePromptVersion } from "@/src/features/prompts/components/delete-prompt-version";
|
||||
import { PromptType } from "@/src/features/prompts/server/utils/validation";
|
||||
import useProjectIdFromURL from "@/src/hooks/useProjectIdFromURL";
|
||||
import { api } from "@/src/utils/api";
|
||||
@@ -18,7 +15,6 @@ import { extractVariables } from "@/src/utils/string";
|
||||
import { ScrollArea } from "@radix-ui/react-scroll-area";
|
||||
import { TagPromptDetailsPopover } from "@/src/features/tag/components/TagPromptDetailsPopover";
|
||||
import { PromptHistoryNode } from "./prompt-history";
|
||||
import { SetPromptVersionLabels } from "@/src/features/prompts/components/SetPromptVersionLabels";
|
||||
import Generations from "@/src/components/table/use-cases/generations";
|
||||
import {
|
||||
Accordion,
|
||||
@@ -26,14 +22,12 @@ import {
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/src/components/ui/accordion";
|
||||
import { usePostHogClientCapture } from "@/src/features/posthog-analytics/usePostHogClientCapture";
|
||||
import { JumpToPlaygroundButton } from "@/src/ee/features/playground/page/components/JumpToPlaygroundButton";
|
||||
import { ChatMlArraySchema } from "@/src/components/schemas/ChatMlSchema";
|
||||
import { CommentList } from "@/src/features/comments/CommentList";
|
||||
|
||||
export const PromptDetail = () => {
|
||||
const projectId = useProjectIdFromURL();
|
||||
const capture = usePostHogClientCapture();
|
||||
const promptName = decodeURIComponent(useRouter().query.promptName as string);
|
||||
const [currentPromptVersion, setCurrentPromptVersion] = useQueryParam(
|
||||
"version",
|
||||
@@ -107,31 +101,11 @@ export const PromptDetail = () => {
|
||||
]}
|
||||
actionButtons={
|
||||
<>
|
||||
<SetPromptVersionLabels prompt={prompt} />
|
||||
|
||||
<JumpToPlaygroundButton
|
||||
source="prompt"
|
||||
prompt={prompt}
|
||||
analyticsEventName="prompt_detail:test_in_playground_button_click"
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => capture("prompts:update_form_open")}
|
||||
asChild
|
||||
>
|
||||
<Link
|
||||
href={`/project/${projectId}/prompts/new?promptId=${encodeURIComponent(prompt.id)}`}
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
<DeletePromptVersion
|
||||
promptVersionId={prompt.id}
|
||||
version={prompt.version}
|
||||
countVersions={promptHistory.data.totalCount}
|
||||
/>
|
||||
<DetailPageNav
|
||||
key="nav"
|
||||
@@ -242,6 +216,7 @@ export const PromptDetail = () => {
|
||||
prompts={promptHistory.data.promptVersions}
|
||||
currentPromptVersion={prompt.version}
|
||||
setCurrentPromptVersion={setCurrentPromptVersion}
|
||||
totalCount={promptHistory.data.totalCount}
|
||||
/>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { StatusBadge } from "@/src/components/layouts/status-badge";
|
||||
import { Button } from "@/src/components/ui/button";
|
||||
import { usePostHogClientCapture } from "@/src/features/posthog-analytics/usePostHogClientCapture";
|
||||
import { DeletePromptVersion } from "@/src/features/prompts/components/delete-prompt-version";
|
||||
import { SetPromptVersionLabels } from "@/src/features/prompts/components/SetPromptVersionLabels";
|
||||
import { PRODUCTION_LABEL } from "@/src/features/prompts/constants";
|
||||
import { useHasProjectAccess } from "@/src/features/rbac/utils/checkProjectAccess";
|
||||
import { type RouterOutputs } from "@/src/utils/api";
|
||||
import { Pencil, PencilOff } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { type NextRouter, useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
|
||||
const PromptHistoryTraceNode = (props: {
|
||||
index: number;
|
||||
@@ -10,7 +18,14 @@ const PromptHistoryTraceNode = (props: {
|
||||
setCurrentPromptVersion: (version: number | undefined) => void;
|
||||
router: NextRouter;
|
||||
projectId: string;
|
||||
totalCount: number;
|
||||
}) => {
|
||||
const capture = usePostHogClientCapture();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const hasAccess = useHasProjectAccess({
|
||||
projectId: props.projectId,
|
||||
scope: "prompts:CUD",
|
||||
});
|
||||
const { prompt } = props;
|
||||
let badges: JSX.Element[] = prompt.labels
|
||||
.sort((a, b) =>
|
||||
@@ -21,7 +36,7 @@ const PromptHistoryTraceNode = (props: {
|
||||
: a.localeCompare(b),
|
||||
)
|
||||
.map((label) => {
|
||||
return <StatusBadge type={label} key={label} />;
|
||||
return <StatusBadge type={label} key={label} className="h-6" />;
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -29,19 +44,63 @@ const PromptHistoryTraceNode = (props: {
|
||||
className={`group mb-2 flex cursor-pointer flex-col gap-1 rounded-sm p-2 hover:bg-primary-foreground ${
|
||||
props.currentPromptVersion === prompt.version ? "bg-muted" : ""
|
||||
}`}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
onClick={() => {
|
||||
props.index === 0
|
||||
? props.setCurrentPromptVersion(undefined)
|
||||
: props.setCurrentPromptVersion(prompt.version);
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="rounded-sm bg-input p-1 text-xs">
|
||||
Version {prompt.version}
|
||||
</span>
|
||||
{badges}
|
||||
<div className="grid grid-cols-[auto,1fr] items-start gap-2">
|
||||
<div
|
||||
className={`grid grid-cols-[auto,1fr] items-start ${isHovered ? "h-full" : "h-7"}`}
|
||||
>
|
||||
<span className="flex h-6 text-nowrap rounded-sm bg-input p-1 text-xs">
|
||||
Version {prompt.version}
|
||||
</span>
|
||||
{Boolean(prompt.labels.length) && (
|
||||
<div className="ml-2 flex h-full flex-wrap gap-1 overflow-auto">
|
||||
{badges}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isHovered && (
|
||||
<div className="flex flex-row space-x-1">
|
||||
<SetPromptVersionLabels prompt={prompt} />
|
||||
{hasAccess ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-7 w-7 px-0"
|
||||
onClick={() => {
|
||||
capture("prompts:update_form_open");
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
href={`/project/${props.projectId}/prompts/new?promptId=${encodeURIComponent(prompt.id)}`}
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-7 w-7 px-0"
|
||||
disabled
|
||||
>
|
||||
<PencilOff className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
<DeletePromptVersion
|
||||
promptVersionId={prompt.id}
|
||||
version={prompt.version}
|
||||
countVersions={props.totalCount}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{prompt.createdAt.toLocaleString()}
|
||||
@@ -60,6 +119,7 @@ export const PromptHistoryNode = (props: {
|
||||
prompts: RouterOutputs["prompts"]["allVersions"]["promptVersions"];
|
||||
currentPromptVersion: number | undefined;
|
||||
setCurrentPromptVersion: (id: number | undefined) => void;
|
||||
totalCount: number;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const projectId = router.query.projectId as string;
|
||||
@@ -74,6 +134,7 @@ export const PromptHistoryNode = (props: {
|
||||
setCurrentPromptVersion={props.setCurrentPromptVersion}
|
||||
router={router}
|
||||
projectId={projectId}
|
||||
totalCount={props.totalCount}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
import { type NextApiResponse } from "next";
|
||||
|
||||
// Business Logic
|
||||
// - rate limit strategy is based on org-id, org plan, and resources. Rate limits are appliead in buckets of minutes.
|
||||
// - rate limit strategy is based on org-id, org plan, and resources. Rate limits are applied in buckets of minutes.
|
||||
// - rate limits are not applied for self hosters and are also not applied when Redis is not available
|
||||
// - infos for rate-limits are taken from the API access scope. Info for this scope is stored alongside API Keys in Redis for efficient access.
|
||||
// - isRateLimited returns false for self-hosters
|
||||
|
||||
@@ -35,10 +35,18 @@ export class ApiAuthService {
|
||||
private async invalidate(apiKeys: ApiKey[], identifier: string) {
|
||||
const hashKeys = apiKeys.map((key) => key.fastHashedSecretKey);
|
||||
|
||||
const filteredHashKeys = hashKeys.filter((hash): hash is string =>
|
||||
Boolean(hash),
|
||||
);
|
||||
if (filteredHashKeys.length === 0) {
|
||||
console.log("No valid keys to invalidate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.redis) {
|
||||
console.log(`Invalidating API keys in redis for ${identifier}`);
|
||||
await this.redis.del(
|
||||
hashKeys
|
||||
filteredHashKeys
|
||||
.filter((hash): hash is string => Boolean(hash))
|
||||
.map((hash) => this.createRedisKey(hash)),
|
||||
);
|
||||
@@ -81,9 +89,7 @@ export class ApiAuthService {
|
||||
|
||||
// if redis is available, delete the key from there as well
|
||||
// delete from redis even if caching is disabled via env for consistency
|
||||
if (this.redis && apiKey.fastHashedSecretKey) {
|
||||
await this.redis.del(this.createRedisKey(apiKey.fastHashedSecretKey));
|
||||
}
|
||||
this.invalidate([apiKey], `key ${id}`);
|
||||
|
||||
await this.prisma.apiKey.delete({
|
||||
where: {
|
||||
|
||||
@@ -13,7 +13,7 @@ export async function telemetry() {
|
||||
try {
|
||||
// Only run in prod
|
||||
if (process.env.NODE_ENV !== "production") return;
|
||||
// Do not run in Lanfuse cloud, separate telemetry is used
|
||||
// Do not run in Langfuse cloud, separate telemetry is used
|
||||
if (process.env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION !== undefined) return;
|
||||
// Check if telemetry is not disabled, except for EE
|
||||
if (
|
||||
|
||||
@@ -3,7 +3,6 @@ import { type NextApiRequest, type NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
import { LangfuseNotFoundError, InternalServerError } from "@langfuse/shared";
|
||||
import {
|
||||
getLegacyIngestionQueue,
|
||||
eventTypes,
|
||||
ingestionEvent,
|
||||
traceException,
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
handleBatch,
|
||||
recordIncrement,
|
||||
getCurrentSpan,
|
||||
LegacyIngestionQueue,
|
||||
} from "@langfuse/shared/src/server";
|
||||
import {
|
||||
SdkLogProcessor,
|
||||
@@ -141,43 +141,54 @@ export default async function handler(
|
||||
|
||||
if (env.LANGFUSE_ASYNC_INGESTION_PROCESSING === "true" && redis) {
|
||||
// this function MUST NOT return but send the HTTP response directly
|
||||
const queue = getLegacyIngestionQueue();
|
||||
const queue = LegacyIngestionQueue.getInstance();
|
||||
|
||||
if (queue) {
|
||||
// still need to check auth scope for all events individually
|
||||
|
||||
const failedAccessScope = accessCheckPerEvent(sortedBatch, authCheck);
|
||||
|
||||
await queue.add(
|
||||
QueueJobs.LegacyIngestionJob,
|
||||
{
|
||||
payload: { data: sortedBatch, authCheck: authCheck },
|
||||
id: randomUUID(),
|
||||
timestamp: new Date(),
|
||||
name: QueueJobs.LegacyIngestionJob as const,
|
||||
},
|
||||
{
|
||||
removeOnFail: 1_000_000,
|
||||
removeOnComplete: true,
|
||||
attempts: 5,
|
||||
backoff: {
|
||||
type: "exponential",
|
||||
delay: 1000,
|
||||
let addToQueueFailed = false;
|
||||
try {
|
||||
await queue.add(
|
||||
QueueJobs.LegacyIngestionJob,
|
||||
{
|
||||
payload: { data: sortedBatch, authCheck: authCheck },
|
||||
id: randomUUID(),
|
||||
timestamp: new Date(),
|
||||
name: QueueJobs.LegacyIngestionJob as const,
|
||||
},
|
||||
},
|
||||
);
|
||||
{
|
||||
removeOnFail: 1_000_000,
|
||||
removeOnComplete: true,
|
||||
attempts: 5,
|
||||
backoff: {
|
||||
type: "exponential",
|
||||
delay: 1000,
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
console.warn(
|
||||
"Failed to add batch to queue, falling back to sync processing",
|
||||
e,
|
||||
);
|
||||
addToQueueFailed = true;
|
||||
}
|
||||
|
||||
return handleBatchResult(
|
||||
[
|
||||
...validationErrors,
|
||||
...failedAccessScope.map((e) => ({
|
||||
id: e.id,
|
||||
error: "Access Scope Denied",
|
||||
})),
|
||||
], // we are not sending additional server errors to the client in case of early return
|
||||
sortedBatch.map((event) => ({ id: event.id, result: event })),
|
||||
res,
|
||||
);
|
||||
if (!addToQueueFailed) {
|
||||
return handleBatchResult(
|
||||
[
|
||||
...validationErrors,
|
||||
...failedAccessScope.map((e) => ({
|
||||
id: e.id,
|
||||
error: "Access Scope Denied",
|
||||
})),
|
||||
], // we are not sending additional server errors to the client in case of early return
|
||||
sortedBatch.map((event) => ({ id: event.id, result: event })),
|
||||
res,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.error(
|
||||
"Ingestion queue not initialized, falling back to sync processing",
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { FullScreenPage } from "@/src/components/layouts/full-screen-page";
|
||||
import Header from "@/src/components/layouts/header";
|
||||
import { Button } from "@/src/components/ui/button";
|
||||
import {
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
} from "@/src/components/ui/resizable";
|
||||
import { DatasetRunItemsTable } from "@/src/features/datasets/components/DatasetRunItemsTable";
|
||||
import { EditDatasetItem } from "@/src/features/datasets/components/EditDatasetItem";
|
||||
import { DetailPageNav } from "@/src/features/navigate-detail-pages/DetailPageNav";
|
||||
@@ -68,13 +73,28 @@ export default function Dataset() {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<EditDatasetItem projectId={projectId} datasetItem={item.data ?? null} />
|
||||
<Header title="Runs" level="h3" />
|
||||
<DatasetRunItemsTable
|
||||
projectId={projectId}
|
||||
datasetItemId={itemId}
|
||||
datasetId={datasetId}
|
||||
/>
|
||||
|
||||
<ResizablePanelGroup direction="vertical">
|
||||
<ResizablePanel
|
||||
minSize={10}
|
||||
defaultSize={50}
|
||||
className="!overflow-y-auto"
|
||||
>
|
||||
<EditDatasetItem
|
||||
projectId={projectId}
|
||||
datasetItem={item.data ?? null}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle className="bg-border" />
|
||||
<ResizablePanel minSize={10} className="flex flex-col space-y-4">
|
||||
<Header title="Runs" level="h3" />
|
||||
<DatasetRunItemsTable
|
||||
projectId={projectId}
|
||||
datasetItemId={itemId}
|
||||
datasetId={datasetId}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</FullScreenPage>
|
||||
);
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "worker",
|
||||
"version": "2.75.2",
|
||||
"version": "2.76.0",
|
||||
"description": "",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
@@ -50,7 +50,7 @@
|
||||
"pg": "^8.11.5",
|
||||
"pino": "^9.2.0",
|
||||
"pino-http": "^10.2.0",
|
||||
"pino-pretty": "^10.3.1",
|
||||
"pino-pretty": "^11.2.2",
|
||||
"stripe": "^16.8.0",
|
||||
"tiktoken": "^1.0.15",
|
||||
"uuid": "^9.0.1",
|
||||
@@ -62,7 +62,7 @@
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/express-serve-static-core": "^4.19.3",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/lodash": "^4.17.7",
|
||||
"@types/node": "^20.11.19",
|
||||
"@types/pg": "^8.11.6",
|
||||
"@types/uuid": "^9.0.8",
|
||||
@@ -72,12 +72,12 @@
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"kysely-codegen": "^0.11.0",
|
||||
"msw": "^2.3.1",
|
||||
"msw": "^2.4.1",
|
||||
"nodemon": "^3.1.3",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsc-watch": "^6.2.0",
|
||||
"tsx": "^4.18.0",
|
||||
"tsx": "^4.19.0",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^5.2.13",
|
||||
"vitest": "^1.5.3"
|
||||
|
||||
+11
-13
@@ -35,25 +35,23 @@ app.use("/api", api);
|
||||
app.use(middlewares.notFound);
|
||||
app.use(middlewares.errorHandler);
|
||||
|
||||
logger.info("Eval Job Creator started", evalJobCreator?.isRunning());
|
||||
logger.info(`Eval Job Creator started: ${evalJobCreator?.isRunning()}`);
|
||||
|
||||
logger.info("Eval Job Executor started", evalJobExecutor?.isRunning());
|
||||
logger.info(`Eval Job Executor started: ${evalJobExecutor?.isRunning()}`);
|
||||
logger.info(
|
||||
"Batch Export Job Executor started",
|
||||
batchExportJobExecutor?.isRunning()
|
||||
);
|
||||
logger.info("Repeat Queue Executor started", repeatQueueExecutor?.isRunning());
|
||||
logger.info(
|
||||
"Flush Ingestion Queue Executor started",
|
||||
ingestionQueueExecutor?.isRunning()
|
||||
`Batch Export Job Executor started: ${batchExportJobExecutor?.isRunning()}`
|
||||
);
|
||||
logger.info(
|
||||
"Legacy Ingestion Executor started",
|
||||
legacyIngestionExecutor?.isRunning()
|
||||
`Repeat Queue Executor started: ${repeatQueueExecutor?.isRunning()}`
|
||||
);
|
||||
logger.info(
|
||||
"Cloud Usage Metering Job Executor started",
|
||||
cloudUsageMeteringJobExecutor?.isRunning()
|
||||
`Flush Ingestion Queue Executor started: ${ingestionQueueExecutor?.isRunning()}`
|
||||
);
|
||||
logger.info(
|
||||
`Legacy Ingestion Executor started: ${legacyIngestionExecutor?.isRunning()}`
|
||||
);
|
||||
logger.info(
|
||||
`Cloud Usage Metering Job Executor started: ${cloudUsageMeteringJobExecutor?.isRunning()}`
|
||||
);
|
||||
|
||||
evalJobCreator?.on("failed", logQueueWorkerError);
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v2.75.2";
|
||||
export const VERSION = "v2.76.0";
|
||||
|
||||
@@ -75,6 +75,9 @@ const EnvSchema = z.object({
|
||||
.positive()
|
||||
.default(5),
|
||||
STRIPE_SECRET_KEY: z.string().optional(),
|
||||
QUEUE_CONSUMER_LEGACY_INGESTION_QUEUE_IS_ENABLED: z
|
||||
.enum(["true", "false"])
|
||||
.default("true"),
|
||||
});
|
||||
|
||||
export const env = EnvSchema.parse(process.env);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Job, Worker } from "bullmq";
|
||||
import {
|
||||
traceException,
|
||||
getLegacyIngestionQueue,
|
||||
LegacyIngestionQueue,
|
||||
instrumentAsync,
|
||||
QueueName,
|
||||
recordIncrement,
|
||||
@@ -36,13 +36,13 @@ const createLegacyIngestionExecutor = () => {
|
||||
try {
|
||||
const startTime = Date.now();
|
||||
logger.info(
|
||||
`Processing legacy ingestion for payload ${JSON.stringify(job.data.payload)}`
|
||||
`Processing legacy ingestion for payload ${JSON.stringify(job.data.payload)}`,
|
||||
);
|
||||
|
||||
// Log wait time
|
||||
const waitTime = Date.now() - job.timestamp;
|
||||
logger.debug(
|
||||
`Received flush request after ${waitTime} ms for ${job.data.payload.authCheck.scope.projectId}`
|
||||
`Received flush request after ${waitTime} ms for ${job.data.payload.authCheck.scope.projectId}`,
|
||||
);
|
||||
|
||||
recordIncrement("legacy_ingestion_processing_request");
|
||||
@@ -53,17 +53,17 @@ const createLegacyIngestionExecutor = () => {
|
||||
const result = await handleBatch(
|
||||
job.data.payload.data,
|
||||
job.data.payload.authCheck,
|
||||
tokenCount
|
||||
tokenCount,
|
||||
);
|
||||
|
||||
// send out REDIS requests to worker for all trace types
|
||||
await sendToWorkerIfEnvironmentConfigured(
|
||||
result.results,
|
||||
job.data.payload.authCheck.scope.projectId
|
||||
job.data.payload.authCheck.scope.projectId,
|
||||
);
|
||||
|
||||
// Log queue size
|
||||
await getLegacyIngestionQueue()
|
||||
await LegacyIngestionQueue.getInstance()
|
||||
?.count()
|
||||
.then((count) => {
|
||||
logger.info(`Legacy Ingestion flush queue length: ${count}`);
|
||||
@@ -76,26 +76,29 @@ const createLegacyIngestionExecutor = () => {
|
||||
recordHistogram(
|
||||
"legacy_ingestion_processing_time",
|
||||
Date.now() - startTime,
|
||||
{ unit: "milliseconds" }
|
||||
{ unit: "milliseconds" },
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
e,
|
||||
`Failed job Evaluation for traceId ${job.data.payload} ${e}`
|
||||
`Failed job Evaluation for traceId ${job.data.payload} ${e}`,
|
||||
);
|
||||
traceException(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
{
|
||||
connection: redisInstance,
|
||||
concurrency: env.LANGFUSE_LEGACY_INGESTION_WORKER_CONCURRENCY, // n ingestion batches at a time
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const legacyIngestionExecutor = createLegacyIngestionExecutor();
|
||||
export const legacyIngestionExecutor =
|
||||
env.QUEUE_CONSUMER_LEGACY_INGESTION_QUEUE_IS_ENABLED === "true"
|
||||
? createLegacyIngestionExecutor()
|
||||
: null;
|
||||
|
||||
Reference in New Issue
Block a user