From cf5ed0766bdccd177648daf6a108fcf233f77416 Mon Sep 17 00:00:00 2001 From: RainbowBird Date: Fri, 5 Jun 2026 16:25:33 +0800 Subject: [PATCH] fix(server): make analytics best-effort Remove server-side PostHog wiring so request handlers no longer wait on third-party analytics delivery. Keep auth activity and product event writes best-effort so degraded analytics do not fail session creation. Signed-off-by: RainbowBird Commit-Message-Assisted-by: Codex (via Codex) --- .../docs/ai-context/metrics-ownership.md | 56 ++-- apps/server/package.json | 1 - apps/server/src/app.test.ts | 1 - apps/server/src/app.ts | 50 +-- apps/server/src/libs/auth.ts | 24 +- apps/server/src/libs/env.ts | 5 - .../v1/operations/chat-completions/index.ts | 43 --- .../server/src/routes/openai/v1/route.test.ts | 1 - apps/server/src/routes/openai/v1/types.ts | 3 - apps/server/src/routes/stripe/index.ts | 3 - .../src/routes/stripe/operations/webhook.ts | 83 +---- apps/server/src/services/adapters/posthog.ts | 95 ------ apps/server/tests/verifications/_harness.ts | 1 - pnpm-lock.yaml | 293 ++---------------- pnpm-workspace.yaml | 1 - 15 files changed, 59 insertions(+), 601 deletions(-) delete mode 100644 apps/server/src/services/adapters/posthog.ts diff --git a/apps/server/docs/ai-context/metrics-ownership.md b/apps/server/docs/ai-context/metrics-ownership.md index 17a77d8d6..8b3f82c4b 100644 --- a/apps/server/docs/ai-context/metrics-ownership.md +++ b/apps/server/docs/ai-context/metrics-ownership.md @@ -1,6 +1,6 @@ # Metrics Ownership -这份文档定义 AIRI 团队的指标分层规则:什么指标该走 Grafana / Prometheus(OTel server-side),什么该走 PostHog(前后端混合 product analytics),同名指标怎么处理。落地这份是为了避免后期"同一个 KPI 三处不同数"的漂移。 +这份文档定义 AIRI 团队的指标分层规则:什么指标该走 Grafana / Prometheus(OTel server-side),什么该走 PostHog(frontend/external product analytics),同名指标怎么处理。落地这份是为了避免后期"同一个 KPI 三处不同数"的漂移。 ## 总原则 @@ -9,7 +9,7 @@ | 层 | 工具 | 关键属性 | |---|---|---| | **System / API observability** | Grafana Cloud + Prometheus + OTel | 系统健康、延迟、错误率、SRE on-call 告警 | -| **Product analytics** | PostHog Cloud | 用户行为、漏斗、retention、cohort、A/B、feature adoption | +| **Product analytics** | PostHog Cloud | 前端用户行为、漏斗、retention、cohort、A/B、feature adoption | | **Financial truth source** | Postgres (`flux_transaction` / Stripe webhook 持久化) | 收入与扣费 ledger,任何展示都视作近似 | | **LLM-native observability** | Langfuse Cloud(已接入:chat completion + TTS speech) | 逐条 prompt/completion trace、TTS text trace、token/字符用量、按 user/session 成本归因、eval。真实 staging HTTP E2E 与 model 定价匹配待做 | @@ -45,11 +45,11 @@ |---|---|---| | 计费 ledger(每一分钱可审计) | **Postgres** | Grafana / PostHog 都视作近似展示,争议查 SQL | | HTTP / WS / DB / Stripe webhook **计数** | **Grafana**(OTel counter) | 系统事件,PostHog 看不到 | -| 用户去重 DAU / WAU / retention | **PostHog** | 需要 distinctId 去重,session table 计数不准 | +| 用户去重 DAU / WAU / retention | **Postgres → Grafana** for server truth; **PostHog** for frontend journey | Server 不直接发 PostHog;后端事实查 `product_events` / `user.last_seen_at` | | 收入展示(MRR / ARR / churn revenue) | **Postgres → 两边展示** | 真相在 Postgres,Grafana 取系统侧切片(panel-30),PostHog 取用户维度切片 | | LLM token / cost(聚合速率、按模型) | **Grafana**(OTel counter) | 系统侧聚合,SRE 视角 | | LLM 逐条 prompt / completion / TTS text / eval / 按 user-session 成本 | **Langfuse** | 已接入 chat completion + TTS speech,正文级 trace + eval | -| 用户行为漏斗各步骤 | **PostHog**(必须) | 第一步通常是前端事件,Grafana 拿不到 | +| 用户行为漏斗各步骤 | **PostHog** for frontend steps; **Postgres/Grafana** for server steps | Server-side facts 不在请求路径发 PostHog | ### Better Auth session table 与活跃用户 @@ -80,7 +80,7 @@ | properties 用 `snake_case` | `{ plan_id, price_usd, checkout_session_id }` | | 跟外部系统串联的 ID 用原平台命名 | `stripe_customer_id`、`stripe_subscription_id`、`checkout_session_id` | -`distinctId` 在登录后必须调 `posthog.identify(userId)`,userId 用 Better Auth 的 user id(跟 server 里的 `c.get('user').id` 一致)。后端 `posthog-node` 上报支付事件时用 fallback 链 `userId` (`session.metadata.userId`) > `email` (`session.customer_email`) > `session.id`——第一项跟前端 `identify` 一致,PostHog person merge 在这里完成。前端 wiring 由 `useSharedAnalyticsStore.initialize()` 自动处理,不需要每个 caller 手动 identify。 +`distinctId` 在登录后必须调 `posthog.identify(userId)`,userId 用 Better Auth 的 user id(跟 server 里的 `c.get('user').id` 一致)。AIRI server 不直接接入 `posthog-node`,后端事实事件写入 Postgres `product_events` 并通过 `airi_product_events_total` 暴露到 Grafana。前端 wiring 由 `useSharedAnalyticsStore.initialize()` 自动处理,不需要每个 caller 手动 identify。 参考来源:[PostHog: 5 events all teams should track](https://posthog.com/blog/events-you-should-track-with-posthog)。 @@ -109,23 +109,23 @@ | Runtime | `v8js_memory_*` / `nodejs_eventloop_delay_*` | Grafana | per `service_instance_id` | | Rate-limit | `airi_rate_limit_blocked_total` | Grafana | in-memory per replica | -### PostHog(前后端混合,产品侧) +### PostHog(前端 / 外部数据源,产品侧) 已接入: - 前端 `posthog-js` 通过 `packages/stage-ui/src/stores/analytics/posthog.ts` 初始化,三个 app(web / desktop / pocket)按 `isStageTamagotchi()` 等选 project key -- 后端 `posthog-node` 通过 `apps/server/src/services/adapters/posthog.ts` + injeca provider `services:posthog` -- 前端↔后端 identity merge:`useSharedAnalyticsStore.initialize()` watch `authStore.isAuthenticated` 自动调 `posthog.identify(user.id)` / `reset()` +- Server 不接入 `posthog-node`。后端产品事件写 `product_events`,Grafana 展示低基数聚合;需要 PostHog revenue/person analytics 时优先用 PostHog Stripe source connector 或离线导入,不允许在 API 请求路径同步发 PostHog。 +- 前端 identity:`useSharedAnalyticsStore.initialize()` watch `authStore.isAuthenticated` 自动调 `posthog.identify(user.id)` / `reset()` 已埋点: | 域 | 事件 | 来源 | 落点 | Truth | |---|---|---|---|---| | 付费漏斗 | `pricing_page_viewed` / `plan_selected` / `checkout_started` | 前端 | `packages/stage-pages/src/pages/settings/flux.vue` | PostHog | -| 付费漏斗终点 | `payment_completed` | 后端 webhook | `apps/server/src/routes/stripe/index.ts` | PostHog | +| 付费漏斗终点 | `payment_completed` | 后端 webhook | `product_events` + Grafana;PostHog 走 Stripe source connector/离线导入 | Postgres | | Activation / Retention | `first_model_selected` / `model_switched` | 前端(consciousness store watcher) | `packages/stage-ui/src/stores/analytics/index.ts` | PostHog | | Retention | `character_created` | 前端 | `apps/stage-web/src/pages/settings/characters/components/CharacterDialog.vue` | PostHog | | Retention | `chat_session_started` | 前端 | `packages/stage-ui/src/components/scenarios/chat/components/sessions-drawer.vue` | PostHog | -| Churn | `subscription_cancelled`(带 cancellation_reason) | 后端 webhook | `apps/server/src/routes/stripe/index.ts` | PostHog | +| Churn | `subscription_cancelled`(带 cancellation_reason) | 外部 Stripe 数据源 | PostHog Stripe source connector | Stripe/Postgres | | 老事件 | `provider_card_clicked` / `first_message_sent` | 前端 | `packages/stage-ui/src/composables/use-analytics.ts` | PostHog | 待埋点(API 已在 `use-analytics.ts` 暴露但调用点未接入): @@ -140,34 +140,16 @@ | 指标 | Grafana | PostHog | Truth | 语义差异 | |---|---|---|---|---| -| 活跃用户数 | `user_active_sessions`(Postgres session 计数) | DAU = 去重 distinctId | **PostHog** | Grafana 是 active **sessions**,PostHog 是 active **users** | -| Checkout 完成数 | `stripe_checkout_completed_total` | `payment_completed` event | **Postgres** | 两边都展示,Grafana 是 webhook 计数,PostHog 是漏斗终点 | +| 活跃用户数 | `user_active_rolling` / `user_distinct_active` | DAU = 前端 journey 去重 distinctId | **Postgres/Grafana** for server truth | Grafana 是服务端可验证活跃,PostHog 是前端产品旅程 | +| Checkout 完成数 | `stripe_checkout_completed_total` + `product_events.payment_completed` | Stripe source connector / offline import | **Postgres** | Grafana 是 webhook 计数,PostHog 是产品漏斗展示 | | LLM 请求 | `gen_ai_client_operation_count_total` | `chat_session_started` 等 | **Grafana**(系统计数) | PostHog 是用户维度切片,会少于 Grafana(PostHog 只覆盖 logged-in user) | ## PostHog 接入路线图 -落地分两步,**不要一次性埋全部事件**,否则 schema 漂移会很快出现。 +落地分两步,**不要一次性埋全部事件**,否则 schema 漂移会很快出现。PostHog 采集只发生在前端或外部 source connector;server 请求路径只写 Postgres/Grafana。 ### 阶段 1(P0 — 付费漏斗 + activation) -`apps/server`: - -```ts -// services/adapters/posthog.ts(新增) -import { PostHog } from 'posthog-node' - -export function createPostHog(env: ServerEnv) { - return new PostHog(env.POSTHOG_KEY, { host: 'https://us.i.posthog.com' }) -} - -// 在 Stripe webhook handler 里 -posthog.capture({ - distinctId: stripeCustomerEmail, - event: 'payment_completed', - properties: { plan_id, amount_usd, stripe_customer_id, stripe_subscription_id } -}) -``` - `apps/stage-web`: ```ts @@ -199,12 +181,12 @@ posthog.init(import.meta.env.VITE_POSTHOG_KEY, { 埋点事件清单(P0): - 前端:`pricing_page_viewed`、`plan_selected`、`checkout_started`、`user_signed_up`、`first_message_sent`、`first_model_selected` -- 后端:`payment_completed` +- 后端:不直接发 PostHog;`payment_completed` 写入 `product_events`,PostHog 侧通过 Stripe source connector 或离线导入展示 PostHog UI 配两个 funnel: -- **付费漏斗** (7d 窗口):`pricing_page_viewed → plan_selected → checkout_started → payment_completed` -- **激活漏斗** (14d 窗口):`user_signed_up → first_message_sent → first_model_selected → payment_completed` +- **付费漏斗** (7d 窗口):`pricing_page_viewed → plan_selected → checkout_started → payment_completed`(最后一步来自 Stripe source connector / 离线导入) +- **激活漏斗** (14d 窗口):`user_signed_up → first_message_sent → first_model_selected → payment_completed`(最后一步同上) ### 阶段 2(P1 — retention / feature adoption / churn) @@ -217,14 +199,14 @@ PostHog UI 配 cohort: ### Stripe → PostHog 集成路径 -**两条路径都接**: +**不在 server webhook 里手动 capture**: | 路径 | 用途 | |---|---| | PostHog Stripe **source connector** | MRR / ARR / churn revenue dashboard(PostHog 原生 Revenue analytics) | -| **手动 capture** `payment_completed`(后端 webhook) | 漏斗终点 event,跟前端 `checkout_started` 串联 | +| 离线导入 `product_events.payment_completed`(可选) | 漏斗终点 event,跟前端 `checkout_started` 串联 | -不能只用 source connector:它是 data warehouse 层,**不生成 person event,做不了漏斗**。 +不要在 API 请求路径同步发 PostHog:PostHog 网络尾延迟会污染 auth / billing / chat route latency。需要 person-level funnel endpoint 时,用后台导入或 connector,不阻塞用户请求。 ## 5xx Triage 路径 diff --git a/apps/server/package.json b/apps/server/package.json index a2ef84a41..ee89b1fa8 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -61,7 +61,6 @@ "nanoid": "catalog:", "ofetch": "catalog:", "pg": "catalog:", - "posthog-node": "catalog:", "resend": "catalog:", "stripe": "catalog:", "unspeech": "catalog:xsai", diff --git a/apps/server/src/app.test.ts b/apps/server/src/app.test.ts index 60f4c08cb..790bfb032 100644 --- a/apps/server/src/app.test.ts +++ b/apps/server/src/app.test.ts @@ -81,7 +81,6 @@ function createTestDeps() { encryptKey: vi.fn(), decryptKey: vi.fn(), } as any, - posthog: null, } return { diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index 35bf2394e..c7d3d3382 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -1,5 +1,4 @@ import type Redis from 'ioredis' -import type { PostHog } from 'posthog-node' import type { AuthInstance } from './libs/auth' import type { Database } from './libs/db' @@ -67,7 +66,6 @@ import { createProviderRoutes } from './routes/providers' import { createStripeRoutes } from './routes/stripe' import { createConfigKVService } from './services/adapters/config-kv' import { createEmailService } from './services/adapters/email' -import { createPostHogClient } from './services/adapters/posthog' import { createAdminFluxGrantsService } from './services/domain/admin/flux-grants' import { createAdminRouterConfigService } from './services/domain/admin/router-config' import { createAdminUsersService } from './services/domain/admin/users' @@ -111,7 +109,6 @@ interface AppDeps { otel: OtelInstance | null userDeletionService: UserDeletionService llmRouter: LlmRouterService - posthog: PostHog | null } export async function buildApp(deps: AppDeps) { @@ -233,7 +230,6 @@ export async function buildApp(deps: AppDeps) { genAi: deps.otel?.genAi, revenue: deps.otel?.revenue, rateLimitMetrics: deps.otel?.rateLimit, - posthog: deps.posthog, }) const builtApp = app @@ -365,7 +361,7 @@ export async function buildApp(deps: AppDeps) { /** * Stripe routes. */ - .route('/api/v1/stripe', createStripeRoutes(deps.fluxService, deps.stripeService, deps.billingService, deps.configKV, deps.env, deps.redis, deps.otel?.revenue, deps.otel?.rateLimit, deps.posthog, deps.productEventService)) + .route('/api/v1/stripe', createStripeRoutes(deps.fluxService, deps.stripeService, deps.billingService, deps.configKV, deps.env, deps.redis, deps.otel?.revenue, deps.otel?.rateLimit, deps.productEventService)) /** * Admin routes — guarded by the `adminGuard` role check (`role === 'admin'`, @@ -505,44 +501,6 @@ export async function createApp() { }, undefined, dependsOn.otel?.email), }) - // Webhook capture path goes through `captureSafe` → `captureImmediate`, - // which awaits the HTTP send inline, so individual events never sit in - // the background queue. `flush()` + `_shutdown()` on SIGTERM is the belt- - // and-suspenders drain for any future call site that uses the regular - // `capture()` (which only enqueues). - // - // NOTICE: - // We use the underscore-prefixed `_shutdown` despite its "internal" naming - // because the public `shutdown(timeoutMs)` returns void (`types.d.ts:580`) - // — there is no way to await its completion. `_shutdown(timeoutMs)` returns - // `Promise` (`client.d.ts:934`) and is the only way to ensure the - // process doesn't exit while PostHog cleanup is still running. Posthog's - // own examples show `await client._shutdown()` as the recommended pattern. - const posthog = injeca.provide('services:posthog', { - dependsOn: { env: parsedEnv, lifecycle }, - build: ({ dependsOn }) => { - const client = createPostHogClient(dependsOn.env) - if (client) { - dependsOn.lifecycle.appHooks.onStop(async () => { - try { - await client.flush() - } - catch { - // Flush failures on shutdown are non-fatal; we lose at most a - // few queued events. Fall through to shutdown anyway. - } - try { - await client._shutdown(5000) - } - catch { - // Shutdown errors are also non-fatal during process exit. - } - }) - } - return client - }, - }) - const productEventService = injeca.provide('services:productEvents', { dependsOn: { db, otel }, build: ({ dependsOn }) => createProductEventService(dependsOn.db, dependsOn.otel?.product), @@ -608,7 +566,7 @@ export async function createApp() { }) const auth = injeca.provide('services:auth', { - dependsOn: { db, env: parsedEnv, otel, email: emailService, userDeletionService, posthog, productEventService }, + dependsOn: { db, env: parsedEnv, otel, email: emailService, userDeletionService, productEventService }, build: async ({ dependsOn }) => { // Seed trusted OIDC clients into DB so FK constraints on oauth_access_token are satisfied await seedTrustedClients(dependsOn.db, dependsOn.env) @@ -621,7 +579,7 @@ export async function createApp() { redirectUris: client.redirectUris.join(', '), }).log('OIDC trusted client ready') } - return createAuth(dependsOn.db, dependsOn.env, dependsOn.email, dependsOn.otel?.auth, dependsOn.userDeletionService, dependsOn.posthog, dependsOn.productEventService) + return createAuth(dependsOn.db, dependsOn.env, dependsOn.email, dependsOn.otel?.auth, dependsOn.userDeletionService, dependsOn.productEventService) }, }) @@ -731,7 +689,6 @@ export async function createApp() { otel, userDeletionService, llmRouter, - posthog, }) // Register the cluster-wide ObservableGauges for sessions / users. Each // replica polls the same DB (cached inside each gauge, in-flight coalesced); @@ -773,7 +730,6 @@ export async function createApp() { otel: resolved.otel, userDeletionService: resolved.userDeletionService, llmRouter: resolved.llmRouter, - posthog: resolved.posthog, }) logger.withFields({ hostname: resolved.env.HOST, port: resolved.env.PORT }).log('Server started') diff --git a/apps/server/src/libs/auth.ts b/apps/server/src/libs/auth.ts index eee9d775b..c155117c4 100644 --- a/apps/server/src/libs/auth.ts +++ b/apps/server/src/libs/auth.ts @@ -1,5 +1,3 @@ -import type { PostHog } from 'posthog-node' - import type { AuthMetrics } from '../otel' import type { EmailService } from '../services/adapters/email' import type { ProductEventService } from '../services/domain/product-events' @@ -10,6 +8,7 @@ import type { Env } from './env' import { Buffer } from 'node:buffer' import { oauthProvider } from '@better-auth/oauth-provider' +import { useLogger } from '@guiiai/logg' import { betterAuth } from 'better-auth' import { drizzleAdapter } from 'better-auth/adapters/drizzle' import { createAuthMiddleware } from 'better-auth/api' @@ -17,13 +16,14 @@ import { deleteSessionCookie } from 'better-auth/cookies' import { admin, bearer, jwt, magicLink } from 'better-auth/plugins' import { eq } from 'drizzle-orm' -import { captureSafe } from '../services/adapters/posthog' import { ApiError } from '../utils/error' import { getAuthTrustedOrigins, getTrustedOrigin } from '../utils/origin' import { oidcJwtBearer } from './auth-plugins/oidc-jwt-bearer' import * as authSchema from '../schemas/accounts' +const logger = useLogger('auth').useGlobalConfig() + interface TrustedClientSeed { clientId: string /** Omit for public clients — only confidential clients need a secret. */ @@ -365,7 +365,6 @@ export function createAuth( email?: EmailService, metrics?: AuthMetrics | null, userDeletionService?: UserDeletionService, - posthog?: PostHog | null, productEventService?: ProductEventService, ) { return betterAuth({ @@ -665,17 +664,13 @@ export function createAuth( create: { after: async (user) => { metrics?.userRegistered.add(1) - await productEventService?.track({ + void productEventService?.track({ userId: user.id, feature: 'auth', action: 'user_signed_up', status: 'succeeded', source: 'better-auth.user.create', }) - await captureSafe(posthog ?? null, { - event: 'user_signed_up', - distinctId: user.id, - }) }, }, update: { @@ -706,21 +701,20 @@ export function createAuth( // `after` hook for last-seen / analytics. after: async (session) => { metrics?.userLogin.add(1) - await db + // Best-effort analytics: session creation must not fail because + // active-user reporting is degraded. + void db .update(authSchema.user) .set({ lastSeenAt: new Date() }) .where(eq(authSchema.user.id, session.userId)) - await productEventService?.track({ + .catch(err => logger.withError(err).withFields({ userId: session.userId }).warn('Failed to update user lastSeenAt; continuing session create')) + void productEventService?.track({ userId: session.userId, feature: 'auth', action: 'session_started', status: 'succeeded', source: 'better-auth.session.create', }) - await captureSafe(posthog ?? null, { - event: 'session_started', - distinctId: session.userId, - }) }, }, }, diff --git a/apps/server/src/libs/env.ts b/apps/server/src/libs/env.ts index 1e93d1fb4..b514f16df 100644 --- a/apps/server/src/libs/env.ts +++ b/apps/server/src/libs/env.ts @@ -131,11 +131,6 @@ const EnvSchema = object({ STRIPE_SECRET_KEY: optional(string()), STRIPE_WEBHOOK_SECRET: optional(string()), - // PostHog server-side analytics. Optional — when unset the client is null - // and `captureSafe(...)` is a no-op so webhooks still complete. - POSTHOG_API_KEY: optional(string(), ''), - POSTHOG_HOST: optional(string(), 'https://us.i.posthog.com'), - // LLM/TTS gateway is fully internalised by the in-process router; provider // baseURLs live per-upstream inside LLM_ROUTER_CONFIG, and the default chat / // tts model aliases moved to configKV (DEFAULT_CHAT_MODEL / DEFAULT_TTS_MODEL) diff --git a/apps/server/src/routes/openai/v1/operations/chat-completions/index.ts b/apps/server/src/routes/openai/v1/operations/chat-completions/index.ts index c819be162..061fc8d8c 100644 --- a/apps/server/src/routes/openai/v1/operations/chat-completions/index.ts +++ b/apps/server/src/routes/openai/v1/operations/chat-completions/index.ts @@ -4,7 +4,6 @@ import type { V1RouteDeps } from '../../types' import { useLogger } from '@guiiai/logg' -import { captureSafe } from '../../../../../services/adapters/posthog' import { extractUsageFromBody } from '../../../../../services/domain/billing/billing' import { nanoid } from '../../../../../utils/id' import { buildSafeResponseHeaders } from '../../http/response' @@ -156,19 +155,6 @@ export function chatCompletions(deps: V1RouteDeps): GatewayCallback<'chat.comple stream, }, }) - // Emit server-side so funnels see real HTTP status — the client only - // ever observes "stream closed" and cannot tell 401 / 429 / 5xx apart. - void captureSafe(deps.posthog ?? null, { - distinctId: input.userId, - event: 'llm_request_failed', - properties: { - model: requestModel, - http_status: response.status, - duration_ms: durationMs, - stream: !!body.stream, - }, - }) - logger.withFields({ requestId, userId: input.userId, model: requestModel, status: response.status, durationMs }) .warn('chat completion delivered with upstream error status') @@ -400,21 +386,6 @@ function streamChatCompletion(input: { }, }) - void captureSafe(input.deps.posthog ?? null, { - distinctId: input.userId, - event: 'llm_request_succeeded', - properties: { - model: input.requestModel, - http_status: input.response.status, - duration_ms: input.durationMs, - prompt_tokens: usage.promptTokens ?? 0, - completion_tokens: usage.completionTokens ?? 0, - flux_consumed: actualCharged, - stream: true, - stream_interrupted: streamInterrupted, - }, - }) - input.logger.withFields({ requestId: input.requestId, userId: input.userId, @@ -534,20 +505,6 @@ async function completeNonStreamingChat(input: { }, }) - void captureSafe(input.deps.posthog ?? null, { - distinctId: input.userId, - event: 'llm_request_succeeded', - properties: { - model: input.requestModel, - http_status: input.response.status, - duration_ms: input.durationMs, - prompt_tokens: usage.promptTokens ?? 0, - completion_tokens: usage.completionTokens ?? 0, - flux_consumed: actualCharged, - stream: false, - }, - }) - input.logger.withFields({ requestId: input.requestId, userId: input.userId, diff --git a/apps/server/src/routes/openai/v1/route.test.ts b/apps/server/src/routes/openai/v1/route.test.ts index b7117752a..da98d4267 100644 --- a/apps/server/src/routes/openai/v1/route.test.ts +++ b/apps/server/src/routes/openai/v1/route.test.ts @@ -151,7 +151,6 @@ function createTestApp( genAi: null, revenue: null, rateLimitMetrics: null, - posthog: null, llmTracing, }) const app = new Hono() diff --git a/apps/server/src/routes/openai/v1/types.ts b/apps/server/src/routes/openai/v1/types.ts index e1b1e9490..abc8583d5 100644 --- a/apps/server/src/routes/openai/v1/types.ts +++ b/apps/server/src/routes/openai/v1/types.ts @@ -1,5 +1,3 @@ -import type { PostHog } from 'posthog-node' - import type { GenAiMetrics, RateLimitMetrics, RevenueMetrics } from '../../../otel' import type { ConfigKVService } from '../../../services/adapters/config-kv' import type { BillingService } from '../../../services/domain/billing/billing-service' @@ -28,7 +26,6 @@ export interface V1RouteDeps { genAi?: GenAiMetrics | null revenue?: RevenueMetrics | null rateLimitMetrics?: RateLimitMetrics | null - posthog?: PostHog | null llmTracing: LlmTracingDeps } diff --git a/apps/server/src/routes/stripe/index.ts b/apps/server/src/routes/stripe/index.ts index 23af9218f..6428d16a2 100644 --- a/apps/server/src/routes/stripe/index.ts +++ b/apps/server/src/routes/stripe/index.ts @@ -1,5 +1,4 @@ import type Redis from 'ioredis' -import type { PostHog } from 'posthog-node' import type { Env } from '../../libs/env' import type { RateLimitMetrics, RevenueMetrics } from '../../otel' @@ -47,7 +46,6 @@ export function createStripeRoutes( redis: Redis, metrics?: RevenueMetrics | null, rateLimitMetrics?: RateLimitMetrics | null, - posthog?: PostHog | null, productEventService?: ProductEventService, ) { const stripe = env.STRIPE_SECRET_KEY ? new Stripe(env.STRIPE_SECRET_KEY) : null @@ -60,7 +58,6 @@ export function createStripeRoutes( stripeService, billingService, metrics, - posthog, productEventService, }) diff --git a/apps/server/src/routes/stripe/operations/webhook.ts b/apps/server/src/routes/stripe/operations/webhook.ts index 9f7661958..5e57b4537 100644 --- a/apps/server/src/routes/stripe/operations/webhook.ts +++ b/apps/server/src/routes/stripe/operations/webhook.ts @@ -1,4 +1,3 @@ -import type { PostHog } from 'posthog-node' import type Stripe from 'stripe' import type { RevenueMetrics } from '../../../otel' @@ -9,7 +8,6 @@ import type { StripeService } from '../../../services/domain/stripe' import { useLogger } from '@guiiai/logg' -import { captureSafe } from '../../../services/adapters/posthog' import { createBadRequestError, createServiceUnavailableError } from '../../../utils/error' import { errorMessageFromUnknown } from '../../../utils/error-message' @@ -22,7 +20,6 @@ export interface WebhookOperationDeps { stripeService: StripeService billingService: BillingService metrics?: RevenueMetrics | null - posthog?: PostHog | null productEventService?: ProductEventService } @@ -75,13 +72,9 @@ export function createWebhookOperation(deps: WebhookOperationDeps) { source: 'checkout', }) } - // PostHog: funnel terminator. Only fire when the handler actually - // processed the checkout — malformed sessions (missing userId, - // invalid fluxAmount) take the early-return path above and would - // otherwise poison the funnel with phantom conversions. distinctId - // is the Better Auth user id so it merges with the browser's - // `posthog.identify(userId)` and the prior `checkout_started` - // event lines up. See docs/ai-context/metrics-ownership.md. + // Record the product conversion only after the handler actually + // processed the checkout. Malformed sessions (missing userId, + // invalid fluxAmount) take the early-return path above. if (result.processed) { const userId = event.data.object.metadata?.userId if (userId) { @@ -99,7 +92,6 @@ export function createWebhookOperation(deps: WebhookOperationDeps) { }, }) } - await capturePaymentCompleted(deps.posthog, event.data.object) } break } @@ -113,8 +105,6 @@ export function createWebhookOperation(deps: WebhookOperationDeps) { case 'customer.subscription.deleted': { await handleSubscriptionEvent(event.data.object, deps.stripeService) deps.metrics?.stripeSubscriptionEvent.add(1, { event_type: event.type.replace('customer.subscription.', '') }) - if (event.type === 'customer.subscription.deleted') - await captureSubscriptionCancelled(deps.posthog, deps.stripeService, event.data.object) break } case 'invoice.created': @@ -226,73 +216,6 @@ async function handleCheckoutSessionCompleted( return { processed: true } } -async function capturePaymentCompleted( - posthog: PostHog | null | undefined, - session: Stripe.Checkout.Session, -): Promise { - if (!posthog) - return - - const userId = session.metadata?.userId - const email = session.customer_email - || (typeof session.customer_details?.email === 'string' ? session.customer_details.email : null) - || null - - // distinctId fallback chain: userId (Better Auth, matches browser identify()) - // > email (PostHog will merge on identify later) > stripe session id (last - // resort — orphan event but at least we count it). - const distinctId = userId || email || session.id - - const fluxAmount = Number(session.metadata?.fluxAmount) - const stripeCustomerId = typeof session.customer === 'string' ? session.customer : session.customer?.id - - await captureSafe(posthog, { - distinctId, - event: 'payment_completed', - properties: { - amount_total: session.amount_total, - currency: session.currency, - flux_amount: Number.isFinite(fluxAmount) ? fluxAmount : null, - mode: session.mode, - stripe_session_id: session.id, - stripe_customer_id: stripeCustomerId, - stripe_subscription_id: typeof session.subscription === 'string' ? session.subscription : session.subscription?.id, - ...(userId ? { user_id: userId } : {}), - // $set populates the PostHog person profile so funnel joins work even - // when a user pays via direct checkout link before ever loading the SPA. - ...(email ? { $set: { email } } : {}), - }, - }) -} - -async function captureSubscriptionCancelled( - posthog: PostHog | null | undefined, - stripeService: StripeService, - subscription: Stripe.Subscription, -): Promise { - if (!posthog) - return - - const stripeCustomerId = typeof subscription.customer === 'string' ? subscription.customer : subscription.customer.id - const customer = await stripeService.getCustomerByStripeId(stripeCustomerId) - const distinctId = customer?.userId || stripeCustomerId - - await captureSafe(posthog, { - distinctId, - event: 'subscription_cancelled', - properties: { - stripe_subscription_id: subscription.id, - stripe_customer_id: stripeCustomerId, - cancel_at_period_end: subscription.cancel_at_period_end, - cancellation_reason: subscription.cancellation_details?.reason ?? null, - cancellation_comment: subscription.cancellation_details?.comment ?? null, - canceled_at: subscription.canceled_at, - ended_at: subscription.ended_at, - ...(customer?.userId ? { user_id: customer.userId } : {}), - }, - }) -} - async function handleCustomerEvent( customer: Stripe.Customer | Stripe.DeletedCustomer, stripeService: StripeService, diff --git a/apps/server/src/services/adapters/posthog.ts b/apps/server/src/services/adapters/posthog.ts deleted file mode 100644 index c2ef529f1..000000000 --- a/apps/server/src/services/adapters/posthog.ts +++ /dev/null @@ -1,95 +0,0 @@ -import type { Env } from '../../libs/env' - -import { useLogger } from '@guiiai/logg' -import { PostHog } from 'posthog-node' - -const logger = useLogger('posthog') - -/** - * Server-side PostHog client. Used to capture authoritative business events - * the browser cannot see (Stripe webhooks, subscription state changes, - * admin actions). Pairs with the browser-side PostHog already wired up in - * `packages/stage-ui/src/stores/analytics/posthog.ts`. - * - * Use when: - * - You're inside a server-side handler (Stripe webhook, admin route) and - * need to emit an event that will be analysed in PostHog funnels or - * cohorts (e.g. `payment_completed`, `subscription_cancelled`). - * - * Expects: - * - `POSTHOG_API_KEY` env var. When unset (dev/CI) this returns `null` so - * callers degrade gracefully with `posthog?.capture(...)`. - * - `distinctId` must match the browser's `posthog.identify(userId)` — we - * use the Better Auth `user.id` for that everywhere. Stripe webhooks - * that only have an email use the email as a fallback `distinctId` and - * include `userId` in the event properties so PostHog's merge resolves - * the person. - * - * Returns: - * - A `PostHog` client configured for low-latency immediate sends, or - * `null` when key is unset. Callers must use `captureSafe()` (which - * wraps `captureImmediate`) — the regular `capture()` only enqueues - * and would let webhook responses race ahead of the HTTP send. - */ -export function createPostHogClient(env: Env): PostHog | null { - if (!env.POSTHOG_API_KEY) { - logger.warn('POSTHOG_API_KEY is unset — server-side analytics disabled') - return null - } - - // NOTICE: - // `flushAt: 1` keeps the background-batch threshold low so any stray - // `posthog.capture()` (non-immediate path) flushes promptly. Real send- - // path for webhook events goes through `captureImmediate()` in - // `captureSafe`, which bypasses the queue entirely and resolves only - // after the HTTP round-trip. We also rely on `shutdown(timeoutMs)` from - // app.ts to drain any residual queue on SIGTERM. - return new PostHog(env.POSTHOG_API_KEY, { - host: env.POSTHOG_HOST || 'https://us.i.posthog.com', - flushAt: 1, - flushInterval: 0, - }) -} - -/** - * Safe capture wrapper. PostHog must never block or fail a webhook / - * billing path — any error here is logged and swallowed. - * - * Use when: - * - Inside a server-side handler that has business work to finish even - * if PostHog is down. The handler already wrote to Postgres and - * updated metrics; PostHog is the optional last step. - * - * Expects: - * - Caller awaits the returned promise. We use `captureImmediate` (not - * `capture`) because PostHog Node SDK's regular `capture` only enqueues - * — `flushAt: 1` triggers a *background* flush, which means the webhook - * handler can return before the event reaches PostHog and SIGTERM may - * strand the queued event. `captureImmediate` does the HTTP send inline - * and resolves only after the network round-trip. - * - * Consent boundary: - * - Browser-side capture is gated by `useAnalytics().canCapture()` (user - * toggle in Settings → Analytics). - * - Server-side events here are operational telemetry tied to business - * facts that already occurred (auth records the user, Stripe records - * the payment, the LLM router records the request). They are emitted - * regardless of the browser toggle on legitimate-interest grounds — - * the user cannot opt out of the server knowing they signed up or - * paid, only out of additional product analytics on top. Surface this - * distinction in the privacy policy. - */ -export async function captureSafe( - posthog: PostHog | null, - event: { distinctId: string, event: string, properties?: Record }, -): Promise { - if (!posthog) - return - - try { - await posthog.captureImmediate(event) - } - catch (err) { - logger.withError(err).withFields({ event: event.event, distinctId: event.distinctId }).warn('PostHog captureImmediate failed; swallowing to protect caller') - } -} diff --git a/apps/server/tests/verifications/_harness.ts b/apps/server/tests/verifications/_harness.ts index e496e8125..d1f2f8c46 100644 --- a/apps/server/tests/verifications/_harness.ts +++ b/apps/server/tests/verifications/_harness.ts @@ -199,7 +199,6 @@ export async function startVerificationContext() { route: vi.fn(async () => new Response('{}', { status: 200 })), invalidateConfig: vi.fn(), } as any, - posthog: null, }) return { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b56c7c681..0e2336640 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -880,9 +880,6 @@ catalogs: posthog-js: specifier: 1.306.1 version: 1.306.1 - posthog-node: - specifier: ^5.34.1 - version: 5.34.1 postprocessing: specifier: ^6.39.1 version: 6.39.1 @@ -1608,9 +1605,6 @@ importers: pg: specifier: 'catalog:' version: 8.20.0 - posthog-node: - specifier: 'catalog:' - version: 5.34.1(rxjs@7.8.2) resend: specifier: 'catalog:' version: 6.12.2 @@ -2345,7 +2339,7 @@ importers: version: 3.0.2(electron@41.2.1) '@electron-toolkit/tsconfig': specifier: 'catalog:' - version: 2.0.0(@types/node@24.12.2) + version: 2.0.0(@types/node@25.6.0) '@electron-toolkit/utils': specifier: 'catalog:' version: 4.0.0(electron@41.2.1) @@ -2384,7 +2378,7 @@ importers: version: 3.1.0 '@intlify/unplugin-vue-i18n': specifier: 'catalog:' - version: 11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + version: 11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) '@modelcontextprotocol/sdk': specifier: 'catalog:' version: 1.29.0(@cfworker/json-schema@4.1.1)(zod@4.3.6) @@ -2420,10 +2414,10 @@ importers: version: link:../../packages/ui-transitions '@proj-airi/unplugin-fetch': specifier: 'catalog:' - version: 0.2.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 0.2.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@proj-airi/unplugin-live2d-sdk': specifier: 'catalog:' - version: 0.1.7(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 0.1.7(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) '@types/audioworklet': specifier: 'catalog:' version: 0.0.97 @@ -2450,7 +2444,7 @@ importers: version: 2.10.3 '@vitejs/plugin-vue': specifier: 'catalog:' - version: 6.0.6(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) + version: 6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) '@vue-macros/volar': specifier: 'catalog:' version: 3.1.2(typescript@5.9.3)(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) @@ -2483,7 +2477,7 @@ importers: version: 6.8.3 electron-vite: specifier: 'catalog:' - version: 5.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 5.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) get-port-please: specifier: 'catalog:' version: 3.2.0 @@ -2504,31 +2498,31 @@ importers: version: 2.2.6 unocss-preset-scrollbar: specifier: 'catalog:' - version: 4.0.0(unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) + version: 4.0.0(unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) unplugin-info: specifier: 'catalog:' - version: 1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) unplugin-yaml: specifier: 'catalog:' - version: 4.1.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.0(@nuxt/kit@3.20.2(magicast@0.5.2))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vite: specifier: 'catalog:' - version: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-bundle-visualizer: specifier: 'catalog:' version: 1.2.1(rolldown@1.0.0-rc.16)(rollup@4.60.1) vite-plugin-mkcert: specifier: 'catalog:' - version: 2.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 2.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plugin-vue-devtools: specifier: 'catalog:' - version: 8.1.1(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) + version: 8.1.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) vite-plugin-vue-layouts: specifier: 'catalog:' - version: 0.11.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + version: 0.11.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) vue-macros: specifier: 'catalog:' - version: 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) + version: 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) vue-tsc: specifier: 'catalog:' version: 3.2.6(typescript@5.9.3) @@ -9654,15 +9648,9 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@posthog/core@1.29.1': - resolution: {integrity: sha512-q+/t/DZALr50YTE0dFgfGSS9EgwcyAlqsn+JS61wLkwdcDM5yu/YTDM8oMKmJupsyjSZlVkDuHZAMd4ab7AxzQ==} - '@posthog/core@1.7.1': resolution: {integrity: sha512-kjK0eFMIpKo9GXIbts8VtAknsoZ18oZorANdtuTj1CbgS28t4ZVq//HAWhnxEuXRTrtkd+SUJ6Ux3j2Af8NCuA==} - '@posthog/types@1.373.4': - resolution: {integrity: sha512-n+0AbGRYYsbi+CQXQi2rF1lwTSyASlaogcw4YSkzB5KeMa4Y6nhNb7+TTnu9aVor+BycsQYCa2OsBrMMbaTekw==} - '@prisma/client@5.22.0': resolution: {integrity: sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==} engines: {node: '>=16.13'} @@ -16684,15 +16672,6 @@ packages: posthog-js@1.306.1: resolution: {integrity: sha512-wO7bliv/5tlAlfoKCUzwkGXZVNexk0dHigMf9tNp0q1rzs62wThogREY7Tz7h/iWKYiuXy1RumtVlTmHuBXa1w==} - posthog-node@5.34.1: - resolution: {integrity: sha512-kGl0kSfh2+Ey3KL5Sji3yv9W5xwPK9sTkINRoFqCh9fbYXWWY6Zwi5Psv2QmRcbYiMJBk/iecnoOKVDRRga6PA==} - engines: {node: ^20.20.0 || >=22.22.0} - peerDependencies: - rxjs: ^7.0.0 - peerDependenciesMeta: - rxjs: - optional: true - postject@1.0.0-alpha.6: resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} engines: {node: '>=14.0.0'} @@ -20909,9 +20888,9 @@ snapshots: dependencies: electron: 41.2.1 - '@electron-toolkit/tsconfig@2.0.0(@types/node@24.12.2)': + '@electron-toolkit/tsconfig@2.0.0(@types/node@25.6.0)': dependencies: - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@electron-toolkit/utils@4.0.0(electron@41.2.1)': dependencies: @@ -21823,31 +21802,6 @@ snapshots: - supports-color - typescript - '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3))': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) - '@intlify/bundle-utils': 11.0.7(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3))) - '@intlify/shared': 11.3.2 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.3.2)(@vue/compiler-dom@3.5.32)(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) - '@rollup/pluginutils': 5.3.0(rollup@4.60.1) - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) - debug: 4.4.3(supports-color@10.2.2) - fast-glob: 3.3.3 - pathe: 2.0.3 - picocolors: 1.1.1 - unplugin: 2.3.11 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vue: 3.5.32(typescript@5.9.3) - optionalDependencies: - vue-i18n: 11.3.2(vue@3.5.32(typescript@5.9.3)) - transitivePeerDependencies: - - '@vue/compiler-dom' - - eslint - - rollup - - supports-color - - typescript - '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) @@ -23789,16 +23743,10 @@ snapshots: '@polka/url@1.0.0-next.29': {} - '@posthog/core@1.29.1': - dependencies: - '@posthog/types': 1.373.4 - '@posthog/core@1.7.1': dependencies: cross-spawn: 7.0.6 - '@posthog/types@1.373.4': {} - '@prisma/client@5.22.0': {} '@proj-airi/chromatic@1.1.1': @@ -23856,35 +23804,11 @@ snapshots: transitivePeerDependencies: - magicast - '@proj-airi/unplugin-fetch@0.2.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - ofetch: 1.5.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - '@proj-airi/unplugin-fetch@0.2.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: ofetch: 1.5.1 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - '@proj-airi/unplugin-live2d-sdk@0.1.7(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)': - dependencies: - ofetch: 1.5.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - yauzl: 3.3.0 - transitivePeerDependencies: - - '@types/node' - - '@vitejs/devtools' - - esbuild - - jiti - - less - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - '@proj-airi/unplugin-live2d-sdk@0.1.7(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)': dependencies: ofetch: 1.5.1 @@ -25450,12 +25374,6 @@ snapshots: vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vue: 3.5.32(typescript@5.9.3) - '@vitejs/plugin-vue@6.0.6(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3))': - dependencies: - '@rolldown/pluginutils': 1.0.0-rc.13 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vue: 3.5.32(typescript@5.9.3) - '@vitejs/plugin-vue@6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.13 @@ -25536,9 +25454,9 @@ snapshots: obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.1.1(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.1.1(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) optionalDependencies: - '@vitest/browser': 4.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4) + '@vitest/browser': 4.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4) '@vitest/eslint-plugin@1.6.15(@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.1.4)': dependencies: @@ -25758,15 +25676,6 @@ snapshots: transitivePeerDependencies: - vue - '@vue-macros/devtools@3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - sirv: 3.0.2 - vue: 3.5.32(typescript@5.9.3) - optionalDependencies: - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - typescript - '@vue-macros/devtools@3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: sirv: 3.0.2 @@ -27908,7 +27817,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron-vite@5.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + electron-vite@5.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) @@ -27916,7 +27825,7 @@ snapshots: esbuild: 0.25.12 magic-string: 0.30.21 picocolors: 1.1.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -31983,12 +31892,6 @@ snapshots: preact: 10.28.1 web-vitals: 4.2.4 - posthog-node@5.34.1(rxjs@7.8.2): - dependencies: - '@posthog/core': 1.29.1 - optionalDependencies: - rxjs: 7.8.2 - postject@1.0.0-alpha.6: dependencies: commander: 9.5.0 @@ -33944,6 +33847,11 @@ snapshots: '@unocss/preset-mini': 66.6.8 unocss: 66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + unocss-preset-scrollbar@4.0.0(unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))): + dependencies: + '@unocss/preset-mini': 66.6.8 + unocss: 66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@unocss/cli': 66.6.8 @@ -34040,14 +33948,6 @@ snapshots: unplugin: 2.3.11 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - unplugin-combine@2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - optionalDependencies: - esbuild: 0.27.2 - rolldown: 1.0.0-rc.16 - rollup: 4.60.1 - unplugin: 2.3.11 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - unplugin-combine@2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): optionalDependencies: esbuild: 0.27.2 @@ -34082,19 +33982,6 @@ snapshots: transitivePeerDependencies: - supports-color - unplugin-info@1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - ci-info: 4.4.0 - git-url-parse: 16.1.0 - simple-git: 3.36.0 - unplugin: 2.3.11 - optionalDependencies: - esbuild: 0.27.2 - rollup: 4.60.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - supports-color - unplugin-info@1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: ci-info: 4.4.0 @@ -34204,17 +34091,6 @@ snapshots: rollup: 4.60.1 vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - unplugin-yaml@4.1.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.60.1) - unplugin: 3.0.0 - yaml: 2.8.3 - optionalDependencies: - esbuild: 0.27.2 - rolldown: 1.0.0-rc.16 - rollup: 4.60.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 @@ -34446,22 +34322,12 @@ snapshots: - rollup - supports-color - vite-dev-rpc@1.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - birpc: 2.9.0 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-hot-client: 2.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - vite-dev-rpc@1.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: birpc: 2.9.0 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-hot-client: 2.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - vite-hot-client@2.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-hot-client@2.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) @@ -34507,21 +34373,6 @@ snapshots: - tsx - yaml - vite-plugin-inspect@11.3.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - ansis: 4.2.0 - debug: 4.4.3(supports-color@10.2.2) - error-stack-parser-es: 1.0.5 - ohash: 2.0.11 - open: 10.2.0 - perfect-debounce: 2.1.0 - sirv: 3.0.2 - unplugin-utils: 0.3.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-dev-rpc: 1.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - transitivePeerDependencies: - - supports-color - vite-plugin-inspect@11.3.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: ansis: 4.2.0 @@ -34553,13 +34404,6 @@ snapshots: - typescript - ws - vite-plugin-mkcert@2.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - debug: 4.4.3(supports-color@10.2.2) - supports-color: 10.2.2 - undici: 8.1.0 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-plugin-mkcert@2.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -34578,20 +34422,6 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vue-devtools@8.1.1(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)): - dependencies: - '@vue/devtools-core': 8.1.1(vue@3.5.32(typescript@5.9.3)) - '@vue/devtools-kit': 8.1.1 - '@vue/devtools-shared': 8.1.1 - sirv: 3.0.2 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-plugin-inspect: 11.3.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - vite-plugin-vue-inspector: 5.3.2(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - transitivePeerDependencies: - - '@nuxt/kit' - - supports-color - - vue - vite-plugin-vue-devtools@8.1.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)): dependencies: '@vue/devtools-core': 8.1.1(vue@3.5.32(typescript@5.9.3)) @@ -34606,21 +34436,6 @@ snapshots: - supports-color - vue - vite-plugin-vue-inspector@5.3.2(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.29.0) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.29.0) - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0) - '@vue/compiler-dom': 3.5.32 - kolorist: 1.8.0 - magic-string: 0.30.21 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - supports-color - vite-plugin-vue-inspector@5.3.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@babel/core': 7.29.0 @@ -34636,16 +34451,6 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vue-layouts@0.11.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)): - dependencies: - debug: 4.4.3(supports-color@10.2.2) - fast-glob: 3.3.3 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vue: 3.5.32(typescript@5.9.3) - vue-router: 5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) - transitivePeerDependencies: - - supports-color - vite-plugin-vue-layouts@0.11.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)): dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -34912,54 +34717,6 @@ snapshots: - vue-tsc - webpack - vue-macros@3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)): - dependencies: - '@vue-macros/better-define': 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/boolean-prop': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/chain-call': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/common': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/config': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-emit': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-models': 3.1.2(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-prop': 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-props': 3.1.2(@vue-macros/reactivity-transform@3.1.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-props-refs': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-render': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-slots': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-stylex': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/devtools': 3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vue-macros/export-expose': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/export-props': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/export-render': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/hoist-static': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/jsx-directive': 3.1.2(typescript@5.9.3) - '@vue-macros/named-template': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/reactivity-transform': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/script-lang': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/setup-block': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/setup-component': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/setup-sfc': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/short-bind': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/short-emits': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/short-vmodel': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/volar': 3.1.2(typescript@5.9.3)(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) - unplugin: 2.3.11 - unplugin-combine: 2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - unplugin-vue-define-options: 3.1.2(vue@3.5.32(typescript@5.9.3)) - vue: 3.5.32(typescript@5.9.3) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - '@rspack/core' - - '@vueuse/core' - - esbuild - - rolldown - - rollup - - typescript - - vite - - vue-tsc - - webpack - vue-macros@3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)): dependencies: '@vue-macros/better-define': 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vue@3.5.32(typescript@5.9.3)) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1493b91c4..fab37cee2 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -321,7 +321,6 @@ catalog: postcss: ^8.5.10 postgres: ^3.4.9 posthog-js: 1.306.1 - posthog-node: ^5.34.1 postprocessing: ^6.39.1 prismarine-block: ^1.23.0 prismarine-entity: ^2.6.0