mirror of
https://github.com/civitai/civitai.git
synced 2026-09-20 22:08:18 +08:00
8113e62777
* fix(metrics): exclude metric-suppressed accounts from Postgres reaction sums The reaction counts shown on posts, articles and bounty entries are summed in Postgres from ImageReaction/ArticleReaction/BountyEntryReaction with no exclusion predicate, so they count accounts the reaction-abuse detector already suppressed from every other reaction surface. Unlike the ClickHouse totals these never decay: the jobs recompute the same unfiltered sum from the same rows, so the numbers stay wrong until the queries filter. Post has two live reaction queries, not one — post.metrics.ts delegates to post.metrics-old.ts whenever the simplified-post-metrics flag reads false, which includes Flipt being unreachable. Both filter now. The jobs read the list through a new getMetricExcludedUserIdsOrThrow rather than the existing lenient reader. The lenient one degrades to [] so the reaction milestone keeps firing during an outage; a metric job doing that would write an unfiltered total that nothing later recomputes, because a job only revisits an entity that receives another reaction. Rejecting instead leaves the cursor and the queue untouched in createMetricProcessor, so the window is recomputed next run. Answer and Question reaction metrics have the same shape and are left alone — out of the scope this was asked for, and named as exemptions in the guard rather than skipped silently. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(metrics): zero the entities whose reactions are ALL excluded, and filter the milestones too Five review lanes over 9cb53ed. Everything here is a finding they raised, each verified against the code or the replica before acting on it. Filtering the aggregate was not enough. An entity whose remaining countable reactions are zero produces NO ROW from a GROUP BY over the reaction table, and a missing row means "no change" to every writer downstream — so the pre-exclusion total survived even a full recompute. Measured on the replica: 18 of 594 affected articles and 338 of 1,154 affected bounty entries are in that state. Post and article seed zeros into ctx.updates before the aggregate overwrites them; bountyEntry has no JS intermediate, so its CTE now drives from the affected ids with a LEFT JOIN. That LEFT JOIN needed timeframeSum to be NULL-safe. Its leading `WHEN NOT (cond) THEN 0` is NULL for an unmatched row and falls through to the AllTime arm, counting a reaction that is not there. `(cond) IS NOT TRUE` is identical for every inner-joined caller. Verified on the replica: with the old form a fully-excluded entry returns 1 heart / 1 like, with the new form 0. The seeding was only safe once a pre-existing bug was fixed. Both post jobs bound their chunk with `BETWEEN ids[0] AND ids[ids.length - 1]` over an unordered Set, so roughly half of all chunks matched nothing. Seeding zeros into a chunk that matches nothing would have written zeros over real counts. The chunk is sorted now. The article and bounty-entry milestone notifications counted unfiltered. Before this work both halves were unfiltered and therefore agreed; filtering only the displayed half would have manufactured, for those two entities, the exact display-vs-notification divergence this defect is a sibling of. They use the LENIENT reader on purpose — a notification should degrade to the old count, not to silence. The guard now covers the notifications too, and three mutations that were demonstrated to pass against it: a `.catch(() => [])` on the strict read, a filter spliced inside an SQL line comment, and a wrong column argument. The last is fixed by construction — the column is hardcoded rather than passed, since a raw-SQL parameter beside an integer guard reads as though the guard covered it. Also: the strict reader now reports the outage to Axiom instead of surfacing only as a generic job error, and a comment claiming coercion parity with metric-reaction-repair.service.ts was false and now says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(metrics): assert the emitted SQL, not that a token appears in the file Round 2 of review demonstrated six mutations that pass the source guard, each measured rather than argued: a second unfiltered count of the same table in the same template literal; a consistent alias swap so `r."userId"` names the image owner instead of the reactor; `.then().catch()` and a plain try/catch around the strict read; a key moved into the exemption list, which had no length pin; a `/* */` comment around the splice; and the bounty-entry filter moved out of the LEFT JOIN's ON into a WHERE, which collapses it to an inner join and restores the no-row defect the rewrite exists to fix. A source guard checks that a token appears in a file. It cannot see what the composed statement does, which is why six separate textual assertions each missed one of these in their own way. `post-reaction-metrics-sql.test.ts` calls the real getReactionTasks with a fake pg that captures every statement, and asserts on the SQL that was actually sent — one test that catches the alias swap, the swallow, the commented splice, the second count, the missing sort and the missing zero-fill. Its fixture crosses the 30,000-image chunk boundary and returns a LOWER run of post ids second. That is not decoration: the first version of the sort control PASSED, because `getAffected` sorts its own return, so a single-chunk fixture cannot produce the out-of-order set the bug needs. It was an assertion that could not fail for the case it was named after. The guard keeps the cases it can see, hardened: block comments as well as line comments, a requirement that the filter be built from a direct `await` of the reader rather than any expression with somewhere to swallow a rejection, a requirement that the alias `r` is bound to the reaction table and to nothing else, a shape pin on the bounty-entry ON clause, and a length pin on the exemption list. Two fixes to the round-1 fix. The Axiom report was effectively unreachable: one latch shared by both readers, and the lenient one runs on every reaction toggle, so it wins every race and the only line for an incident would say a notification degraded while the metric jobs stalled silently. Keyed per outcome now. And `post.metrics.ts` chunked image ids from a ClickHouse query with no ORDER BY under the same inverted-BETWEEN bug fixed one block below; post.metrics-old.ts has that ORDER BY, the live path did not. Both `!clickhouse` branches had no test at all, in any file, because every other test supplies a client. Backfill note, recorded here because a squash merge takes commit messages and not the PR body: this does NOT close ClickUp 868m6vftv. The filter only corrects an entity the next time it is affected, so the already-wrong rows stay wrong until a backfill recomputes them. That ships separately against main, not stacked on this branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(notifications): keep the ClickHouse client out of the client bundle The milestone filter pulled the exclusion-list reader — and through it the ClickHouse client — into the notification processor files. Those files are in the _app client graph, because prepareMessage renders there. no-server-infra-in-app-graph caught it: it ran and failed in 44ms before the full suite was killed by a daemon restart, so the one real result that run produced was this. A lazy import inside prepareQuery does not fix it. The guard says why and is right: a dynamic import() still compiles the chunk into the client bundle. So the processors no longer read the list at all. The server-only runner, send-notifications.ts, reads it once per job run with the lenient reader and passes it through NotificationProcessorRunInput, which prepareQuery already receives. The pure SQL builder moves to ~/shared/utils/excluded-reactor-filter.ts with no imports, and metrics/metric-helpers re-exports it. One read per run instead of one per processor. The field is optional and the two reaction milestones default a missing list to [], because degrading to the pre-exclusion count is already the posture these notifications want, and ten existing processor tests construct the input without it. That makes the runner the single point deciding whether milestones are filtered at all, so the guard now pins it: it must read with the lenient reader and pass the list to every prepareQuery, and a processor may import neither reader. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(notifications): pin the runner-to-milestone hand-off by behaviour, not spelling Round 3 of review measured eight mutations that ship the reaction milestones unfiltered with the source guard green, because the guard pinned how the hand-off is SPELLED rather than what is passed: a shadowing `const excludedUserIds = []` inside the batch loop, `excludedUserIds.length = 0` after the read, a spread that overrides the shorthand, a processor that ignores its input, a filter built but never spliced, and the filter moved into the `affected` CTE — valid SQL that narrows which entities are revisited while the COUNT stays unfiltered. send-notifications.excluded.test.ts runs the real job with the real processors, captures the SQL they send, and asserts the filter lands in the CTE that COUNTS. All six of the lane's mutations fail it by name; the processor-level ones fail only their own milestone. It also asserts no processor logged an error, because the runner swallows a per-processor throw and a milestone whose SQL no longer builds would otherwise read as "no query". NotificationProcessorRunInput.excludedUserIds is now required but nullable rather than optional. The milestones default a missing list to [], so a second runner that simply omitted the key would ship every milestone unfiltered without a sound. Required, tsc rejects it. Verified that the protection is real rather than vacuous: typecheck does not read __tests__, which is why ten fixtures building this input still pass, so the control was on the production caller — dropping the key from send-notifications.ts fails with TS2345 at line 49. Plus direct tests of the shared SQL builder's empty-list and non-integer branches, which only the non-empty path had reached. With the integer guard removed, the three non-integer cases fail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(notifications): bound the counting-CTE slice instead of failing open countingCte sliced from `affected_value AS (` to the next `), ` and, finding none, fell back to the end of the query. Round 4 of review measured that as a green mutant: put the next CTE's name on its own line and move the filter into `reaction_milestone`, a CTE that counts nothing, and the slice ran on far enough to include it. The helper now bounds the slice by the next CTE header and requires it to find one. That mutant is red now. The same round confirmed the other six mutants go red on the assertion named for their defect rather than incidentally, and found an alias-revert mutant (bounty table back to `br` beside a filter that names `r`) that this test does not catch because it never executes the SQL. It does not need to: no-unfiltered-reaction-metric-sum's alias assertion fails on it, verified. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(notifications): give the pgDb mock its full export set pgDbMock.parity requires every inline `~/server/db/pgDb` factory to list the complete export set, because kyselyDb.ts destructures all of them at module-eval time and Vitest throws on any omitted name — during module LOAD, so a suite that reaches it dies at collection and reports zero tests rather than failing. The job test listed only pgDbRead. It passed because kyselyDb is not in its graph, which is the case the guard exists to stop depending on. Caught by the full suite, the only thing that runs it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
457 lines
22 KiB
JSON
457 lines
22 KiB
JSON
{
|
|
"name": "model-share",
|
|
"version": "5.1.113",
|
|
"private": true,
|
|
"packageManager": "pnpm@10.28.1",
|
|
"engines": {
|
|
"node": ">=24.0.0 <25"
|
|
},
|
|
"scripts": {
|
|
"preinstall": "npx only-allow pnpm",
|
|
"start": "next start",
|
|
"start-debug": "NODE_OPTIONS='--inspect' next start",
|
|
"build:workers": "node scripts/build-workers.mjs",
|
|
"clean": "node -e \"fs.rmSync('.next',{recursive:true,force:true})\"",
|
|
"predev": "pnpm build:workers",
|
|
"dev": "next dev",
|
|
"dev:auth": "pnpm --filter @civitai/auth-app dev",
|
|
"dev:moderator": "pnpm --filter @civitai/moderator-app dev",
|
|
"dev:creator-studio": "pnpm --filter @civitai/creator-studio-app dev",
|
|
"dev:training-studio": "pnpm --filter @civitai/training-studio-app dev",
|
|
"dev:storage": "pnpm --filter @civitai/storage-app dev",
|
|
"dev-low": "cross-env NODE_OPTIONS=\"--max_old_space_size=6144\" next dev",
|
|
"dev-debug": "pnpm build:workers && cross-env NODE_OPTIONS=\"--max_old_space_size=8192 --inspect\" next dev",
|
|
"dev-snap": "cross-env NODE_OPTIONS=\"--max_old_space_size=8192 --heapsnapshot-near-heap-limit=3\" next dev",
|
|
"dev:daemon": "node .claude/skills/dev-server/console.mjs",
|
|
"dev:rgb": "node .claude/skills/dev-server/cli.mjs rgb start",
|
|
"dev:rgb:stop": "node .claude/skills/dev-server/cli.mjs rgb stop",
|
|
"dev:rgb:status": "node .claude/skills/dev-server/cli.mjs rgb status",
|
|
"prod": "cross-env NODE_ENV=production next dev",
|
|
"boost": "next-boost",
|
|
"release:base": "git checkout release && git pull --rebase && git rebase main && git push --force-with-lease && git checkout main",
|
|
"release:major": "git pull && npm version major && git push --follow-tags && pnpm run release:base",
|
|
"release:minor": "git pull && npm version minor && git push --follow-tags && pnpm run release:base",
|
|
"release:patch": "git pull && npm version patch && git push --follow-tags && pnpm run release:base",
|
|
"release": "pnpm run release:patch",
|
|
"release:auth": "pnpm run release:auth:patch",
|
|
"release:auth:patch": "node scripts/release-app.mjs apps/auth auth-app-v patch",
|
|
"release:auth:minor": "node scripts/release-app.mjs apps/auth auth-app-v minor",
|
|
"release:auth:major": "node scripts/release-app.mjs apps/auth auth-app-v major",
|
|
"release:notifications": "pnpm run release:notifications:patch",
|
|
"release:notifications:patch": "node scripts/release-app.mjs apps/notifications notifications-v patch",
|
|
"release:notifications:minor": "node scripts/release-app.mjs apps/notifications notifications-v minor",
|
|
"release:notifications:major": "node scripts/release-app.mjs apps/notifications notifications-v major",
|
|
"release:creator-studio": "pnpm run release:creator-studio:patch",
|
|
"release:creator-studio:patch": "node scripts/release-app.mjs apps/creator-studio creator-studio-v patch",
|
|
"release:creator-studio:minor": "node scripts/release-app.mjs apps/creator-studio creator-studio-v minor",
|
|
"release:creator-studio:major": "node scripts/release-app.mjs apps/creator-studio creator-studio-v major",
|
|
"release:storage": "pnpm run release:storage:patch",
|
|
"release:storage:patch": "node scripts/release-app.mjs apps/storage storage-v patch",
|
|
"release:storage:minor": "node scripts/release-app.mjs apps/storage storage-v minor",
|
|
"release:storage:major": "node scripts/release-app.mjs apps/storage storage-v major",
|
|
"release:event-engine": "pnpm run release:event-engine:patch",
|
|
"release:event-engine:patch": "node scripts/release-app.mjs apps/event-engine event-engine-v patch",
|
|
"release:event-engine:minor": "node scripts/release-app.mjs apps/event-engine event-engine-v minor",
|
|
"release:event-engine:major": "node scripts/release-app.mjs apps/event-engine event-engine-v major",
|
|
"release:moderator": "pnpm run release:moderator:patch",
|
|
"release:moderator:patch": "node scripts/release-app.mjs apps/moderator moderator-v patch",
|
|
"release:moderator:minor": "node scripts/release-app.mjs apps/moderator moderator-v minor",
|
|
"release:moderator:major": "node scripts/release-app.mjs apps/moderator moderator-v major",
|
|
"release:training-studio": "pnpm run release:training-studio:patch",
|
|
"release:training-studio:patch": "node scripts/release-app.mjs apps/training-studio training-studio-v patch",
|
|
"release:training-studio:minor": "node scripts/release-app.mjs apps/training-studio training-studio-v minor",
|
|
"release:training-studio:major": "node scripts/release-app.mjs apps/training-studio training-studio-v major",
|
|
"yolo": "pnpm run release",
|
|
"seed:scanner-policies": "tsx --env-file=.env scripts/seed-scanner-policies.ts",
|
|
"prebuild": "pnpm build:workers",
|
|
"build": "next build",
|
|
"build:dev": "pnpm build:workers && cross-env NODE_OPTIONS=\"--max_old_space_size=16384\" next build",
|
|
"build:analyze": "cross-env NODE_OPTIONS=\"--max_old_space_size=16384\" ANALYZE=true next build",
|
|
"size": "node scripts/bundle-budget.mjs",
|
|
"deploy": "pnpm run build && pnpm run db:deploy",
|
|
"postinstall": "pnpm run db:generate",
|
|
"typecheck": "node scripts/typecheck.mjs",
|
|
"lint": "eslint src/ --cache --cache-strategy metadata",
|
|
"lint:packages": "eslint packages --ext .ts",
|
|
"eslint": "cross-env TIMING=1 eslint src/ --quiet --cache --cache-strategy metadata",
|
|
"prettier:check": "node scripts/prettier-changed.mjs check",
|
|
"prettier:write": "node scripts/prettier-changed.mjs write",
|
|
"db:ui": "prisma studio",
|
|
"db:pull": "prisma db pull",
|
|
"db:push": "prisma db push",
|
|
"db:migrate": "node scripts/prisma-migrate-with-views-workaround.mjs",
|
|
"db:migrate:empty": "node scripts/create-empty-migration.mjs",
|
|
"db:applied": "node scripts/prisma-mark-migration-applied.mjs",
|
|
"db:deploy": "node scripts/prisma-migrate-with-views-workaround.mjs -p && npm run db:program",
|
|
"db:program": "node scripts/prisma-prepare-programmability.mjs",
|
|
"db:generate": "node scripts/generate-slim-schema.js && prisma generate --no-hints",
|
|
"db:check-generated": "pnpm run db:generate && git diff --exit-code -- packages/civitai-db-schema/src",
|
|
"db:seed": "prisma db seed",
|
|
"db:moderator:pull": "prisma db pull --schema apps/moderator/prisma/schema.prisma",
|
|
"db:moderator:generate": "prisma generate --no-hints --schema apps/moderator/prisma/schema.prisma",
|
|
"share": "ngrok http 3000",
|
|
"prepare": "husky",
|
|
"analyze": "cross-env ANALYZE=true next build",
|
|
"analyze:server": "cross-env BUNDLE_ANALYZE=server next build",
|
|
"analyze:browser": "cross-env BUNDLE_ANALYZE=browser next build",
|
|
"tsc:trace": "cross-env NODE_OPTIONS=\"--max_old_space_size=8192\" tsc --generateTrace ./trace --incremental false",
|
|
"tsc:analyze": "npx analyze-trace trace",
|
|
"test": "cross-env NODE_ENV=development npx playwright test",
|
|
"test:ui": "cross-env NODE_ENV=development npx playwright test --ui",
|
|
"test:gen": "cross-env NODE_ENV=development npx playwright codegen",
|
|
"test:reset": "make bootstrap-db",
|
|
"test:unit": "vitest --project 'unit*'",
|
|
"test:unit:run": "node scripts/test-unit-run.mjs",
|
|
"test:unit:coverage": "vitest run --project 'unit*' --coverage",
|
|
"test:packages": "vitest --project '@civitai/*'",
|
|
"test:packages:run": "vitest run --project '@civitai/*'",
|
|
"test:apps": "vitest --project 'app:*'",
|
|
"test:apps:run": "vitest run --project 'app:*'",
|
|
"test:lint-rules": "vitest run --project 'unit*' src/server/notifications/__tests__/notification-settings-polarity.test.ts src/server/schema/__tests__/track.addView.schema.test.ts src/server/services/__tests__/hub-filter-parity.test.ts src/server/services/__tests__/poi-checks-strip-benign-phrases.test.ts src/server/services/__tests__/video-leaderboard-badge-staging.test.ts src/server/services/__tests__/no-agent-ground-truth-write.test.ts src/server/services/__tests__/no-coerce-boolean-in-api.test.ts src/server/services/__tests__/no-direct-shared-module-mock.test.ts src/server/services/__tests__/no-divergent-active-sales-cap.test.ts src/server/services/__tests__/no-divergent-author-fee-base.test.ts src/server/services/__tests__/no-divergent-can-generate-derivation.test.ts src/server/services/__tests__/no-divergent-model-recency-derivation.test.ts src/server/services/__tests__/no-divergent-generation-submit-payload.test.ts src/server/services/__tests__/no-divergent-paid-gate-derivation.test.ts src/server/services/__tests__/no-divergent-safetensor-rule.test.ts src/server/services/__tests__/no-doubled-free-slot-noun.test.ts src/server/services/__tests__/no-hand-typed-redis-key-constants.test.ts src/server/services/__tests__/no-io-in-transaction.test.ts src/server/services/__tests__/no-job-kind-on-remix-mint.test.ts src/server/services/__tests__/no-lint-rules-script-drift.test.ts src/server/services/__tests__/no-menu-target-tooltip-nesting.test.ts src/server/services/__tests__/no-module-scope-cache.test.ts src/server/services/__tests__/no-pk-addressed-engagement-write.test.ts src/server/services/__tests__/no-server-infra-in-app-graph.test.ts src/server/services/__tests__/no-sharp-outside-native-project.test.ts src/server/services/__tests__/no-ssr-divergent-media-query.test.ts src/server/services/__tests__/no-stale-moderator-route-probe.test.ts src/server/services/__tests__/no-static-html2canvas-import.test.ts src/server/services/__tests__/no-unbounded-paging-fake.test.ts src/server/services/__tests__/no-unbumped-draft-status-write.test.ts src/server/services/__tests__/no-unfiltered-reaction-metric-sum.test.ts src/server/services/__tests__/no-unguarded-billable-submit.test.ts src/server/services/__tests__/no-unguarded-block-bridge-token.test.ts src/server/services/__tests__/no-unguarded-block-rest-token.test.ts src/server/services/__tests__/no-unguarded-user-text.test.ts src/server/services/__tests__/no-unhydrated-home-block-reactions.test.ts src/server/services/__tests__/no-unloadable-image-fixture.test.ts src/server/services/__tests__/no-unmoderated-blob-retraction.test.ts src/server/services/__tests__/no-unmuteable-comment-processor.test.ts src/server/services/__tests__/no-unpriced-default-model.test.ts src/server/services/__tests__/no-unroled-image-resource-match.test.ts src/server/services/__tests__/no-unscoped-email-verification-exemption.test.ts src/server/services/__tests__/no-untruthy-query-gate.test.ts src/server/services/__tests__/no-unverified-provenance-write.test.ts src/server/services/__tests__/no-unwrapped-knob-rotation.test.ts src/server/services/__tests__/no-wholesale-module-mock.test.ts",
|
|
"test:component": "node scripts/test-component-run.mjs",
|
|
"test:component:watch": "vitest --project component",
|
|
"test:geometry": "vitest run --project geometry",
|
|
"test:geometry:watch": "vitest --project geometry",
|
|
"meilisearch:migrate": "NODE_ENV=development tsx scripts/oneoffs/meilisearch-migration.ts",
|
|
"tsscript": "NODE_ENV=development tsx",
|
|
"madge:orphans": "madge --orphans --image ./public/orphans-graph.svg --ts-config ./tsconfig.json --extensions ts,tsx src/",
|
|
"depcheck": "depcheck",
|
|
"generate-types": "typed-scss-modules src",
|
|
"ts-script": "NODE_ENV=development tsx",
|
|
"generate:moderator-endpoints": "node scripts/generate-moderator-endpoint-catalog.mjs"
|
|
},
|
|
"prisma": {
|
|
"schema": "packages/civitai-db-schema/prisma/schema.prisma",
|
|
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} packages/civitai-db-schema/prisma/seed.ts"
|
|
},
|
|
"dependencies": {
|
|
"@aws-sdk/client-s3": "^3.490.0",
|
|
"@aws-sdk/lib-storage": "^3.490.0",
|
|
"@aws-sdk/s3-request-presigner": "^3.490.0",
|
|
"@axiomhq/axiom-node": "^0.12.0",
|
|
"@civitai/app-sdk": "^0.14.0",
|
|
"@civitai/auth": "workspace:*",
|
|
"@civitai/buzz": "workspace:*",
|
|
"@civitai/client": "0.2.0-beta.98",
|
|
"@civitai/cybertipline-tools": "^0.1.0",
|
|
"@civitai/db-queries": "workspace:*",
|
|
"@civitai/db-schema": "workspace:*",
|
|
"@civitai/flipt": "workspace:*",
|
|
"@civitai/generation-metadata": "^0.3.0",
|
|
"@civitai/moderation": "workspace:*",
|
|
"@civitai/next-axiom": "^0.17.0",
|
|
"@civitai/orchestration-client": "0.2.0-beta.106",
|
|
"@civitai/shared": "workspace:*",
|
|
"@clavata/sdk": "^0.2.3",
|
|
"@clickhouse/client": "^1.23.1",
|
|
"@coinbase/cdp-sdk": "^1.13.0",
|
|
"@discordjs/rest": "^2.6.0",
|
|
"@dnd-kit/core": "^6.1.0",
|
|
"@dnd-kit/sortable": "^8.0.0",
|
|
"@dnd-kit/utilities": "^3.2.2",
|
|
"@emotion/react": "^11.10.4",
|
|
"@essentials/one-key-map": "^1.2.0",
|
|
"@flipt-io/flipt-client-js": "^0.2.0",
|
|
"@floating-ui/dom": "^1.6.0",
|
|
"@google-cloud/recaptcha-enterprise": "^5.1.1",
|
|
"@grafana/faro-web-sdk": "2.8.2",
|
|
"@grafana/faro-web-tracing": "2.8.2",
|
|
"@headlessui/react": "2.2",
|
|
"@hookform/resolvers": "^5.1.1",
|
|
"@mantine/core": "^7.17.7",
|
|
"@mantine/dates": "^7.17.7",
|
|
"@mantine/dropzone": "^7.17.7",
|
|
"@mantine/hooks": "^7.17.7",
|
|
"@mantine/modals": "^7.17.7",
|
|
"@mantine/notifications": "^7.17.7",
|
|
"@mantine/nprogress": "^7.17.7",
|
|
"@mantine/tiptap": "^7.17.7",
|
|
"@marsidev/react-turnstile": "^1.0.1",
|
|
"@meilisearch/instant-meilisearch": "0.13.5",
|
|
"@microsoft/signalr": "^7.0.10",
|
|
"@next/bundle-analyzer": "^16.3.0",
|
|
"@next/third-parties": "^15.0.3",
|
|
"@node-oauth/oauth2-server": "^5.3.0",
|
|
"@number-flow/react": "^0.5.7",
|
|
"@okikio/sharedworker": "^1.1.0",
|
|
"@openrouter/sdk": "^0.5.1",
|
|
"@opentelemetry/api": "^1.9.0",
|
|
"@opentelemetry/api-logs": "^0.219.0",
|
|
"@opentelemetry/core": "2.9.0",
|
|
"@opentelemetry/exporter-logs-otlp-proto": "^0.219.0",
|
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.219.0",
|
|
"@opentelemetry/instrumentation": "0.219.0",
|
|
"@opentelemetry/instrumentation-http": "^0.213.0",
|
|
"@opentelemetry/instrumentation-redis": "^0.61.0",
|
|
"@opentelemetry/resources": "2.9.0",
|
|
"@opentelemetry/sdk-logs": "^0.219.0",
|
|
"@opentelemetry/sdk-node": "^0.219.0",
|
|
"@opentelemetry/sdk-trace-node": "^2.5.0",
|
|
"@opentelemetry/sdk-trace-web": "2.9.0",
|
|
"@opentelemetry/semantic-conventions": "^1.39.0",
|
|
"@paddle/paddle-js": "^1.2.1",
|
|
"@paddle/paddle-node-sdk": "^1.4.1",
|
|
"@paypal/react-paypal-js": "^8.1.3",
|
|
"@prisma/client": "^6.3.0",
|
|
"@prisma/instrumentation": "^7.4.2",
|
|
"@pyroscope/nodejs": "0.6.2",
|
|
"@react-hook/window-size": "^3.1.1",
|
|
"@react-pdf/renderer": "^3.3.8",
|
|
"@stripe/react-stripe-js": "^2.4.0",
|
|
"@stripe/stripe-js": "^2.2.0",
|
|
"@tabler/icons-react": "^3.7.0",
|
|
"@tanstack/react-query": "^5.101.0",
|
|
"@tanstack/react-query-devtools": "^5.101.0",
|
|
"@tanstack/react-virtual": "^3.13.12",
|
|
"@tiptap/core": "3.16.0",
|
|
"@tiptap/extension-color": "3.16.0",
|
|
"@tiptap/extension-heading": "3.16.0",
|
|
"@tiptap/extension-image": "3.16.0",
|
|
"@tiptap/extension-link": "3.16.0",
|
|
"@tiptap/extension-mention": "3.16.0",
|
|
"@tiptap/extension-placeholder": "3.16.0",
|
|
"@tiptap/extension-text": "3.16.0",
|
|
"@tiptap/extension-text-style": "3.16.0",
|
|
"@tiptap/extension-underline": "3.16.0",
|
|
"@tiptap/extension-youtube": "3.16.0",
|
|
"@tiptap/extensions": "3.16.0",
|
|
"@tiptap/html": "3.16.0",
|
|
"@tiptap/pm": "3.16.0",
|
|
"@tiptap/react": "3.16.0",
|
|
"@tiptap/starter-kit": "3.16.0",
|
|
"@tiptap/static-renderer": "3.16.0",
|
|
"@tiptap/suggestion": "3.16.0",
|
|
"@trpc/client": "^11.17.0",
|
|
"@trpc/next": "^11.17.0",
|
|
"@trpc/react-query": "^11.17.0",
|
|
"@trpc/server": "^11.17.0",
|
|
"@types/stream-to-blob": "^2.0.0",
|
|
"@typescript/analyze-trace": "^0.10.1",
|
|
"algoliasearch": "^4.23.3",
|
|
"archiver": "^6.0.1",
|
|
"blurhash": "^2.0.4",
|
|
"chalk": "^5.2.0",
|
|
"chart.js": "^4.4.0",
|
|
"chartjs-adapter-dayjs-4": "^1.0.4",
|
|
"circular-dependency-plugin": "^5.2.2",
|
|
"cloudflare": "^2.9.1",
|
|
"clsx": "^2.1.1",
|
|
"compromise": "^14.14.4",
|
|
"cookies-next": "^2.1.1",
|
|
"dayjs": "^1.11.12",
|
|
"decimal.js": "^10.5.0",
|
|
"devalue": "5.8.1",
|
|
"diff": "4.0.2",
|
|
"discord-api-types": "^0.38.37",
|
|
"discord.js": "^14.7.1",
|
|
"dotenv": "^16.4.5",
|
|
"draft-js": "^0.11.7",
|
|
"embla-carousel": "^8.6.0",
|
|
"embla-carousel-autoplay": "^8.5.2",
|
|
"embla-carousel-react": "^8.5.2",
|
|
"exceljs": "^4.4.0",
|
|
"exifreader": "^4.39.0",
|
|
"fastest-levenshtein": "^1.0.16",
|
|
"file-saver": "^2.0.5",
|
|
"form-graph": "^0.4.2",
|
|
"google-auth-library": "^9.15.0",
|
|
"googleapis": "^144.0.0",
|
|
"gray-matter": "^4.0.3",
|
|
"happy-dom": "^20.0.2",
|
|
"he": "^1.2.0",
|
|
"html-to-text": "^9.0.5",
|
|
"html2canvas-pro": "2.3.8",
|
|
"htmlparser2": "8.0.2",
|
|
"idb-keyval": "^6.2.0",
|
|
"immer": "^9.0.15",
|
|
"instantsearch.js": "4.64.1",
|
|
"jose": "^6.0.11",
|
|
"js-yaml": "^4.1.1",
|
|
"jsonwebtoken": "^9.0.1",
|
|
"jssha": "^3.3.1",
|
|
"jszip": "^3.10.1",
|
|
"konva": "^10.0.12",
|
|
"linkify-react": "^4.1.3",
|
|
"linkifyjs": "^4.1.3",
|
|
"lodash-es": "^4.17.21",
|
|
"lottie-react": "^2.4.1",
|
|
"lru-cache": "^11.2.2",
|
|
"mantine-react-table": "^2.0.0-beta.9",
|
|
"masonic": "^3.7.0",
|
|
"meilisearch": "0.33.0",
|
|
"motion": "^11.11.17",
|
|
"msgpackr": "^1.10.2",
|
|
"next": "^16.3.1",
|
|
"nodemailer": "^6.8.0",
|
|
"obscenity": "^0.4.5",
|
|
"openai": "^4.73.0",
|
|
"p-limit": "^6.2.0",
|
|
"path-to-regexp": "^6.2.1",
|
|
"pg": "^8.11.3",
|
|
"prom-client": "^14.2.0",
|
|
"qrcode.react": "^4.2.0",
|
|
"query-string": "^7.1.1",
|
|
"rand-seed": "^1.0.2",
|
|
"randomstring": "^1.3.0",
|
|
"react": "^18.3.1",
|
|
"react-blurhash": "^0.2.0",
|
|
"react-chartjs-2": "^5.2.0",
|
|
"react-dom": "^18.3.1",
|
|
"react-easy-crop": "^5.4.1",
|
|
"react-highlight-within-textarea": "^3.2.1",
|
|
"react-hook-form": "^7.71.1",
|
|
"react-instantsearch": "7.12.0",
|
|
"react-instantsearch-router-nextjs": "7.12.0",
|
|
"react-intersection-observer": "^9.4.0",
|
|
"react-joyride": "^2.9.3",
|
|
"react-konva": "^18.2.14",
|
|
"react-markdown": "^9.0.1",
|
|
"react-social-media-embed": "^2.5.9",
|
|
"recheck": "^4.5.0",
|
|
"redis": "^5.8.3",
|
|
"rehype-raw": "^7.0.0",
|
|
"rehype-stringify": "^10.0.1",
|
|
"remark-breaks": "^4.0.0",
|
|
"remark-gfm": "^4.0.0",
|
|
"remark-parse": "^11.0.0",
|
|
"remark-rehype": "^11.1.1",
|
|
"request-ip": "^3.3.0",
|
|
"sanitize-html": "2.12.1",
|
|
"sass": "^1.82.0",
|
|
"semver": "^7.6.0",
|
|
"sharp": "^0.32.6",
|
|
"slate": "^0.94.1",
|
|
"slate-history": "^0.93.0",
|
|
"slate-react": "^0.95.0",
|
|
"slugify": "^1.6.5",
|
|
"socket.io-client": "^4.5.4",
|
|
"source-map": "^0.7.4",
|
|
"sqids": "^0.3.0",
|
|
"stacktrace-parser": "^0.1.10",
|
|
"stream-to-blob": "^2.0.1",
|
|
"stripe": "^11.6.0",
|
|
"superjson": "^2.2.6",
|
|
"three": "^0.180.0",
|
|
"trie-memoize": "^1.2.0",
|
|
"unfurl.js": "^6.4.0",
|
|
"unified": "^11.0.5",
|
|
"use-sound": "^5.0.0",
|
|
"uuid": "^9.0.0",
|
|
"viem": "^2.30.6",
|
|
"xml2js": "^0.6.2",
|
|
"yaml": "^2.8.1",
|
|
"zod": "^4.0.17",
|
|
"zustand": "^4.3.7"
|
|
},
|
|
"devDependencies": {
|
|
"@anthropic-ai/claude-agent-sdk": "^0.2.6",
|
|
"@electric-sql/pglite": "^0.4.6",
|
|
"@faker-js/faker": "^9.0.3",
|
|
"@ladle/react": "^5.1.1",
|
|
"@next/eslint-plugin-next": "^15.5.19",
|
|
"@playwright/test": "^1.57.0",
|
|
"@prisma/generator-helper": "^5.22.0",
|
|
"@types/archiver": "^6.0.2",
|
|
"@types/cloudflare": "^2.7.9",
|
|
"@types/diff": "4.0.2",
|
|
"@types/file-saver": "^2.0.7",
|
|
"@types/he": "^1.2.3",
|
|
"@types/html-to-text": "^9.0.4",
|
|
"@types/js-yaml": "^4.0.9",
|
|
"@types/jsonwebtoken": "^9.0.2",
|
|
"@types/lodash-es": "^4.17.7",
|
|
"@types/mailchimp__mailchimp_marketing": "^3.0.12",
|
|
"@types/marked": "^4.0.7",
|
|
"@types/node": "24.13.3",
|
|
"@types/node-os-utils": "^1.3.1",
|
|
"@types/nodemailer": "^6.4.7",
|
|
"@types/offscreencanvas": "^2019.7.3",
|
|
"@types/pg": "^8.11.0",
|
|
"@types/pg-format": "^1.0.5",
|
|
"@types/randomstring": "^1.1.8",
|
|
"@types/react": "18.0.14",
|
|
"@types/react-dom": "18.0.5",
|
|
"@types/request-ip": "^0.0.37",
|
|
"@types/sanitize-html": "^2.6.2",
|
|
"@types/semver": "^7.7.1",
|
|
"@types/sharp": "^0.31.0",
|
|
"@types/three": "^0.180.0",
|
|
"@types/uuid": "^9.0.0",
|
|
"@types/vimeo__player": "^2.18.3",
|
|
"@types/xml2js": "^0.4.14",
|
|
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
|
"@typescript-eslint/parser": "^5.33.0",
|
|
"@vitest/browser": "^4.1.11",
|
|
"@vitest/browser-playwright": "4.1.11",
|
|
"@vitest/coverage-v8": "^4.1.11",
|
|
"autoprefixer": "^10.4.19",
|
|
"cross-env": "^7.0.3",
|
|
"cssnano": "^7.0.1",
|
|
"esbuild": "^0.25.5",
|
|
"eslint": "8.57.1",
|
|
"eslint-config-next": "^15.5.19",
|
|
"eslint-config-prettier": "^8.5.0",
|
|
"eslint-plugin-import": "^2.26.0",
|
|
"eslint-plugin-local-rules": "^3.0.2",
|
|
"eslint-plugin-tailwindcss": "^3.15.1",
|
|
"husky": "^9.1.1",
|
|
"jsdom": "^27.4.0",
|
|
"pg-format": "^1.0.4",
|
|
"playwright": "^1.57.0",
|
|
"postcss": "^8.5.3",
|
|
"postcss-assign-layer": "^0.4.0",
|
|
"postcss-preset-mantine": "^1.17.0",
|
|
"postcss-simple-vars": "^7.0.1",
|
|
"prettier": "^2.8.8",
|
|
"prisma": "^6.3.0",
|
|
"prisma-generator-typescript-interfaces": "^1.6.1",
|
|
"prisma-kysely": "^2.2.0",
|
|
"tailwindcss": "^3.4.3",
|
|
"ts-node": "^10.9.1",
|
|
"tsx": "^4.19.2",
|
|
"turbo": "^2.9.17",
|
|
"typed-scss-modules": "^8.1.1",
|
|
"typescript": "^5.9.2",
|
|
"vitest": "^4.1.11",
|
|
"vitest-browser-react": "^2.2.0",
|
|
"ws": "^8.19.0"
|
|
},
|
|
"ct3aMetadata": {
|
|
"initVersion": "6.2.1"
|
|
},
|
|
"//eslint-config-next": "Stay on major 15. v16 is flat-config-only (peer eslint >=9); extending it from .eslintrc.js makes @eslint/eslintrc reject it and then crash while formatting the error, so lint silently never runs. Pinned below so a `pnpm up` can't walk it forward.",
|
|
"pnpm": {
|
|
"overrides": {
|
|
"eslint-config-next": "15",
|
|
"vite": "6.4.3",
|
|
"protobufjs@7": "^7.5.6",
|
|
"fast-xml-parser": "^5.9.3",
|
|
"@aws-sdk/core>fast-xml-parser": "5.2.5",
|
|
"axios": "^1.16.0",
|
|
"undici@6": "^6.27.0",
|
|
"tar-fs@2": "^2.1.5",
|
|
"tar-fs@3": "^3.1.3",
|
|
"ws@7": "^7.5.11"
|
|
},
|
|
"onlyBuiltDependencies": [
|
|
"@parcel/watcher",
|
|
"@prisma/client",
|
|
"@prisma/engines",
|
|
"bigint-buffer",
|
|
"bufferutil",
|
|
"core-js",
|
|
"esbuild",
|
|
"exifreader",
|
|
"msgpackr-extract",
|
|
"prisma",
|
|
"protobufjs",
|
|
"sharp",
|
|
"unrs-resolver",
|
|
"utf-8-validate"
|
|
],
|
|
"patchedDependencies": {
|
|
"@mantine/hooks": "patches/@mantine__hooks.patch"
|
|
}
|
|
}
|
|
}
|