Listen to and share the music in the Atmosphere. musicsky.up.railway.app/
nextjs atproto music typescript react
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add appview service with Tap consumer, feed API, and web integration

Introduces the appview app with SQLite storage, AT Protocol identity
resolution, Tap firehose consumer, and getFeed XRPC endpoint. Updates
the web app to fetch and display the feed. Adds shared packages/common
for reusable AT Protocol utilities and identity helpers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Maciej Malinowski <did:plc:ix2e4nkbttdtyurtuvxbeqpw>

+4147 -209
+4 -1
.gitignore
··· 12 12 13 13 # production 14 14 build 15 + dist/ 15 16 16 17 # misc 17 18 .DS_Store ··· 34 35 next-env.d.ts 35 36 36 37 # database 37 - app.db* 38 + *.db 39 + *.db-shm 40 + *.db-wal 38 41 39 42 # turbo 40 43 .turbo
+1
.husky/pre-commit
··· 1 1 lint-staged 2 2 pnpm run typecheck 3 + pnpm run test
+1
.lintstagedrc
··· 1 1 { 2 2 "apps/web/**/*.{ts,tsx}": "eslint --config apps/web/eslint.config.mjs --fix", 3 + "apps/appview/**/*.ts": "eslint --config apps/appview/eslint.config.mjs --fix", 3 4 "*": "prettier --ignore-unknown --write" 4 5 }
+30
apps/appview/eslint.config.mjs
··· 1 + import { defineConfig, globalIgnores } from "eslint/config"; 2 + import eslintConfigPrettier from "eslint-config-prettier/flat"; 3 + import js from "@eslint/js"; 4 + import tseslint from "typescript-eslint"; 5 + 6 + const eslintConfig = defineConfig([ 7 + js.configs.recommended, 8 + ...tseslint.configs.recommended, 9 + { 10 + files: ["**/*.ts"], 11 + rules: { 12 + "@typescript-eslint/no-explicit-any": "error", 13 + "@typescript-eslint/no-unused-vars": [ 14 + "error", 15 + { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }, 16 + ], 17 + "@typescript-eslint/consistent-type-imports": [ 18 + "error", 19 + { prefer: "type-imports", fixStyle: "separate-type-imports" }, 20 + ], 21 + "no-console": ["error", { allow: ["error", "warn", "log"] }], 22 + "prefer-const": "error", 23 + "no-var": "error", 24 + }, 25 + }, 26 + globalIgnores(["dist/**", "node_modules/**"]), 27 + eslintConfigPrettier, 28 + ]); 29 + 30 + export default eslintConfig;
+5
apps/appview/knip.json
··· 1 + { 2 + "$schema": "https://unpkg.com/knip@5/schema.json", 3 + "ignoreDependencies": ["common"], 4 + "entry": ["src/**/*.test.ts"] 5 + }
+39
apps/appview/package.json
··· 1 + { 2 + "name": "appview", 3 + "version": "0.0.0", 4 + "private": true, 5 + "type": "module", 6 + "scripts": { 7 + "dev": "tsx watch src/index.ts", 8 + "build": "tsup src/index.ts --format esm --out-dir dist", 9 + "start": "pnpm run migrate && node dist/index.js", 10 + "migrate": "tsx src/scripts/migrate.ts", 11 + "typecheck": "tsc", 12 + "lint": "eslint", 13 + "knip": "knip", 14 + "test": "vitest run", 15 + "test:watch": "vitest --watch" 16 + }, 17 + "dependencies": { 18 + "@atproto/syntax": "^0.3.2", 19 + "@atproto/tap": "^0.1.0", 20 + "better-sqlite3": "^12.6.2", 21 + "common": "workspace:*", 22 + "express": "^5.0.1", 23 + "kysely": "^0.28.11" 24 + }, 25 + "devDependencies": { 26 + "@eslint/js": "^9", 27 + "@types/better-sqlite3": "^7.6.13", 28 + "@types/express": "^5.0.1", 29 + "@types/node": "^20", 30 + "eslint": "^9", 31 + "eslint-config-prettier": "^10", 32 + "knip": "^5.86.0", 33 + "tsup": "^8", 34 + "tsx": "^4.21.0", 35 + "typescript": "^5", 36 + "typescript-eslint": "^8", 37 + "vitest": "^4.1.0" 38 + } 39 + }
+6
apps/appview/src/config.ts
··· 1 + export const config = { 2 + port: parseInt(process.env.PORT ?? "3001"), 3 + dbPath: process.env.DATABASE_PATH ?? "appview.db", 4 + tapUrl: process.env.TAP_URL ?? "http://localhost:2480", 5 + tapAdminPassword: process.env.TAP_ADMIN_PASSWORD, 6 + };
+17
apps/appview/src/db/index.ts
··· 1 + import Database from "better-sqlite3"; 2 + import { Kysely, SqliteDialect } from "kysely"; 3 + import type { DatabaseSchema } from "./schema.js"; 4 + import { config } from "../config.js"; 5 + 6 + let _db: Kysely<DatabaseSchema> | null = null; 7 + 8 + export const getDb = (): Kysely<DatabaseSchema> => { 9 + if (!_db) { 10 + const sqlite = new Database(config.dbPath); 11 + sqlite.pragma("journal_mode = WAL"); 12 + _db = new Kysely<DatabaseSchema>({ 13 + dialect: new SqliteDialect({ database: sqlite }), 14 + }); 15 + } 16 + return _db; 17 + };
+99
apps/appview/src/db/migrations.ts
··· 1 + import { type Kysely, type Migration, Migrator } from "kysely"; 2 + import { getDb } from "./index.js"; 3 + 4 + export const migrations: Record<string, Migration> = { 5 + "001": { 6 + async up(db: Kysely<unknown>) { 7 + await db.schema 8 + .createTable("song") 9 + .addColumn("uri", "text", (col) => col.primaryKey()) 10 + .addColumn("cid", "text", (col) => col.notNull()) 11 + .addColumn("did", "text", (col) => col.notNull()) 12 + .addColumn("rkey", "text", (col) => col.notNull()) 13 + .addColumn("record", "text", (col) => col.notNull()) 14 + .addColumn("indexed_at", "text", (col) => col.notNull()) 15 + .addColumn("created_at", "text", (col) => col.notNull()) 16 + .execute(); 17 + 18 + await db.schema 19 + .createIndex("idx_song_created_at") 20 + .on("song") 21 + .column("created_at") 22 + .execute(); 23 + 24 + await db.schema 25 + .createIndex("idx_song_did") 26 + .on("song") 27 + .column("did") 28 + .execute(); 29 + 30 + await db.schema 31 + .createTable("identity") 32 + .addColumn("did", "text", (col) => col.primaryKey()) 33 + .addColumn("handle", "text", (col) => col.notNull()) 34 + .addColumn("pds", "text", (col) => col.notNull()) 35 + .addColumn("status", "text", (col) => col.notNull().defaultTo("active")) 36 + .addColumn("updated_at", "text", (col) => col.notNull()) 37 + .execute(); 38 + 39 + await db.schema 40 + .createTable("like") 41 + .addColumn("uri", "text", (col) => col.primaryKey()) 42 + .addColumn("did", "text", (col) => col.notNull()) 43 + .addColumn("rkey", "text", (col) => col.notNull()) 44 + .addColumn("subject_uri", "text", (col) => col.notNull()) 45 + .addColumn("created_at", "text", (col) => col.notNull()) 46 + .execute(); 47 + 48 + await db.schema 49 + .createIndex("idx_like_subject") 50 + .on("like") 51 + .column("subject_uri") 52 + .execute(); 53 + 54 + await db.schema 55 + .createIndex("idx_like_did_subject") 56 + .on("like") 57 + .columns(["did", "subject_uri"]) 58 + .execute(); 59 + 60 + await db.schema 61 + .createTable("repost") 62 + .addColumn("uri", "text", (col) => col.primaryKey()) 63 + .addColumn("did", "text", (col) => col.notNull()) 64 + .addColumn("rkey", "text", (col) => col.notNull()) 65 + .addColumn("subject_uri", "text", (col) => col.notNull()) 66 + .addColumn("created_at", "text", (col) => col.notNull()) 67 + .execute(); 68 + 69 + await db.schema 70 + .createIndex("idx_repost_subject") 71 + .on("repost") 72 + .column("subject_uri") 73 + .execute(); 74 + 75 + await db.schema 76 + .createIndex("idx_repost_did_subject") 77 + .on("repost") 78 + .columns(["did", "subject_uri"]) 79 + .execute(); 80 + }, 81 + 82 + async down(db: Kysely<unknown>) { 83 + await db.schema.dropTable("repost").execute(); 84 + await db.schema.dropTable("like").execute(); 85 + await db.schema.dropTable("identity").execute(); 86 + await db.schema.dropTable("song").execute(); 87 + }, 88 + }, 89 + }; 90 + 91 + export function getMigrator() { 92 + const db = getDb(); 93 + return new Migrator({ 94 + db, 95 + provider: { 96 + getMigrations: async () => migrations, 97 + }, 98 + }); 99 + }
+40
apps/appview/src/db/schema.ts
··· 1 + export interface SongTable { 2 + uri: string; 3 + cid: string; 4 + did: string; 5 + rkey: string; 6 + record: string; // JSON-serialized full record 7 + indexed_at: string; 8 + created_at: string; // TID-derived timestamp 9 + } 10 + 11 + export interface IdentityTable { 12 + did: string; 13 + handle: string; 14 + pds: string; 15 + status: string; 16 + updated_at: string; 17 + } 18 + 19 + export interface LikeTable { 20 + uri: string; 21 + did: string; 22 + rkey: string; 23 + subject_uri: string; 24 + created_at: string; 25 + } 26 + 27 + export interface RepostTable { 28 + uri: string; 29 + did: string; 30 + rkey: string; 31 + subject_uri: string; 32 + created_at: string; 33 + } 34 + 35 + export interface DatabaseSchema { 36 + song: SongTable; 37 + identity: IdentityTable; 38 + like: LikeTable; 39 + repost: RepostTable; 40 + }
+165
apps/appview/src/identity/resolver.test.ts
··· 1 + import { describe, it, expect, vi, beforeEach } from "vitest"; 2 + import type { Kysely } from "kysely"; 3 + import type { DatabaseSchema } from "../db/schema.js"; 4 + import { createIdentityResolver } from "./resolver.js"; 5 + import { createTestDb } from "../tests/helpers/db.js"; 6 + 7 + // Mock the common package's network functions 8 + vi.mock("common", () => ({ 9 + getPds: vi.fn(), 10 + getHandleFromDid: vi.fn(), 11 + })); 12 + 13 + import { getPds, getHandleFromDid } from "common"; 14 + 15 + const mockGetPds = vi.mocked(getPds); 16 + const mockGetHandleFromDid = vi.mocked(getHandleFromDid); 17 + 18 + describe("IdentityResolver", () => { 19 + let db: Kysely<DatabaseSchema>; 20 + 21 + beforeEach(async () => { 22 + db = await createTestDb(); 23 + vi.clearAllMocks(); 24 + }); 25 + 26 + describe("resolve", () => { 27 + it("resolves from network on cache miss and persists to DB", async () => { 28 + mockGetPds.mockResolvedValue("https://pds.example.com"); 29 + mockGetHandleFromDid.mockResolvedValue("alice.test"); 30 + 31 + const resolver = createIdentityResolver(db); 32 + const result = await resolver.resolve("did:plc:abc"); 33 + 34 + expect(result).toEqual({ 35 + handle: "alice.test", 36 + pds: "https://pds.example.com", 37 + }); 38 + expect(mockGetPds).toHaveBeenCalledWith("did:plc:abc"); 39 + expect(mockGetHandleFromDid).toHaveBeenCalledWith( 40 + "did:plc:abc", 41 + "https://pds.example.com", 42 + ); 43 + 44 + // Verify persisted to DB 45 + const row = await db 46 + .selectFrom("identity") 47 + .selectAll() 48 + .where("did", "=", "did:plc:abc") 49 + .executeTakeFirst(); 50 + expect(row?.handle).toBe("alice.test"); 51 + expect(row?.pds).toBe("https://pds.example.com"); 52 + }); 53 + 54 + it("returns cached identity without calling network", async () => { 55 + // Seed the DB 56 + await db 57 + .insertInto("identity") 58 + .values({ 59 + did: "did:plc:cached", 60 + handle: "bob.test", 61 + pds: "https://pds.cached.com", 62 + status: "active", 63 + updated_at: new Date().toISOString(), 64 + }) 65 + .execute(); 66 + 67 + const resolver = createIdentityResolver(db); 68 + const result = await resolver.resolve("did:plc:cached"); 69 + 70 + expect(result).toEqual({ 71 + handle: "bob.test", 72 + pds: "https://pds.cached.com", 73 + }); 74 + expect(mockGetPds).not.toHaveBeenCalled(); 75 + expect(mockGetHandleFromDid).not.toHaveBeenCalled(); 76 + }); 77 + 78 + it("returns null when PDS cannot be resolved", async () => { 79 + mockGetPds.mockResolvedValue(null); 80 + 81 + const resolver = createIdentityResolver(db); 82 + const result = await resolver.resolve("did:plc:unknown"); 83 + 84 + expect(result).toBeNull(); 85 + }); 86 + }); 87 + 88 + describe("resolvePds", () => { 89 + it("throws when PDS cannot be resolved", async () => { 90 + mockGetPds.mockResolvedValue(null); 91 + 92 + const resolver = createIdentityResolver(db); 93 + 94 + await expect(resolver.resolvePds("did:plc:unknown")).rejects.toThrow( 95 + "Could not resolve PDS for did:plc:unknown", 96 + ); 97 + }); 98 + 99 + it("returns cached PDS without network call", async () => { 100 + await db 101 + .insertInto("identity") 102 + .values({ 103 + did: "did:plc:cached", 104 + handle: "bob.test", 105 + pds: "https://pds.cached.com", 106 + status: "active", 107 + updated_at: new Date().toISOString(), 108 + }) 109 + .execute(); 110 + 111 + const resolver = createIdentityResolver(db); 112 + const pds = await resolver.resolvePds("did:plc:cached"); 113 + 114 + expect(pds).toBe("https://pds.cached.com"); 115 + expect(mockGetPds).not.toHaveBeenCalled(); 116 + }); 117 + }); 118 + 119 + describe("upsertFromEvent", () => { 120 + it("does not clobber existing PDS", async () => { 121 + // Seed with a fully resolved identity 122 + await db 123 + .insertInto("identity") 124 + .values({ 125 + did: "did:plc:full", 126 + handle: "alice.test", 127 + pds: "https://pds.example.com", 128 + status: "active", 129 + updated_at: new Date().toISOString(), 130 + }) 131 + .execute(); 132 + 133 + const resolver = createIdentityResolver(db); 134 + await resolver.upsertFromEvent( 135 + "did:plc:full", 136 + "alice-new.test", 137 + "active", 138 + ); 139 + 140 + const row = await db 141 + .selectFrom("identity") 142 + .selectAll() 143 + .where("did", "=", "did:plc:full") 144 + .executeTakeFirst(); 145 + 146 + expect(row?.handle).toBe("alice-new.test"); 147 + expect(row?.pds).toBe("https://pds.example.com"); // PDS preserved 148 + }); 149 + 150 + it("inserts new identity from event", async () => { 151 + const resolver = createIdentityResolver(db); 152 + await resolver.upsertFromEvent("did:plc:new", "newuser.test", "active"); 153 + 154 + const row = await db 155 + .selectFrom("identity") 156 + .selectAll() 157 + .where("did", "=", "did:plc:new") 158 + .executeTakeFirst(); 159 + 160 + expect(row?.handle).toBe("newuser.test"); 161 + expect(row?.pds).toBe(""); // No PDS from TAP event 162 + expect(row?.status).toBe("active"); 163 + }); 164 + }); 165 + });
+108
apps/appview/src/identity/resolver.ts
··· 1 + import type { Kysely } from "kysely"; 2 + import type { DatabaseSchema } from "../db/schema.js"; 3 + import { getPds, getHandleFromDid } from "common"; 4 + 5 + export interface ResolvedIdentity { 6 + handle: string; 7 + pds: string; 8 + } 9 + 10 + export interface IdentityResolver { 11 + resolve(did: string): Promise<ResolvedIdentity | null>; 12 + resolvePds(did: string): Promise<string>; 13 + upsertFromEvent(did: string, handle: string, status: string): Promise<void>; 14 + } 15 + 16 + export function createIdentityResolver( 17 + db: Kysely<DatabaseSchema>, 18 + ): IdentityResolver { 19 + async function resolve(did: string): Promise<ResolvedIdentity | null> { 20 + const existing = await db 21 + .selectFrom("identity") 22 + .select(["handle", "pds"]) 23 + .where("did", "=", did) 24 + .executeTakeFirst(); 25 + 26 + if (existing?.pds) return existing; 27 + 28 + const pds = await getPds(did); 29 + if (!pds) return null; 30 + 31 + const handle = await getHandleFromDid(did, pds); 32 + 33 + await db 34 + .insertInto("identity") 35 + .values({ 36 + did, 37 + handle, 38 + pds, 39 + status: "active", 40 + updated_at: new Date().toISOString(), 41 + }) 42 + .onConflict((oc) => 43 + oc 44 + .column("did") 45 + .doUpdateSet({ handle, pds, updated_at: new Date().toISOString() }), 46 + ) 47 + .execute(); 48 + 49 + return { handle, pds }; 50 + } 51 + 52 + async function resolvePds(did: string): Promise<string> { 53 + const existing = await db 54 + .selectFrom("identity") 55 + .select("pds") 56 + .where("did", "=", did) 57 + .executeTakeFirst(); 58 + 59 + if (existing?.pds) return existing.pds; 60 + 61 + const pds = await getPds(did); 62 + if (!pds) throw new Error(`Could not resolve PDS for ${did}`); 63 + 64 + await db 65 + .insertInto("identity") 66 + .values({ 67 + did, 68 + handle: did, 69 + pds, 70 + status: "active", 71 + updated_at: new Date().toISOString(), 72 + }) 73 + .onConflict((oc) => 74 + oc 75 + .column("did") 76 + .doUpdateSet({ pds, updated_at: new Date().toISOString() }), 77 + ) 78 + .execute(); 79 + 80 + return pds; 81 + } 82 + 83 + async function upsertFromEvent( 84 + did: string, 85 + handle: string, 86 + status: string, 87 + ): Promise<void> { 88 + await db 89 + .insertInto("identity") 90 + .values({ 91 + did, 92 + handle, 93 + pds: "", 94 + status, 95 + updated_at: new Date().toISOString(), 96 + }) 97 + .onConflict((oc) => 98 + oc.column("did").doUpdateSet({ 99 + handle, 100 + status, 101 + updated_at: new Date().toISOString(), 102 + }), 103 + ) 104 + .execute(); 105 + } 106 + 107 + return { resolve, resolvePds, upsertFromEvent }; 108 + }
+49
apps/appview/src/index.ts
··· 1 + import express from "express"; 2 + import { getMigrator } from "./db/migrations.js"; 3 + import { getDb } from "./db/index.js"; 4 + import { createIdentityResolver } from "./identity/resolver.js"; 5 + import { createTapConsumer } from "./tap/consumer.js"; 6 + import { registerRoutes } from "./routes/index.js"; 7 + import { config } from "./config.js"; 8 + 9 + async function main() { 10 + // Run migrations 11 + const migrator = getMigrator(); 12 + const { error, results } = await migrator.migrateToLatest(); 13 + results?.forEach((it) => { 14 + if (it.status === "Success") { 15 + console.log(`Migration "${it.migrationName}" executed successfully`); 16 + } else if (it.status === "Error") { 17 + console.error(`Failed to execute migration "${it.migrationName}"`); 18 + } 19 + }); 20 + if (error) { 21 + console.error("Migration failed:", error); 22 + process.exit(1); 23 + } 24 + 25 + const db = getDb(); 26 + const resolver = createIdentityResolver(db); 27 + 28 + // Start Tap consumer 29 + createTapConsumer({ 30 + db, 31 + resolver, 32 + tapUrl: config.tapUrl, 33 + tapAdminPassword: config.tapAdminPassword, 34 + }).start(); 35 + 36 + // Start Express server 37 + const app = express(); 38 + app.use(express.json()); 39 + registerRoutes(app, resolver); 40 + 41 + app.listen(config.port, () => { 42 + console.log(`AppView listening on port ${config.port}`); 43 + }); 44 + } 45 + 46 + main().catch((err) => { 47 + console.error("Fatal error:", err); 48 + process.exit(1); 49 + });
+63
apps/appview/src/routes/blob.ts
··· 1 + import type { Request, Response } from "express"; 2 + import type { IdentityResolver } from "../identity/resolver.js"; 3 + 4 + export function createBlobHandler(resolver: IdentityResolver) { 5 + return async function blobHandler( 6 + req: Request, 7 + res: Response, 8 + ): Promise<void> { 9 + const { did, cid } = req.params as { did: string; cid: string }; 10 + 11 + if (!did || !cid) { 12 + res.status(400).json({ error: "Missing did or cid" }); 13 + return; 14 + } 15 + 16 + let pds: string; 17 + try { 18 + pds = await resolver.resolvePds(did); 19 + } catch { 20 + res.status(404).json({ error: "Could not resolve PDS for DID" }); 21 + return; 22 + } 23 + 24 + const blobUrl = `${pds}/xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent(did)}&cid=${encodeURIComponent(cid)}`; 25 + 26 + try { 27 + const upstream = await fetch(blobUrl); 28 + 29 + if (!upstream.ok) { 30 + res.status(upstream.status).json({ error: "Blob not found" }); 31 + return; 32 + } 33 + 34 + const contentType = upstream.headers.get("content-type"); 35 + if (contentType) { 36 + res.setHeader("Content-Type", contentType); 37 + } 38 + res.setHeader("Cache-Control", "public, max-age=31536000, immutable"); 39 + 40 + const body = upstream.body; 41 + if (!body) { 42 + res.status(502).json({ error: "Empty response from PDS" }); 43 + return; 44 + } 45 + 46 + // Stream the response 47 + const reader = body.getReader(); 48 + const pump = async (): Promise<void> => { 49 + const { done, value } = await reader.read(); 50 + if (done) { 51 + res.end(); 52 + return; 53 + } 54 + res.write(value); 55 + return pump(); 56 + }; 57 + await pump(); 58 + } catch (err) { 59 + console.error("Blob proxy error:", err); 60 + res.status(502).json({ error: "Failed to fetch blob from PDS" }); 61 + } 62 + }; 63 + }
+137
apps/appview/src/routes/feed.ts
··· 1 + import type { Request, Response } from "express"; 2 + import { getDb } from "../db/index.js"; 3 + import type { FeedOutput, SongView } from "../types/feed.js"; 4 + 5 + const DEFAULT_LIMIT = 50; 6 + const MAX_LIMIT = 100; 7 + 8 + export async function getFeedHandler( 9 + req: Request, 10 + res: Response, 11 + ): Promise<void> { 12 + const limit = Math.min( 13 + parseInt(req.query["limit"] as string) || DEFAULT_LIMIT, 14 + MAX_LIMIT, 15 + ); 16 + const cursor = req.query["cursor"] as string | undefined; 17 + const viewer = req.query["viewer"] as string | undefined; 18 + 19 + const db = getDb(); 20 + 21 + let query = db 22 + .selectFrom("song as s") 23 + .innerJoin("identity as i", "i.did", "s.did") 24 + .select([ 25 + "s.uri", 26 + "s.cid", 27 + "s.did", 28 + "s.rkey", 29 + "s.record", 30 + "s.created_at", 31 + "s.indexed_at", 32 + "i.handle", 33 + "i.pds", 34 + ]); 35 + 36 + if (cursor) { 37 + const [cursorTs, cursorUri] = cursor.split("::"); 38 + if (cursorTs && cursorUri) { 39 + query = query.where((eb) => 40 + eb.or([ 41 + eb("s.created_at", "<", cursorTs), 42 + eb.and([ 43 + eb("s.created_at", "=", cursorTs), 44 + eb("s.uri", "<", cursorUri), 45 + ]), 46 + ]), 47 + ); 48 + } 49 + } 50 + 51 + const rows = await query 52 + .orderBy("s.created_at", "desc") 53 + .orderBy("s.uri", "desc") 54 + .limit(limit) 55 + .execute(); 56 + 57 + if (rows.length === 0) { 58 + res.json({ songs: [] } satisfies FeedOutput); 59 + return; 60 + } 61 + 62 + const uris = rows.map((r) => r.uri); 63 + 64 + const viewerLikes = new Map<string, string>(); 65 + const viewerReposts = new Map<string, string>(); 66 + 67 + if (viewer) { 68 + const [likes, reposts] = await Promise.all([ 69 + db 70 + .selectFrom("like") 71 + .select(["uri", "subject_uri"]) 72 + .where("did", "=", viewer) 73 + .where("subject_uri", "in", uris) 74 + .execute(), 75 + db 76 + .selectFrom("repost") 77 + .select(["uri", "subject_uri"]) 78 + .where("did", "=", viewer) 79 + .where("subject_uri", "in", uris) 80 + .execute(), 81 + ]); 82 + for (const l of likes) viewerLikes.set(l.subject_uri, l.uri); 83 + for (const r of reposts) viewerReposts.set(r.subject_uri, r.uri); 84 + } 85 + 86 + const [likeCounts, repostCounts] = await Promise.all([ 87 + db 88 + .selectFrom("like") 89 + .select(["subject_uri"]) 90 + .select((eb) => eb.fn.count<number>("uri").as("count")) 91 + .where("subject_uri", "in", uris) 92 + .groupBy("subject_uri") 93 + .execute(), 94 + db 95 + .selectFrom("repost") 96 + .select(["subject_uri"]) 97 + .select((eb) => eb.fn.count<number>("uri").as("count")) 98 + .where("subject_uri", "in", uris) 99 + .groupBy("subject_uri") 100 + .execute(), 101 + ]); 102 + 103 + const likeCountMap = new Map( 104 + likeCounts.map((r) => [r.subject_uri, Number(r.count)]), 105 + ); 106 + const repostCountMap = new Map( 107 + repostCounts.map((r) => [r.subject_uri, Number(r.count)]), 108 + ); 109 + 110 + const songs: SongView[] = rows.map((row) => ({ 111 + uri: row.uri, 112 + cid: row.cid, 113 + author: { 114 + did: row.did, 115 + handle: row.handle, 116 + pds: row.pds, 117 + }, 118 + record: JSON.parse(row.record) as unknown, 119 + likeCount: likeCountMap.get(row.uri) ?? 0, 120 + repostCount: repostCountMap.get(row.uri) ?? 0, 121 + viewer: viewer 122 + ? { 123 + like: viewerLikes.get(row.uri), 124 + repost: viewerReposts.get(row.uri), 125 + } 126 + : undefined, 127 + indexedAt: row.indexed_at, 128 + createdAt: row.created_at, 129 + })); 130 + 131 + const lastRow = rows[rows.length - 1]; 132 + const nextCursor = lastRow 133 + ? `${lastRow.created_at}::${lastRow.uri}` 134 + : undefined; 135 + 136 + res.json({ cursor: nextCursor, songs } satisfies FeedOutput); 137 + }
+25
apps/appview/src/routes/index.ts
··· 1 + import type { Express } from "express"; 2 + import type { IdentityResolver } from "../identity/resolver.js"; 3 + import { getFeedHandler } from "./feed.js"; 4 + import { createBlobHandler } from "./blob.js"; 5 + 6 + export function registerRoutes(app: Express, resolver: IdentityResolver): void { 7 + app.get("/health", (_req, res) => { 8 + res.json({ status: "ok" }); 9 + }); 10 + 11 + app.get("/xrpc/app.musicsky.temp.getFeed", (req, res) => { 12 + getFeedHandler(req, res).catch((err) => { 13 + console.error("getFeed error:", err); 14 + res.status(500).json({ error: "Internal server error" }); 15 + }); 16 + }); 17 + 18 + const blobHandler = createBlobHandler(resolver); 19 + app.get("/blob/:did/:cid", (req, res) => { 20 + blobHandler(req, res).catch((err) => { 21 + console.error("blob error:", err); 22 + res.status(500).json({ error: "Internal server error" }); 23 + }); 24 + }); 25 + }
+18
apps/appview/src/scripts/migrate.ts
··· 1 + import { getMigrator } from "../db/migrations.js"; 2 + 3 + const migrator = getMigrator(); 4 + const { error, results } = await migrator.migrateToLatest(); 5 + 6 + results?.forEach((it) => { 7 + if (it.status === "Success") { 8 + console.log(`migration "${it.migrationName}" was executed successfully`); 9 + } else if (it.status === "Error") { 10 + console.error(`failed to execute migration "${it.migrationName}"`); 11 + } 12 + }); 13 + 14 + if (error) { 15 + console.error("failed to migrate"); 16 + console.error(error); 17 + process.exit(1); 18 + }
+211
apps/appview/src/tap/consumer.test.ts
··· 1 + import { describe, it, expect, vi, beforeEach } from "vitest"; 2 + import type { Kysely } from "kysely"; 3 + import type { DatabaseSchema } from "../db/schema.js"; 4 + import type { IdentityResolver } from "../identity/resolver.js"; 5 + import { handleSong, handleLike, handleRepost } from "./consumer.js"; 6 + import { createTestDb } from "../tests/helpers/db.js"; 7 + import { COLLECTIONS } from "common"; 8 + 9 + vi.mock("common", async (importOriginal) => { 10 + const actual = (await importOriginal()) as Record<string, unknown>; 11 + return { 12 + ...actual, 13 + getCreatedAtFromRkey: vi.fn(() => "2026-03-22T00:00:00.000Z"), 14 + }; 15 + }); 16 + 17 + function createFakeResolver( 18 + override?: Partial<IdentityResolver>, 19 + ): IdentityResolver { 20 + return { 21 + resolve: vi.fn(async () => ({ 22 + handle: "alice.test", 23 + pds: "https://pds.test", 24 + })), 25 + resolvePds: vi.fn(async () => "https://pds.test"), 26 + upsertFromEvent: vi.fn(async () => {}), 27 + ...override, 28 + }; 29 + } 30 + 31 + describe("handleSong", () => { 32 + let db: Kysely<DatabaseSchema>; 33 + 34 + beforeEach(async () => { 35 + db = await createTestDb(); 36 + }); 37 + 38 + it("inserts a song on create", async () => { 39 + const resolver = createFakeResolver(); 40 + 41 + await handleSong( 42 + { 43 + action: "create", 44 + did: "did:plc:abc", 45 + collection: COLLECTIONS.song, 46 + rkey: "3jui7kd2zcszw", 47 + cid: "bafyreiabc", 48 + record: { title: "Test Song", createdAt: "2026-03-22T00:00:00.000Z" }, 49 + } as never, 50 + db, 51 + resolver, 52 + ); 53 + 54 + const row = await db.selectFrom("song").selectAll().executeTakeFirst(); 55 + expect(row).toBeDefined(); 56 + expect(row?.did).toBe("did:plc:abc"); 57 + expect(row?.cid).toBe("bafyreiabc"); 58 + expect(resolver.resolve).toHaveBeenCalledWith("did:plc:abc"); 59 + }); 60 + 61 + it("deletes a song on delete", async () => { 62 + const resolver = createFakeResolver(); 63 + 64 + // Seed a song 65 + await handleSong( 66 + { 67 + action: "create", 68 + did: "did:plc:abc", 69 + collection: COLLECTIONS.song, 70 + rkey: "3jui7kd2zcszw", 71 + cid: "bafyreiabc", 72 + record: { title: "Test Song" }, 73 + } as never, 74 + db, 75 + resolver, 76 + ); 77 + 78 + // Delete it 79 + await handleSong( 80 + { 81 + action: "delete", 82 + did: "did:plc:abc", 83 + collection: COLLECTIONS.song, 84 + rkey: "3jui7kd2zcszw", 85 + } as never, 86 + db, 87 + resolver, 88 + ); 89 + 90 + const rows = await db.selectFrom("song").selectAll().execute(); 91 + expect(rows).toHaveLength(0); 92 + }); 93 + 94 + it("skips insert when identity cannot be resolved", async () => { 95 + const resolver = createFakeResolver({ 96 + resolve: vi.fn(async () => null), 97 + }); 98 + 99 + await handleSong( 100 + { 101 + action: "create", 102 + did: "did:plc:unknown", 103 + collection: COLLECTIONS.song, 104 + rkey: "3jui7kd2zcszw", 105 + cid: "bafyreiabc", 106 + record: { title: "Test Song" }, 107 + } as never, 108 + db, 109 + resolver, 110 + ); 111 + 112 + const rows = await db.selectFrom("song").selectAll().execute(); 113 + expect(rows).toHaveLength(0); 114 + }); 115 + }); 116 + 117 + describe("handleLike", () => { 118 + let db: Kysely<DatabaseSchema>; 119 + 120 + beforeEach(async () => { 121 + db = await createTestDb(); 122 + }); 123 + 124 + it("inserts a like", async () => { 125 + await handleLike( 126 + { 127 + action: "create", 128 + did: "did:plc:liker", 129 + collection: COLLECTIONS.like, 130 + rkey: "3jui7kd2zcszw", 131 + cid: "bafyreilike", 132 + record: { 133 + subject: { 134 + uri: "at://did:plc:abc/app.musicsky.temp.song/3jui7kd2zcszw", 135 + }, 136 + }, 137 + } as never, 138 + db, 139 + ); 140 + 141 + const row = await db.selectFrom("like").selectAll().executeTakeFirst(); 142 + expect(row).toBeDefined(); 143 + expect(row?.did).toBe("did:plc:liker"); 144 + expect(row?.subject_uri).toBe( 145 + "at://did:plc:abc/app.musicsky.temp.song/3jui7kd2zcszw", 146 + ); 147 + }); 148 + 149 + it("is idempotent — second insert with same URI is ignored", async () => { 150 + const evt = { 151 + action: "create", 152 + did: "did:plc:liker", 153 + collection: COLLECTIONS.like, 154 + rkey: "3jui7kd2zcszw", 155 + cid: "bafyreilike", 156 + record: { 157 + subject: { 158 + uri: "at://did:plc:abc/app.musicsky.temp.song/3jui7kd2zcszw", 159 + }, 160 + }, 161 + } as never; 162 + 163 + await handleLike(evt, db); 164 + await handleLike(evt, db); 165 + 166 + const rows = await db.selectFrom("like").selectAll().execute(); 167 + expect(rows).toHaveLength(1); 168 + }); 169 + }); 170 + 171 + describe("handleRepost", () => { 172 + let db: Kysely<DatabaseSchema>; 173 + 174 + beforeEach(async () => { 175 + db = await createTestDb(); 176 + }); 177 + 178 + it("inserts a repost and deletes it", async () => { 179 + await handleRepost( 180 + { 181 + action: "create", 182 + did: "did:plc:reposter", 183 + collection: COLLECTIONS.repost, 184 + rkey: "3jui7kd2zcszw", 185 + cid: "bafyreirepost", 186 + record: { 187 + subject: { 188 + uri: "at://did:plc:abc/app.musicsky.temp.song/3jui7kd2zcszw", 189 + }, 190 + }, 191 + } as never, 192 + db, 193 + ); 194 + 195 + let rows = await db.selectFrom("repost").selectAll().execute(); 196 + expect(rows).toHaveLength(1); 197 + 198 + await handleRepost( 199 + { 200 + action: "delete", 201 + did: "did:plc:reposter", 202 + collection: COLLECTIONS.repost, 203 + rkey: "3jui7kd2zcszw", 204 + } as never, 205 + db, 206 + ); 207 + 208 + rows = await db.selectFrom("repost").selectAll().execute(); 209 + expect(rows).toHaveLength(0); 210 + }); 211 + });
+164
apps/appview/src/tap/consumer.ts
··· 1 + import { Tap, SimpleIndexer } from "@atproto/tap"; 2 + import type { RecordEvent, IdentityEvent } from "@atproto/tap"; 3 + import { AtUri } from "@atproto/syntax"; 4 + import type { Kysely } from "kysely"; 5 + import type { DatabaseSchema } from "../db/schema.js"; 6 + import type { IdentityResolver } from "../identity/resolver.js"; 7 + import { COLLECTIONS, getCreatedAtFromRkey } from "common"; 8 + 9 + const SONG = COLLECTIONS.song; 10 + const LIKE = COLLECTIONS.like; 11 + const REPOST = COLLECTIONS.repost; 12 + 13 + export async function handleSong( 14 + evt: RecordEvent, 15 + db: Kysely<DatabaseSchema>, 16 + resolver: IdentityResolver, 17 + ): Promise<void> { 18 + const uri = AtUri.make(evt.did, evt.collection, evt.rkey).toString(); 19 + 20 + if (evt.action === "delete") { 21 + await db.deleteFrom("song").where("uri", "=", uri).execute(); 22 + return; 23 + } 24 + 25 + if (!evt.record || !evt.cid) return; 26 + 27 + const identity = await resolver.resolve(evt.did); 28 + if (!identity) { 29 + console.warn( 30 + `Could not resolve identity for ${evt.did}, skipping song ${uri}`, 31 + ); 32 + return; 33 + } 34 + 35 + await db 36 + .insertInto("song") 37 + .values({ 38 + uri, 39 + cid: evt.cid, 40 + did: evt.did, 41 + rkey: evt.rkey, 42 + record: JSON.stringify(evt.record), 43 + indexed_at: new Date().toISOString(), 44 + created_at: getCreatedAtFromRkey(evt.rkey), 45 + }) 46 + .onConflict((oc) => 47 + oc.column("uri").doUpdateSet({ 48 + cid: evt.cid!, 49 + record: JSON.stringify(evt.record), 50 + indexed_at: new Date().toISOString(), 51 + created_at: 52 + (evt.record!["createdAt"] as string) ?? new Date().toISOString(), 53 + }), 54 + ) 55 + .execute(); 56 + } 57 + 58 + export async function handleLike( 59 + evt: RecordEvent, 60 + db: Kysely<DatabaseSchema>, 61 + ): Promise<void> { 62 + const uri = AtUri.make(evt.did, evt.collection, evt.rkey).toString(); 63 + 64 + if (evt.action === "delete") { 65 + await db.deleteFrom("like").where("uri", "=", uri).execute(); 66 + return; 67 + } 68 + 69 + if (!evt.record || !evt.cid) return; 70 + 71 + const subject = evt.record["subject"] as { uri: string } | undefined; 72 + if (!subject?.uri) return; 73 + 74 + await db 75 + .insertInto("like") 76 + .values({ 77 + uri, 78 + did: evt.did, 79 + rkey: evt.rkey, 80 + subject_uri: subject.uri, 81 + created_at: getCreatedAtFromRkey(evt.rkey), 82 + }) 83 + .onConflict((oc) => oc.column("uri").doNothing()) 84 + .execute(); 85 + } 86 + 87 + export async function handleRepost( 88 + evt: RecordEvent, 89 + db: Kysely<DatabaseSchema>, 90 + ): Promise<void> { 91 + const uri = AtUri.make(evt.did, evt.collection, evt.rkey).toString(); 92 + 93 + if (evt.action === "delete") { 94 + await db.deleteFrom("repost").where("uri", "=", uri).execute(); 95 + return; 96 + } 97 + 98 + if (!evt.record || !evt.cid) return; 99 + 100 + const subject = evt.record["subject"] as { uri: string } | undefined; 101 + if (!subject?.uri) return; 102 + 103 + await db 104 + .insertInto("repost") 105 + .values({ 106 + uri, 107 + did: evt.did, 108 + rkey: evt.rkey, 109 + subject_uri: subject.uri, 110 + created_at: getCreatedAtFromRkey(evt.rkey), 111 + }) 112 + .onConflict((oc) => oc.column("uri").doNothing()) 113 + .execute(); 114 + } 115 + 116 + interface TapConsumerDeps { 117 + db: Kysely<DatabaseSchema>; 118 + resolver: IdentityResolver; 119 + tapUrl: string; 120 + tapAdminPassword: string | undefined; 121 + } 122 + 123 + export function createTapConsumer(deps: TapConsumerDeps): { start(): void } { 124 + const { db, resolver, tapUrl, tapAdminPassword } = deps; 125 + 126 + return { 127 + start() { 128 + const tap = new Tap(tapUrl, { adminPassword: tapAdminPassword }); 129 + const indexer = new SimpleIndexer(); 130 + 131 + indexer 132 + .record(async (evt) => { 133 + try { 134 + if (evt.collection === SONG) { 135 + await handleSong(evt, db, resolver); 136 + } else if (evt.collection === LIKE) { 137 + await handleLike(evt, db); 138 + } else if (evt.collection === REPOST) { 139 + await handleRepost(evt, db); 140 + } 141 + } catch (err) { 142 + console.error(`Error handling ${evt.collection} event:`, err); 143 + } 144 + }) 145 + .identity(async (evt: IdentityEvent) => { 146 + try { 147 + await resolver.upsertFromEvent(evt.did, evt.handle, evt.status); 148 + } catch (err) { 149 + console.error("Error handling identity event:", err); 150 + } 151 + }) 152 + .error((err) => { 153 + console.error("Tap consumer error:", err); 154 + }); 155 + 156 + const channel = tap.channel(indexer); 157 + channel.start().catch((err) => { 158 + console.error("Tap channel ended:", err); 159 + }); 160 + 161 + console.log(`Tap consumer started, connecting to ${tapUrl}`); 162 + }, 163 + }; 164 + }
+20
apps/appview/src/tests/helpers/db.ts
··· 1 + import Database from "better-sqlite3"; 2 + import { Kysely, Migrator, SqliteDialect } from "kysely"; 3 + import type { DatabaseSchema } from "../../db/schema.js"; 4 + import { migrations } from "../../db/migrations.js"; 5 + 6 + export async function createTestDb(): Promise<Kysely<DatabaseSchema>> { 7 + const db = new Kysely<DatabaseSchema>({ 8 + dialect: new SqliteDialect({ database: new Database(":memory:") }), 9 + }); 10 + 11 + const migrator = new Migrator({ 12 + db, 13 + provider: { getMigrations: async () => migrations }, 14 + }); 15 + 16 + const { error } = await migrator.migrateToLatest(); 17 + if (error) throw error; 18 + 19 + return db; 20 + }
+27
apps/appview/src/types/feed.ts
··· 1 + export interface AuthorView { 2 + did: string; 3 + handle: string; 4 + pds: string; 5 + } 6 + 7 + export interface ViewerState { 8 + like?: string; 9 + repost?: string; 10 + } 11 + 12 + export interface SongView { 13 + uri: string; 14 + cid: string; 15 + author: AuthorView; 16 + record: unknown; 17 + likeCount?: number; 18 + repostCount?: number; 19 + viewer?: ViewerState; 20 + indexedAt: string; 21 + createdAt: string; 22 + } 23 + 24 + export interface FeedOutput { 25 + cursor?: string; 26 + songs: SongView[]; 27 + }
+17
apps/appview/tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + "target": "ES2022", 4 + "lib": ["ES2022"], 5 + "module": "esnext", 6 + "moduleResolution": "bundler", 7 + "strict": true, 8 + "noEmit": true, 9 + "esModuleInterop": true, 10 + "resolveJsonModule": true, 11 + "verbatimModuleSyntax": true, 12 + "skipLibCheck": true, 13 + "incremental": true 14 + }, 15 + "include": ["src/**/*.ts"], 16 + "exclude": ["node_modules", "dist"] 17 + }
+7
apps/appview/vitest.config.ts
··· 1 + import { defineConfig } from "vitest/config"; 2 + 3 + export default defineConfig({ 4 + test: { 5 + globals: true, 6 + }, 7 + });
+1 -1
apps/web/knip.json
··· 4 4 "ignoreIssues": { 5 5 "src/components/ui/**": ["exports", "types", "classMembers"] 6 6 }, 7 - "ignoreDependencies": ["@knip/mcp"] 7 + "ignoreDependencies": ["@knip/mcp", "common"] 8 8 }
+6
apps/web/next.config.ts
··· 14 14 images: { 15 15 remotePatterns: [ 16 16 { 17 + protocol: "http", 18 + hostname: "127.0.0.1", 19 + port: "3001", 20 + pathname: "/blob/**", 21 + }, 22 + { 17 23 protocol: "https", 18 24 hostname: "cdn.bsky.app", 19 25 port: "",
+1 -1
apps/web/package.json
··· 14 14 "knip": "knip" 15 15 }, 16 16 "dependencies": { 17 + "common": "workspace:*", 17 18 "@atproto/api": "^0.19.0", 18 19 "@atproto/common-web": "^0.4.18", 19 - "@atproto/identity": "^0.4.12", 20 20 "@atproto/lexicon": "^0.6.1", 21 21 "@atproto/oauth-client-node": "^0.3.17", 22 22 "@hookform/resolvers": "^5.2.2",
+123
apps/web/src/app/(main)/feed.tsx
··· 1 + import { Song } from "@/components/song"; 2 + import type { SongProps } from "@/types/song"; 3 + import type { PlayerSong } from "@/stores/player-store"; 4 + import { PlaylistQueueProvider } from "@/components/playlist/playlist-queue-context"; 5 + import { getSession } from "@/lib/auth/session"; 6 + import { APPVIEW_URL } from "@/lib/api"; 7 + import { getRkeyFromUri } from "@/lib/atproto"; 8 + 9 + interface AuthorView { 10 + did: string; 11 + handle: string; 12 + pds: string; 13 + } 14 + 15 + interface ViewerState { 16 + like?: string; 17 + repost?: string; 18 + } 19 + 20 + interface SongView { 21 + uri: string; 22 + cid: string; 23 + author: AuthorView; 24 + record: unknown; 25 + likeCount?: number; 26 + repostCount?: number; 27 + viewer?: ViewerState; 28 + indexedAt: string; 29 + createdAt?: string; 30 + } 31 + 32 + interface FeedOutput { 33 + cursor?: string; 34 + songs: SongView[]; 35 + } 36 + 37 + function getBlobProxyUrl(did: string, ref: unknown): string { 38 + const blobRef = ref as { ref?: { $link?: string }; cid?: string } | null; 39 + const cid = blobRef?.ref?.["$link"] ?? blobRef?.cid; 40 + if (!cid) return ""; 41 + return `${APPVIEW_URL}/blob/${did}/${cid}`; 42 + } 43 + 44 + function songViewToProps( 45 + song: SongView, 46 + sessionDid: string | undefined, 47 + ): SongProps { 48 + const record = song.record as { 49 + title: string; 50 + audio: unknown; 51 + coverArt: unknown; 52 + duration: number; 53 + genre?: string; 54 + description?: string; 55 + }; 56 + 57 + return { 58 + uri: song.uri, 59 + cid: song.cid, 60 + rkey: getRkeyFromUri(song.uri), 61 + title: record.title, 62 + coverArt: getBlobProxyUrl(song.author.did, record.coverArt), 63 + audio: getBlobProxyUrl(song.author.did, record.audio), 64 + duration: record.duration, 65 + genre: record.genre ?? null, 66 + description: record.description ?? null, 67 + author: song.author.handle, 68 + createdAt: song.createdAt ?? song.indexedAt, 69 + isOwner: sessionDid === song.author.did, 70 + loggedIn: sessionDid !== undefined, 71 + likeRkey: song.viewer?.like ? getRkeyFromUri(song.viewer.like) : null, 72 + repostRkey: song.viewer?.repost ? getRkeyFromUri(song.viewer.repost) : null, 73 + }; 74 + } 75 + 76 + async function fetchFeed(viewer?: string): Promise<FeedOutput> { 77 + try { 78 + const params = new URLSearchParams({ limit: "30" }); 79 + if (viewer) params.set("viewer", viewer); 80 + const res = await fetch( 81 + `${APPVIEW_URL}/xrpc/app.musicsky.temp.getFeed?${params.toString()}`, 82 + { next: { revalidate: 60 } }, 83 + ); 84 + if (!res.ok) return { songs: [] }; 85 + return (await res.json()) as FeedOutput; 86 + } catch { 87 + return { songs: [] }; 88 + } 89 + } 90 + 91 + export async function Feed() { 92 + const session = await getSession(); 93 + const feed = await fetchFeed(session?.did); 94 + 95 + if (feed.songs.length === 0) { 96 + return ( 97 + <p className="text-muted-foreground"> 98 + No songs yet. Be the first to upload one! 99 + </p> 100 + ); 101 + } 102 + 103 + const songs = feed.songs.map((song) => songViewToProps(song, session?.did)); 104 + 105 + const queueSongs: PlayerSong[] = songs.map((song) => ({ 106 + uri: song.uri, 107 + cid: song.cid, 108 + rkey: song.rkey, 109 + title: song.title, 110 + coverArt: song.coverArt, 111 + audio: song.audio, 112 + duration: song.duration, 113 + author: song.author, 114 + })); 115 + 116 + return ( 117 + <PlaylistQueueProvider songs={queueSongs}> 118 + {songs.map((song) => ( 119 + <Song key={song.uri} {...song} /> 120 + ))} 121 + </PlaylistQueueProvider> 122 + ); 123 + }
+24 -42
apps/web/src/app/(main)/page.tsx
··· 1 - import { Button } from "@/components/ui/button"; 2 - import { ArrowUpRightIcon } from "lucide-react"; 3 - import Link from "next/link"; 1 + import { Suspense } from "react"; 2 + import { Feed } from "./feed"; 3 + import { Skeleton } from "@/components/ui/skeleton"; 4 + 5 + function FeedSkeleton() { 6 + return ( 7 + <div className="flex flex-col gap-2"> 8 + {Array.from({ length: 5 }).map((_, i) => ( 9 + <div key={i} className="flex flex-row gap-4"> 10 + <Skeleton className="size-16 rounded-md shrink-0" /> 11 + <div className="flex flex-col gap-2 flex-1"> 12 + <Skeleton className="w-48 h-4" /> 13 + <Skeleton className="w-32 h-3" /> 14 + </div> 15 + </div> 16 + ))} 17 + </div> 18 + ); 19 + } 4 20 5 21 export default function Home() { 6 22 return ( 7 - <main className="flex flex-col gap-4 max-w-lg"> 8 - <div className="flex flex-col gap-2"> 9 - <h1 className="text-3xl font-bold text-primary">Hello!</h1> 10 - <h2 className="text-xl"> 11 - This is MusicSky. A place to listen and share the music in the 12 - Atmosphere. 13 - </h2> 14 - </div> 15 - <p>This is a work in progress.</p> 16 - <p> 17 - For now you can log in, upload music and listen to it on your profile 18 - (currently all the profile data is fetched from Bluesky, will have to 19 - implement Musicsky&apos;s own profile data). Listening to other 20 - people&apos;s music by typing out their handle in the URL should work 21 - too. <br /> 22 - <br /> 23 - Below should be a feed of newly uploaded songs, but this requires a 24 - dedicated backend which will be implement in the future once the basic 25 - functionality is there, like liking songs, comments etc. 26 - <br /> 27 - Please check back later for more updates. <br /> 28 - <br /> 29 - Thank you for checking this out! 30 - <br /> 31 - <Link 32 - target={"_blank"} 33 - href="https://bsky.app/profile/did:plc:ix2e4nkbttdtyurtuvxbeqpw" 34 - > 35 - - Maciej 36 - </Link> 37 - </p> 38 - <Button className="w-min" asChild> 39 - <Link 40 - target={"_blank"} 41 - href="https://tangled.org/mejsiejdev.bsky.social/musicsky/" 42 - > 43 - Check out MusicSky repository on Tangled! <ArrowUpRightIcon /> 44 - </Link> 45 - </Button> 23 + <main className="flex flex-col gap-4"> 24 + <h1 className="text-xl font-bold text-primary">Latest Songs</h1> 25 + <Suspense fallback={<FeedSkeleton />}> 26 + <Feed /> 27 + </Suspense> 46 28 </main> 47 29 ); 48 30 }
+4
apps/web/src/components/song/song.tsx
··· 132 132 alt={title} 133 133 width={100} 134 134 height={100} 135 + unoptimized={ 136 + coverArt.startsWith("http://127.0.0.1") || 137 + coverArt.startsWith("http://localhost") 138 + } 135 139 /> 136 140 <div className="flex flex-col gap-1 h-full justify-between"> 137 141 <div className="flex flex-col gap-1">
+6 -6
apps/web/src/components/song/upload-action.ts
··· 32 32 const agent = new Agent(session); 33 33 34 34 try { 35 - const [{ data: audioUpload }, { data: coverArtUpload }] = await Promise.all( 36 - [ 37 - agent.uploadBlob(audio, { encoding: audio.type }), 38 - agent.uploadBlob(coverArt, { encoding: coverArt.type }), 39 - ], 40 - ); 35 + const { data: audioUpload } = await agent.uploadBlob(audio, { 36 + encoding: audio.type, 37 + }); 38 + const { data: coverArtUpload } = await agent.uploadBlob(coverArt, { 39 + encoding: coverArt.type, 40 + }); 41 41 42 42 const { data: record } = await agent.com.atproto.repo.createRecord({ 43 43 repo: agent.assertDid,
+3
apps/web/src/lib/api.ts
··· 1 1 export const PUBLIC_URL = 2 2 process.env.NEXT_PUBLIC_URL ?? "http://127.0.0.1:3000"; 3 + 4 + export const APPVIEW_URL = 5 + process.env.NEXT_PUBLIC_APPVIEW_URL ?? "http://127.0.0.1:3001";
+7 -29
apps/web/src/lib/atproto.ts
··· 1 - export function getDidFromUri(uri: string): string { 2 - return uri.split("/")[2]!; 3 - } 4 - 5 - export function getRkeyFromUri(uri: string): string { 6 - return uri.split("/")[4]!; 7 - } 8 - 9 - export function buildBlobUrl( 10 - pds: string, 11 - did: string, 12 - ref: { toString(): string }, 13 - ): string { 14 - return `${pds}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${ref.toString()}`; 15 - } 16 - 17 - export function isResourceOwner( 18 - sessionDid: string | undefined, 19 - resourceUri: string, 20 - ): boolean { 21 - return sessionDid === getDidFromUri(resourceUri); 22 - } 23 - 24 - export const COLLECTIONS = { 25 - song: "app.musicsky.temp.song", 26 - playlist: "app.musicsky.temp.playlist", 27 - like: "app.musicsky.temp.like", 28 - repost: "app.musicsky.temp.repost", 29 - } as const; 1 + export { 2 + getDidFromUri, 3 + getRkeyFromUri, 4 + buildBlobUrl, 5 + isResourceOwner, 6 + COLLECTIONS, 7 + } from "common";
+9 -45
apps/web/src/lib/songs.ts
··· 1 - import { TID } from "@atproto/common-web"; 2 1 import { Agent } from "@atproto/api"; 3 - import { IdResolver } from "@atproto/identity"; 4 2 import type { OAuthSession } from "@atproto/oauth-client-node"; 5 3 import type { SongProps, TrackRecord } from "@/types/song"; 6 - import { getRkeyFromUri, buildBlobUrl, COLLECTIONS } from "@/lib/atproto"; 4 + import { 5 + getRkeyFromUri, 6 + buildBlobUrl, 7 + getCreatedAtFromRkey, 8 + COLLECTIONS, 9 + } from "common"; 10 + 11 + export { getDid, getPds, getHandleFromDid } from "common"; 7 12 8 13 export function mapRecordToSong( 9 14 uri: string, ··· 25 30 duration: value.duration, 26 31 description: value.description ?? null, 27 32 author: handle, 28 - createdAt: new Date(TID.fromStr(rkey).timestamp() / 1000).toISOString(), 33 + createdAt: getCreatedAtFromRkey(rkey), 29 34 }; 30 - } 31 - 32 - export async function getDid(handle: string) { 33 - const agent = new Agent("https://public.api.bsky.app"); 34 - try { 35 - const { data: identity } = await agent.resolveHandle({ handle }); 36 - return identity.did; 37 - } catch (error) { 38 - console.error("Failed to fetch DID for", handle, error); 39 - return null; 40 - } 41 - } 42 - 43 - export async function getPds(did: string) { 44 - const resolver = new IdResolver(); 45 - try { 46 - const doc = await resolver.did.resolve(did); 47 - const pdsService = doc?.service?.find( 48 - (service) => service.id === "#atproto_pds", 49 - ); 50 - if (!pdsService?.serviceEndpoint) { 51 - throw new Error("No PDS endpoint found for this user"); 52 - } 53 - return pdsService.serviceEndpoint as string; 54 - } catch (error) { 55 - console.error("Failed to fetch PDS URL for", did, error); 56 - return null; 57 - } 58 - } 59 - 60 - export async function getHandleFromDid(did: string, knownPds?: string) { 61 - try { 62 - const pds = knownPds ?? (await getPds(did)); 63 - if (!pds) throw new Error("Could not resolve PDS for DID"); 64 - const agent = new Agent(pds); 65 - const { data } = await agent.com.atproto.repo.describeRepo({ repo: did }); 66 - return data.handle; 67 - } catch (error) { 68 - console.error("Failed to resolve handle for", did, error); 69 - return did; 70 - } 71 35 } 72 36 73 37 export async function getUserInteractions(session: OAuthSession | null) {
+7
package.json
··· 8 8 "lint": "turbo run lint", 9 9 "typecheck": "turbo run typecheck", 10 10 "knip": "turbo run knip", 11 + "test": "turbo run test", 11 12 "format": "prettier --write .", 12 13 "format:check": "prettier --check .", 13 14 "prepare": "husky" 14 15 }, 16 + "pnpm": { 17 + "overrides": { 18 + "zod@^3.25.0": "4.3.6" 19 + } 20 + }, 15 21 "devDependencies": { 22 + "@atproto/lex-cli": "^0.9.9", 16 23 "husky": "^9.1.7", 17 24 "lint-staged": "^16.2.7", 18 25 "prettier": "^3.8.1",
+16
packages/common/package.json
··· 1 + { 2 + "name": "common", 3 + "version": "0.0.0", 4 + "private": true, 5 + "type": "module", 6 + "main": "src/index.ts", 7 + "types": "src/index.ts", 8 + "exports": { 9 + ".": "./src/index.ts" 10 + }, 11 + "dependencies": { 12 + "@atproto/api": "^0.19.0", 13 + "@atproto/common-web": "^0.4.18", 14 + "@atproto/identity": "^0.4.12" 15 + } 16 + }
+35
packages/common/src/atproto.ts
··· 1 + import { TID } from "@atproto/common-web"; 2 + 3 + export function getCreatedAtFromRkey(rkey: string): string { 4 + return new Date(TID.fromStr(rkey).timestamp() / 1000).toISOString(); 5 + } 6 + 7 + export function getDidFromUri(uri: string): string { 8 + return uri.split("/")[2]!; 9 + } 10 + 11 + export function getRkeyFromUri(uri: string): string { 12 + return uri.split("/")[4]!; 13 + } 14 + 15 + export function buildBlobUrl( 16 + pds: string, 17 + did: string, 18 + ref: { toString(): string }, 19 + ): string { 20 + return `${pds}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${ref.toString()}`; 21 + } 22 + 23 + export function isResourceOwner( 24 + sessionDid: string | undefined, 25 + resourceUri: string, 26 + ): boolean { 27 + return sessionDid === getDidFromUri(resourceUri); 28 + } 29 + 30 + export const COLLECTIONS = { 31 + song: "app.musicsky.temp.song", 32 + playlist: "app.musicsky.temp.playlist", 33 + like: "app.musicsky.temp.like", 34 + repost: "app.musicsky.temp.repost", 35 + } as const;
+44
packages/common/src/identity.ts
··· 1 + import { Agent } from "@atproto/api"; 2 + import { IdResolver } from "@atproto/identity"; 3 + 4 + export async function getDid(handle: string) { 5 + const agent = new Agent("https://public.api.bsky.app"); 6 + try { 7 + const { data: identity } = await agent.resolveHandle({ handle }); 8 + return identity.did; 9 + } catch (error) { 10 + console.error("Failed to fetch DID for", handle, error); 11 + return null; 12 + } 13 + } 14 + 15 + export async function getPds(did: string) { 16 + const resolver = new IdResolver(); 17 + try { 18 + const doc = await resolver.did.resolve(did); 19 + const pdsService = doc?.service?.find( 20 + (service: { id: string; serviceEndpoint?: string }) => 21 + service.id === "#atproto_pds", 22 + ); 23 + if (!pdsService?.serviceEndpoint) { 24 + throw new Error("No PDS endpoint found for this user"); 25 + } 26 + return pdsService.serviceEndpoint as string; 27 + } catch (error) { 28 + console.error("Failed to fetch PDS URL for", did, error); 29 + return null; 30 + } 31 + } 32 + 33 + export async function getHandleFromDid(did: string, knownPds?: string) { 34 + try { 35 + const pds = knownPds ?? (await getPds(did)); 36 + if (!pds) throw new Error("Could not resolve PDS for DID"); 37 + const agent = new Agent(pds); 38 + const { data } = await agent.com.atproto.repo.describeRepo({ repo: did }); 39 + return data.handle; 40 + } catch (error) { 41 + console.error("Failed to resolve handle for", did, error); 42 + return did; 43 + } 44 + }
+10
packages/common/src/index.ts
··· 1 + export { 2 + getCreatedAtFromRkey, 3 + getDidFromUri, 4 + getRkeyFromUri, 5 + buildBlobUrl, 6 + isResourceOwner, 7 + COLLECTIONS, 8 + } from "./atproto"; 9 + 10 + export { getDid, getPds, getHandleFromDid } from "./identity";
+17
packages/common/tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + "target": "ES2017", 4 + "lib": ["esnext"], 5 + "strict": true, 6 + "noEmit": true, 7 + "esModuleInterop": true, 8 + "module": "esnext", 9 + "moduleResolution": "bundler", 10 + "resolveJsonModule": true, 11 + "verbatimModuleSyntax": true, 12 + "skipLibCheck": true, 13 + "incremental": true 14 + }, 15 + "include": ["src/**/*.ts"], 16 + "exclude": ["node_modules"] 17 + }
+86
packages/lexicons/defs/app/musicsky/temp/getFeed.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "app.musicsky.temp.getFeed", 4 + "defs": { 5 + "main": { 6 + "type": "query", 7 + "description": "Get a chronological feed of songs.", 8 + "parameters": { 9 + "type": "params", 10 + "properties": { 11 + "limit": { 12 + "type": "integer", 13 + "minimum": 1, 14 + "maximum": 100, 15 + "default": 50, 16 + "description": "Maximum number of results." 17 + }, 18 + "cursor": { 19 + "type": "string", 20 + "description": "Pagination cursor." 21 + }, 22 + "viewer": { 23 + "type": "string", 24 + "description": "DID of the viewing user for viewer state." 25 + } 26 + } 27 + }, 28 + "output": { 29 + "encoding": "application/json", 30 + "schema": { 31 + "type": "object", 32 + "required": ["songs"], 33 + "properties": { 34 + "cursor": { 35 + "type": "string" 36 + }, 37 + "songs": { 38 + "type": "array", 39 + "items": { 40 + "type": "ref", 41 + "ref": "#songView" 42 + } 43 + } 44 + } 45 + } 46 + } 47 + }, 48 + "songView": { 49 + "type": "object", 50 + "required": ["uri", "cid", "author", "record", "indexedAt"], 51 + "properties": { 52 + "uri": { "type": "string" }, 53 + "cid": { "type": "string" }, 54 + "author": { 55 + "type": "ref", 56 + "ref": "#authorView" 57 + }, 58 + "record": { "type": "unknown" }, 59 + "likeCount": { "type": "integer" }, 60 + "repostCount": { "type": "integer" }, 61 + "viewer": { 62 + "type": "ref", 63 + "ref": "#viewerState" 64 + }, 65 + "indexedAt": { "type": "string" }, 66 + "createdAt": { "type": "string" } 67 + } 68 + }, 69 + "authorView": { 70 + "type": "object", 71 + "required": ["did", "handle", "pds"], 72 + "properties": { 73 + "did": { "type": "string" }, 74 + "handle": { "type": "string" }, 75 + "pds": { "type": "string" } 76 + } 77 + }, 78 + "viewerState": { 79 + "type": "object", 80 + "properties": { 81 + "like": { "type": "string" }, 82 + "repost": { "type": "string" } 83 + } 84 + } 85 + } 86 + }
+14
packages/lexicons/src/index.ts
··· 10 10 import { CID } from 'multiformats/cid' 11 11 import { type OmitKey, type Un$Typed } from './util.js' 12 12 import * as AppMusicskyTempComment from './types/app/musicsky/temp/comment.js' 13 + import * as AppMusicskyTempGetFeed from './types/app/musicsky/temp/getFeed.js' 13 14 import * as AppMusicskyTempLike from './types/app/musicsky/temp/like.js' 14 15 import * as AppMusicskyTempPlaylist from './types/app/musicsky/temp/playlist.js' 15 16 import * as AppMusicskyTempRepost from './types/app/musicsky/temp/repost.js' 16 17 import * as AppMusicskyTempSong from './types/app/musicsky/temp/song.js' 17 18 18 19 export * as AppMusicskyTempComment from './types/app/musicsky/temp/comment.js' 20 + export * as AppMusicskyTempGetFeed from './types/app/musicsky/temp/getFeed.js' 19 21 export * as AppMusicskyTempLike from './types/app/musicsky/temp/like.js' 20 22 export * as AppMusicskyTempPlaylist from './types/app/musicsky/temp/playlist.js' 21 23 export * as AppMusicskyTempRepost from './types/app/musicsky/temp/repost.js' ··· 70 72 this.playlist = new AppMusicskyTempPlaylistRecord(client) 71 73 this.repost = new AppMusicskyTempRepostRecord(client) 72 74 this.song = new AppMusicskyTempSongRecord(client) 75 + } 76 + 77 + getFeed( 78 + params?: AppMusicskyTempGetFeed.QueryParams, 79 + opts?: AppMusicskyTempGetFeed.CallOptions, 80 + ): Promise<AppMusicskyTempGetFeed.Response> { 81 + return this._client.call( 82 + 'app.musicsky.temp.getFeed', 83 + params, 84 + undefined, 85 + opts, 86 + ) 73 87 } 74 88 } 75 89
+112 -14
packages/lexicons/src/lexicons.ts
··· 65 65 }, 66 66 }, 67 67 }, 68 + AppMusicskyTempGetFeed: { 69 + lexicon: 1, 70 + id: 'app.musicsky.temp.getFeed', 71 + defs: { 72 + main: { 73 + type: 'query', 74 + description: 'Get a chronological feed of songs.', 75 + parameters: { 76 + type: 'params', 77 + properties: { 78 + limit: { 79 + type: 'integer', 80 + minimum: 1, 81 + maximum: 100, 82 + default: 50, 83 + description: 'Maximum number of results.', 84 + }, 85 + cursor: { 86 + type: 'string', 87 + description: 'Pagination cursor.', 88 + }, 89 + viewer: { 90 + type: 'string', 91 + description: 'DID of the viewing user for viewer state.', 92 + }, 93 + }, 94 + }, 95 + output: { 96 + encoding: 'application/json', 97 + schema: { 98 + type: 'object', 99 + required: ['songs'], 100 + properties: { 101 + cursor: { 102 + type: 'string', 103 + }, 104 + songs: { 105 + type: 'array', 106 + items: { 107 + type: 'ref', 108 + ref: 'lex:app.musicsky.temp.getFeed#songView', 109 + }, 110 + }, 111 + }, 112 + }, 113 + }, 114 + }, 115 + songView: { 116 + type: 'object', 117 + required: ['uri', 'cid', 'author', 'record', 'indexedAt'], 118 + properties: { 119 + uri: { 120 + type: 'string', 121 + }, 122 + cid: { 123 + type: 'string', 124 + }, 125 + author: { 126 + type: 'ref', 127 + ref: 'lex:app.musicsky.temp.getFeed#authorView', 128 + }, 129 + record: { 130 + type: 'unknown', 131 + }, 132 + likeCount: { 133 + type: 'integer', 134 + }, 135 + repostCount: { 136 + type: 'integer', 137 + }, 138 + viewer: { 139 + type: 'ref', 140 + ref: 'lex:app.musicsky.temp.getFeed#viewerState', 141 + }, 142 + indexedAt: { 143 + type: 'string', 144 + }, 145 + createdAt: { 146 + type: 'string', 147 + }, 148 + }, 149 + }, 150 + authorView: { 151 + type: 'object', 152 + required: ['did', 'handle', 'pds'], 153 + properties: { 154 + did: { 155 + type: 'string', 156 + }, 157 + handle: { 158 + type: 'string', 159 + }, 160 + pds: { 161 + type: 'string', 162 + }, 163 + }, 164 + }, 165 + viewerState: { 166 + type: 'object', 167 + properties: { 168 + like: { 169 + type: 'string', 170 + }, 171 + repost: { 172 + type: 'string', 173 + }, 174 + }, 175 + }, 176 + }, 177 + }, 68 178 AppMusicskyTempLike: { 69 179 lexicon: 1, 70 180 id: 'app.musicsky.temp.like', ··· 190 300 key: 'tid', 191 301 record: { 192 302 type: 'object', 193 - required: [ 194 - 'title', 195 - 'audio', 196 - 'coverArt', 197 - 'slug', 198 - 'duration', 199 - 'createdAt', 200 - ], 303 + required: ['title', 'audio', 'coverArt', 'duration', 'createdAt'], 201 304 properties: { 202 305 title: { 203 306 type: 'string', ··· 252 355 minimum: 1, 253 356 description: 'Duration of the track in seconds.', 254 357 }, 255 - slug: { 256 - type: 'string', 257 - maxLength: 128, 258 - maxGraphemes: 128, 259 - description: 'URL-friendly slug for the track.', 260 - }, 261 358 labels: { 262 359 type: 'union', 263 360 refs: ['lex:com.atproto.label.defs#selfLabels'], ··· 309 406 310 407 export const ids = { 311 408 AppMusicskyTempComment: 'app.musicsky.temp.comment', 409 + AppMusicskyTempGetFeed: 'app.musicsky.temp.getFeed', 312 410 AppMusicskyTempLike: 'app.musicsky.temp.like', 313 411 AppMusicskyTempPlaylist: 'app.musicsky.temp.playlist', 314 412 AppMusicskyTempRepost: 'app.musicsky.temp.repost',
+102
packages/lexicons/src/types/app/musicsky/temp/getFeed.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { 9 + type $Typed, 10 + is$typed as _is$typed, 11 + type OmitKey, 12 + } from '../../../../util' 13 + 14 + const is$typed = _is$typed, 15 + validate = _validate 16 + const id = 'app.musicsky.temp.getFeed' 17 + 18 + export type QueryParams = { 19 + /** Maximum number of results. */ 20 + limit?: number 21 + /** Pagination cursor. */ 22 + cursor?: string 23 + /** DID of the viewing user for viewer state. */ 24 + viewer?: string 25 + } 26 + export type InputSchema = undefined 27 + 28 + export interface OutputSchema { 29 + cursor?: string 30 + songs: SongView[] 31 + } 32 + 33 + export interface CallOptions { 34 + signal?: AbortSignal 35 + headers?: HeadersMap 36 + } 37 + 38 + export interface Response { 39 + success: boolean 40 + headers: HeadersMap 41 + data: OutputSchema 42 + } 43 + 44 + export function toKnownErr(e: any) { 45 + return e 46 + } 47 + 48 + export interface SongView { 49 + $type?: 'app.musicsky.temp.getFeed#songView' 50 + uri: string 51 + cid: string 52 + author: AuthorView 53 + record: { [_ in string]: unknown } 54 + likeCount?: number 55 + repostCount?: number 56 + viewer?: ViewerState 57 + indexedAt: string 58 + createdAt?: string 59 + } 60 + 61 + const hashSongView = 'songView' 62 + 63 + export function isSongView<V>(v: V) { 64 + return is$typed(v, id, hashSongView) 65 + } 66 + 67 + export function validateSongView<V>(v: V) { 68 + return validate<SongView & V>(v, id, hashSongView) 69 + } 70 + 71 + export interface AuthorView { 72 + $type?: 'app.musicsky.temp.getFeed#authorView' 73 + did: string 74 + handle: string 75 + pds: string 76 + } 77 + 78 + const hashAuthorView = 'authorView' 79 + 80 + export function isAuthorView<V>(v: V) { 81 + return is$typed(v, id, hashAuthorView) 82 + } 83 + 84 + export function validateAuthorView<V>(v: V) { 85 + return validate<AuthorView & V>(v, id, hashAuthorView) 86 + } 87 + 88 + export interface ViewerState { 89 + $type?: 'app.musicsky.temp.getFeed#viewerState' 90 + like?: string 91 + repost?: string 92 + } 93 + 94 + const hashViewerState = 'viewerState' 95 + 96 + export function isViewerState<V>(v: V) { 97 + return is$typed(v, id, hashViewerState) 98 + } 99 + 100 + export function validateViewerState<V>(v: V) { 101 + return validate<ViewerState & V>(v, id, hashViewerState) 102 + }
+2251 -68
pnpm-lock.yaml
··· 4 4 autoInstallPeers: true 5 5 excludeLinksFromLockfile: false 6 6 7 + overrides: 8 + zod@^3.25.0: 4.3.6 9 + 7 10 importers: 8 11 .: 9 12 devDependencies: 13 + "@atproto/lex-cli": 14 + specifier: ^0.9.9 15 + version: 0.9.9 10 16 husky: 11 17 specifier: ^9.1.7 12 18 version: 9.1.7 ··· 20 26 specifier: ^2 21 27 version: 2.8.19 22 28 29 + apps/appview: 30 + dependencies: 31 + "@atproto/syntax": 32 + specifier: ^0.3.2 33 + version: 0.3.4 34 + "@atproto/tap": 35 + specifier: ^0.1.0 36 + version: 0.1.3 37 + better-sqlite3: 38 + specifier: ^12.6.2 39 + version: 12.6.2 40 + common: 41 + specifier: workspace:* 42 + version: link:../../packages/common 43 + express: 44 + specifier: ^5.0.1 45 + version: 5.2.1 46 + kysely: 47 + specifier: ^0.28.11 48 + version: 0.28.11 49 + devDependencies: 50 + "@eslint/js": 51 + specifier: ^9 52 + version: 9.39.3 53 + "@types/better-sqlite3": 54 + specifier: ^7.6.13 55 + version: 7.6.13 56 + "@types/express": 57 + specifier: ^5.0.1 58 + version: 5.0.6 59 + "@types/node": 60 + specifier: ^20 61 + version: 20.19.37 62 + eslint: 63 + specifier: ^9 64 + version: 9.39.3(jiti@2.6.1) 65 + eslint-config-prettier: 66 + specifier: ^10 67 + version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) 68 + knip: 69 + specifier: ^5.86.0 70 + version: 5.86.0(@types/node@20.19.37)(typescript@5.9.3) 71 + tsup: 72 + specifier: ^8 73 + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) 74 + tsx: 75 + specifier: ^4.21.0 76 + version: 4.21.0 77 + typescript: 78 + specifier: ^5 79 + version: 5.9.3 80 + typescript-eslint: 81 + specifier: ^8 82 + version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) 83 + vitest: 84 + specifier: ^4.1.0 85 + version: 4.1.0(@types/node@20.19.37)(msw@2.12.10(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.1(@types/node@20.19.37)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) 86 + 23 87 apps/web: 24 88 dependencies: 25 89 "@atproto/api": ··· 28 92 "@atproto/common-web": 29 93 specifier: ^0.4.18 30 94 version: 0.4.18 31 - "@atproto/identity": 32 - specifier: ^0.4.12 33 - version: 0.4.12 34 95 "@atproto/lexicon": 35 96 specifier: ^0.6.1 36 97 version: 0.6.1 ··· 49 110 clsx: 50 111 specifier: ^2.1.1 51 112 version: 2.1.1 113 + common: 114 + specifier: workspace:* 115 + version: link:../../packages/common 52 116 date-fns: 53 117 specifier: ^4.1.0 54 118 version: 4.1.0 ··· 115 179 version: 9.39.3(jiti@2.6.1) 116 180 eslint-config-next: 117 181 specifier: ^16.1.7 118 - version: 16.1.7(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) 182 + version: 16.1.7(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) 119 183 eslint-config-prettier: 120 184 specifier: ^10.1.8 121 185 version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) ··· 144 208 specifier: ^5 145 209 version: 5.9.3 146 210 211 + packages/common: 212 + dependencies: 213 + "@atproto/api": 214 + specifier: ^0.19.0 215 + version: 0.19.0 216 + "@atproto/common-web": 217 + specifier: ^0.4.18 218 + version: 0.4.18 219 + "@atproto/identity": 220 + specifier: ^0.4.12 221 + version: 0.4.12 222 + 147 223 packages/lexicons: 148 224 dependencies: 149 225 "@atproto/lexicon": ··· 170 246 integrity: sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==, 171 247 } 172 248 hasBin: true 249 + 250 + "@atproto-labs/did-resolver@0.2.5": 251 + resolution: 252 + { 253 + integrity: sha512-he7EC6OMSifNs01a4RT9mta/yYitoKDzlK9ty2TFV5Uj/+HpB4vYMRdIDFrRW0Hcsehy90E2t/dw0t7361MEKQ==, 254 + } 173 255 174 256 "@atproto-labs/did-resolver@0.2.6": 175 257 resolution: ··· 239 321 integrity: sha512-ilImzP+9N/mtse440kN60pGrEzG7wi4xsV13nGeLrS+Zocybc/ISOpKlbZM13o+twPJ+Q7veGLw9CtGg0GAFoQ==, 240 322 } 241 323 324 + "@atproto/common-web@0.4.19": 325 + resolution: 326 + { 327 + integrity: sha512-3BTi58p5WpT+9/zb6UZrdsXcfPo5P45UJm0E4iwHLILr+jc37CuBj9JReDSZ4U0i9RTrI3ZkfySyZ9bd+LnMsw==, 328 + } 329 + 330 + "@atproto/common@0.5.15": 331 + resolution: 332 + { 333 + integrity: sha512-+cdfdMPAIbH9zQGLfH1gNY2KEZsMxj0EelVQL5uJUFL+UkkAXiiqWj7J5mbax8sf02cC/afJnfkWzERNAheKoA==, 334 + } 335 + engines: { node: ">=18.7.0" } 336 + 242 337 "@atproto/crypto@0.4.5": 243 338 resolution: 244 339 { 245 340 integrity: sha512-n40aKkMoCatP0u9Yvhrdk6fXyOHFDDbkdm4h4HCyWW+KlKl8iXfD5iV+ECq+w5BM+QH25aIpt3/j6EUNerhLxw==, 246 341 } 247 342 engines: { node: ">=18.7.0" } 343 + 344 + "@atproto/did@0.2.4": 345 + resolution: 346 + { 347 + integrity: sha512-nxNiCgXeo7pfjojq9fpfZxCO0X0xUipNVKW+AHNZwQKiUDt6zYL0VXEfm8HBUwQOCmKvj2pRRSM1Cur+tUWk3g==, 348 + } 248 349 249 350 "@atproto/did@0.3.0": 250 351 resolution: ··· 277 378 integrity: sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw==, 278 379 } 279 380 381 + "@atproto/lex-builder@0.0.11": 382 + resolution: 383 + { 384 + integrity: sha512-7FQ7iEB8CrZ2ie3NsweZpcleddf0Dd3Ck98iZbBmxmnWrHwseC86+NJ2q+THsbHyF/tdtHGhJPxmc7wWZ5WDKA==, 385 + } 386 + 387 + "@atproto/lex-cbor@0.0.15": 388 + resolution: 389 + { 390 + integrity: sha512-3osDicK9bAMXJlKjLKqwYrhLQ60bOguWBNjE+fuNjMuizNzC0aqaClE3d+qMsFuFq9bjEHFw+4Vr9Qmd/m6VYg==, 391 + } 392 + 393 + "@atproto/lex-cbor@0.0.8": 394 + resolution: 395 + { 396 + integrity: sha512-WFUkNTLUMunPaA+NkD2INwfhrgo5fAMz7zSk2ncoqbK2AS78X2ith8TJSevY0ynPukbFmaJ9BdauzCpWQ4ZIqQ==, 397 + } 398 + 399 + "@atproto/lex-cli@0.9.9": 400 + resolution: 401 + { 402 + integrity: sha512-n/ClCBNnrjbqflLFt+j8Vx8q+lQd6OPQiDToi80akUoW2wNyPmsWtK5tKje0HS+7aHZD3gO3yX4B/x6ZqqrEeA==, 403 + } 404 + engines: { node: ">=18.7.0" } 405 + hasBin: true 406 + 407 + "@atproto/lex-client@0.0.9": 408 + resolution: 409 + { 410 + integrity: sha512-30WtEedG0s/JNkbHzxpObkUg0id4+/p1O7LcUVCQWrNhWRw/hCzhHySSgFKKIVeLKAYIrZmaWt1XlAdNhGO7DQ==, 411 + } 412 + 280 413 "@atproto/lex-data@0.0.13": 281 414 resolution: 282 415 { 283 416 integrity: sha512-7Z7RwZ1Y/JzBF/Tcn/I4UJ/vIGfh5zn1zjv0KX+flke2JtgFkSE8uh2hOtqgBQMNqE3zdJFM+dcSWln86hR3MQ==, 284 417 } 285 418 419 + "@atproto/lex-data@0.0.14": 420 + resolution: 421 + { 422 + integrity: sha512-53DUa9664SS76nGAMYopWsO10OH0AAdf7P/HSKB6Wzx3iqe6lk/K61QZnKxOG1LreYl5CfvIJU6eNf4txI6GlQ==, 423 + } 424 + 425 + "@atproto/lex-data@0.0.8": 426 + resolution: 427 + { 428 + integrity: sha512-1Y5tz7BkS7380QuLNXaE8GW8Xba+mRWugt8BKM4BUFYjjUZdmirU8lr72iM4XlEBrzRu8Cfvj+MbsbYaZv+IgA==, 429 + } 430 + 431 + "@atproto/lex-document@0.0.10": 432 + resolution: 433 + { 434 + integrity: sha512-GrvO36UyWhStSNN0CtVswMyzYK7eUA0zLjYJRqpghAyzYV9ZVXTUL1Vx79MUSg3tC1jDM1A0hmtsjE1Cyo2rHQ==, 435 + } 436 + 437 + "@atproto/lex-installer@0.0.11": 438 + resolution: 439 + { 440 + integrity: sha512-uNjpmG7p91UBKd1RJh0AJbbi5jzpHuTCjx1Pr0ZBbBmssOnr9GvMhSpeFU8ZuJ2HJqMMCBxUCU7zlad/b0KafA==, 441 + } 442 + 286 443 "@atproto/lex-json@0.0.13": 287 444 resolution: 288 445 { 289 446 integrity: sha512-hwLhkKaIHulGJpt0EfXAEWdrxqM2L1tV/tvilzhMp3QxPqYgXchFnrfVmLsyFDx6P6qkH1GsX/XC2V36U0UlPQ==, 290 447 } 291 448 449 + "@atproto/lex-json@0.0.14": 450 + resolution: 451 + { 452 + integrity: sha512-6lPkDKqe7teEu4WrN5q7400cvZKgYS3uwUMvzG3F9XkgVYhOwSDCtouV/nSLBbpvo3l9OP0kiigtclcNcyekww==, 453 + } 454 + 455 + "@atproto/lex-json@0.0.8": 456 + resolution: 457 + { 458 + integrity: sha512-w1Qmkae1QhmNz+i1Zm3xr3jp0UPPRENmdlpU0qIrdxWDo9W4Mzkeyc3eSoa+Zs+zN8xkRSQw7RLZte/B7Ipdwg==, 459 + } 460 + 461 + "@atproto/lex-resolver@0.0.10": 462 + resolution: 463 + { 464 + integrity: sha512-7cV/vjJGHMUbzv1y2kIOChC/B5ox1F5hKpG3fFZdkM8eZ5o9NuMiIojvTgCYdxyH+XA/X6qjblMrru73fFRtmA==, 465 + } 466 + 467 + "@atproto/lex-schema@0.0.9": 468 + resolution: 469 + { 470 + integrity: sha512-nsXpG0BdWu5Qn8qgs/+tHKP2gdVoYNiYwIUl+lt6EFb5juuOScmPilhZOa9MPDpLLzVgl35x9whjh842CvpHJQ==, 471 + } 472 + 473 + "@atproto/lex@0.0.11": 474 + resolution: 475 + { 476 + integrity: sha512-/AmuUrBidTMqwmPedjhGI3nqSZ7JqiowcCuFhfa1kvkJLPbv8S+PPALRrc+pvMM3IEgg9EctqmeauQM+as32ww==, 477 + } 478 + hasBin: true 479 + 292 480 "@atproto/lexicon@0.6.1": 293 481 resolution: 294 482 { 295 483 integrity: sha512-/vI1kVlY50Si+5MXpvOucelnYwb0UJ6Qto5mCp+7Q5C+Jtp+SoSykAPVvjVtTnQUH2vrKOFOwpb3C375vSKzXw==, 296 484 } 297 485 486 + "@atproto/lexicon@0.6.2": 487 + resolution: 488 + { 489 + integrity: sha512-p3Ly6hinVZW0ETuAXZMeUGwuMm3g8HvQMQ41yyEE6AL0hAkfeKFaZKos6BdBrr6CjkpbrDZqE8M+5+QOceysMw==, 490 + } 491 + 298 492 "@atproto/oauth-client-node@0.3.17": 299 493 resolution: 300 494 { ··· 314 508 integrity: sha512-jdKuoPknJuh/WjI+mYk7agSbx9mNVMbS6Dr3k1z2YMY2oRiCQjxYBuo4MLKATbxj05nMQaZRWlHRUazoAu5Cng==, 315 509 } 316 510 511 + "@atproto/repo@0.8.12": 512 + resolution: 513 + { 514 + integrity: sha512-QpVTVulgfz5PUiCTELlDBiRvnsnwrFWi+6CfY88VwXzrRHd9NE8GItK7sfxQ6U65vD/idH8ddCgFrlrsn1REPQ==, 515 + } 516 + engines: { node: ">=18.7.0" } 517 + 518 + "@atproto/syntax@0.3.4": 519 + resolution: 520 + { 521 + integrity: sha512-8CNmi5DipOLaVeSMPggMe7FCksVag0aO6XZy9WflbduTKM4dFZVCs4686UeMLfGRXX+X966XgwECHoLYrovMMg==, 522 + } 523 + 524 + "@atproto/syntax@0.4.2": 525 + resolution: 526 + { 527 + integrity: sha512-X9XSRPinBy/0VQ677j8VXlBsYSsUXaiqxWVpGGxJYsAhugdQRb0jqaVKJFtm6RskeNkV6y9xclSUi9UYG/COrA==, 528 + } 529 + 317 530 "@atproto/syntax@0.4.3": 318 531 resolution: 319 532 { 320 533 integrity: sha512-YoZUz40YAJr5nPwvCDWgodEOlt5IftZqPJvA0JDWjuZKD8yXddTwSzXSaKQAzGOpuM+/A3uXRtPzJJqlScc+iA==, 321 534 } 322 535 323 - "@atproto/syntax@0.5.0": 536 + "@atproto/syntax@0.5.1": 324 537 resolution: 325 538 { 326 - integrity: sha512-UA2DSpGdOQzUQ4gi5SH+NEJz/YR3a3Fg3y2oh+xETDSiTRmA4VhHRCojhXAVsBxUT6EnItw190C/KN+DWW90kw==, 539 + integrity: sha512-J8DJjgKgACIyCTbpfvoTnf7+ofTx1kxTGO7KAftkC+jczaMdQhKdgIBAg2DaYy+80cvYGTHy5q/HI9qMAwGbWw==, 327 540 } 328 541 542 + "@atproto/tap@0.1.3": 543 + resolution: 544 + { 545 + integrity: sha512-vjc7RnBOBMHO01zTFvsFy2MvcdmRpoCOy/97xsnFSa0bR7C9OpnRJwMHodLqsbXrt0viLflD25BBXY+Q5VFspg==, 546 + } 547 + engines: { node: ">=18.7.0" } 548 + 549 + "@atproto/ws-client@0.0.4": 550 + resolution: 551 + { 552 + integrity: sha512-dox1XIymuC7/ZRhUqKezIGgooZS45C6vHCfu0PnWjfvsLCK2kAlnvX4IBkA/WpcoijDhQ9ejChnFbo/sLmgvAg==, 553 + } 554 + engines: { node: ">=18.7.0" } 555 + 329 556 "@atproto/xrpc@0.7.7": 330 557 resolution: 331 558 { ··· 1211 1438 peerDependenciesMeta: 1212 1439 "@types/node": 1213 1440 optional: true 1441 + 1442 + "@ipld/dag-cbor@7.0.3": 1443 + resolution: 1444 + { 1445 + integrity: sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA==, 1446 + } 1214 1447 1215 1448 "@jridgewell/gen-mapping@0.3.13": 1216 1449 resolution: ··· 1259 1492 engines: { node: ">=18" } 1260 1493 peerDependencies: 1261 1494 "@cfworker/json-schema": ^4.1.1 1262 - zod: ^3.25 || ^4.0 1495 + zod: 4.3.6 1263 1496 peerDependenciesMeta: 1264 1497 "@cfworker/json-schema": 1265 1498 optional: true ··· 1432 1665 resolution: 1433 1666 { 1434 1667 integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==, 1668 + } 1669 + 1670 + "@oxc-project/types@0.120.0": 1671 + resolution: 1672 + { 1673 + integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==, 1435 1674 } 1436 1675 1437 1676 "@oxc-resolver/binding-android-arm-eabi@11.19.1": ··· 2470 2709 integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==, 2471 2710 } 2472 2711 2712 + "@rolldown/binding-android-arm64@1.0.0-rc.10": 2713 + resolution: 2714 + { 2715 + integrity: sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg==, 2716 + } 2717 + engines: { node: ^20.19.0 || >=22.12.0 } 2718 + cpu: [arm64] 2719 + os: [android] 2720 + 2721 + "@rolldown/binding-darwin-arm64@1.0.0-rc.10": 2722 + resolution: 2723 + { 2724 + integrity: sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w==, 2725 + } 2726 + engines: { node: ^20.19.0 || >=22.12.0 } 2727 + cpu: [arm64] 2728 + os: [darwin] 2729 + 2730 + "@rolldown/binding-darwin-x64@1.0.0-rc.10": 2731 + resolution: 2732 + { 2733 + integrity: sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A==, 2734 + } 2735 + engines: { node: ^20.19.0 || >=22.12.0 } 2736 + cpu: [x64] 2737 + os: [darwin] 2738 + 2739 + "@rolldown/binding-freebsd-x64@1.0.0-rc.10": 2740 + resolution: 2741 + { 2742 + integrity: sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w==, 2743 + } 2744 + engines: { node: ^20.19.0 || >=22.12.0 } 2745 + cpu: [x64] 2746 + os: [freebsd] 2747 + 2748 + "@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10": 2749 + resolution: 2750 + { 2751 + integrity: sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA==, 2752 + } 2753 + engines: { node: ^20.19.0 || >=22.12.0 } 2754 + cpu: [arm] 2755 + os: [linux] 2756 + 2757 + "@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10": 2758 + resolution: 2759 + { 2760 + integrity: sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg==, 2761 + } 2762 + engines: { node: ^20.19.0 || >=22.12.0 } 2763 + cpu: [arm64] 2764 + os: [linux] 2765 + 2766 + "@rolldown/binding-linux-arm64-musl@1.0.0-rc.10": 2767 + resolution: 2768 + { 2769 + integrity: sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g==, 2770 + } 2771 + engines: { node: ^20.19.0 || >=22.12.0 } 2772 + cpu: [arm64] 2773 + os: [linux] 2774 + 2775 + "@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10": 2776 + resolution: 2777 + { 2778 + integrity: sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w==, 2779 + } 2780 + engines: { node: ^20.19.0 || >=22.12.0 } 2781 + cpu: [ppc64] 2782 + os: [linux] 2783 + 2784 + "@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10": 2785 + resolution: 2786 + { 2787 + integrity: sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg==, 2788 + } 2789 + engines: { node: ^20.19.0 || >=22.12.0 } 2790 + cpu: [s390x] 2791 + os: [linux] 2792 + 2793 + "@rolldown/binding-linux-x64-gnu@1.0.0-rc.10": 2794 + resolution: 2795 + { 2796 + integrity: sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw==, 2797 + } 2798 + engines: { node: ^20.19.0 || >=22.12.0 } 2799 + cpu: [x64] 2800 + os: [linux] 2801 + 2802 + "@rolldown/binding-linux-x64-musl@1.0.0-rc.10": 2803 + resolution: 2804 + { 2805 + integrity: sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA==, 2806 + } 2807 + engines: { node: ^20.19.0 || >=22.12.0 } 2808 + cpu: [x64] 2809 + os: [linux] 2810 + 2811 + "@rolldown/binding-openharmony-arm64@1.0.0-rc.10": 2812 + resolution: 2813 + { 2814 + integrity: sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q==, 2815 + } 2816 + engines: { node: ^20.19.0 || >=22.12.0 } 2817 + cpu: [arm64] 2818 + os: [openharmony] 2819 + 2820 + "@rolldown/binding-wasm32-wasi@1.0.0-rc.10": 2821 + resolution: 2822 + { 2823 + integrity: sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA==, 2824 + } 2825 + engines: { node: ">=14.0.0" } 2826 + cpu: [wasm32] 2827 + 2828 + "@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10": 2829 + resolution: 2830 + { 2831 + integrity: sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ==, 2832 + } 2833 + engines: { node: ^20.19.0 || >=22.12.0 } 2834 + cpu: [arm64] 2835 + os: [win32] 2836 + 2837 + "@rolldown/binding-win32-x64-msvc@1.0.0-rc.10": 2838 + resolution: 2839 + { 2840 + integrity: sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w==, 2841 + } 2842 + engines: { node: ^20.19.0 || >=22.12.0 } 2843 + cpu: [x64] 2844 + os: [win32] 2845 + 2846 + "@rolldown/pluginutils@1.0.0-rc.10": 2847 + resolution: 2848 + { 2849 + integrity: sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg==, 2850 + } 2851 + 2852 + "@rollup/rollup-android-arm-eabi@4.59.1": 2853 + resolution: 2854 + { 2855 + integrity: sha512-xB0b51TB7IfDEzAojXahmr+gfA00uYVInJGgNNkeQG6RPnCPGr7udsylFLTubuIUSRE6FkcI1NElyRt83PP5oQ==, 2856 + } 2857 + cpu: [arm] 2858 + os: [android] 2859 + 2860 + "@rollup/rollup-android-arm64@4.59.1": 2861 + resolution: 2862 + { 2863 + integrity: sha512-XOjPId0qwSDKHaIsdzHJtKCxX0+nH8MhBwvrNsT7tVyKmdTx1jJ4XzN5RZXCdTzMpufLb+B8llTC0D8uCrLhcw==, 2864 + } 2865 + cpu: [arm64] 2866 + os: [android] 2867 + 2868 + "@rollup/rollup-darwin-arm64@4.59.1": 2869 + resolution: 2870 + { 2871 + integrity: sha512-vQuRd28p0gQpPrS6kppd8IrWmFo42U8Pz1XLRjSZXq5zCqyMDYFABT7/sywL11mO1EL10Qhh7MVPEwkG8GiBeg==, 2872 + } 2873 + cpu: [arm64] 2874 + os: [darwin] 2875 + 2876 + "@rollup/rollup-darwin-x64@4.59.1": 2877 + resolution: 2878 + { 2879 + integrity: sha512-x6VG6U29+Ivlnajrg1IHdzXeAwSoEHBFVO+CtC9Brugx6de712CUJobRUxsIA0KYrQvCmzNrMPFTT1A4CCqNTg==, 2880 + } 2881 + cpu: [x64] 2882 + os: [darwin] 2883 + 2884 + "@rollup/rollup-freebsd-arm64@4.59.1": 2885 + resolution: 2886 + { 2887 + integrity: sha512-Sgi0Uo6t1YCHJMNO3Y8+bm+SvOanUGkoZKn/VJPwYUe2kp31X5KnXmzKd/NjW8iA3gFcfNZ64zh14uOGrIllCQ==, 2888 + } 2889 + cpu: [arm64] 2890 + os: [freebsd] 2891 + 2892 + "@rollup/rollup-freebsd-x64@4.59.1": 2893 + resolution: 2894 + { 2895 + integrity: sha512-AM4xnwEZwukdhk7laMWfzWu9JGSVnJd+Fowt6Fd7QW1nrf3h0Hp7Qx5881M4aqrUlKBCybOxz0jofvIIfl7C5g==, 2896 + } 2897 + cpu: [x64] 2898 + os: [freebsd] 2899 + 2900 + "@rollup/rollup-linux-arm-gnueabihf@4.59.1": 2901 + resolution: 2902 + { 2903 + integrity: sha512-KUizqxpwaR2AZdAUsMWfL/C94pUu7TKpoPd88c8yFVixJ+l9hejkrwoK5Zj3wiNh65UeyryKnJyxL1b7yNqFQA==, 2904 + } 2905 + cpu: [arm] 2906 + os: [linux] 2907 + 2908 + "@rollup/rollup-linux-arm-musleabihf@4.59.1": 2909 + resolution: 2910 + { 2911 + integrity: sha512-MZoQ/am77ckJtZGFAtPucgUuJWiop3m2R3lw7tC0QCcbfl4DRhQUBUkHWCkcrT3pqy5Mzv5QQgY6Dmlba6iTWg==, 2912 + } 2913 + cpu: [arm] 2914 + os: [linux] 2915 + 2916 + "@rollup/rollup-linux-arm64-gnu@4.59.1": 2917 + resolution: 2918 + { 2919 + integrity: sha512-Sez95TP6xGjkWB1608EfhCX1gdGrO5wzyN99VqzRtC17x/1bhw5VU1V0GfKUwbW/Xr1J8mSasoFoJa6Y7aGGSA==, 2920 + } 2921 + cpu: [arm64] 2922 + os: [linux] 2923 + 2924 + "@rollup/rollup-linux-arm64-musl@4.59.1": 2925 + resolution: 2926 + { 2927 + integrity: sha512-9Cs2Seq98LWNOJzR89EGTZoiP8EkZ9UbQhBlDgfAkM6asVna1xJ04W2CLYWDN/RpUgOjtQvcv8wQVi1t5oQazA==, 2928 + } 2929 + cpu: [arm64] 2930 + os: [linux] 2931 + 2932 + "@rollup/rollup-linux-loong64-gnu@4.59.1": 2933 + resolution: 2934 + { 2935 + integrity: sha512-n9yqttftgFy7IrNEnHy1bOp6B4OSe8mJDiPkT7EqlM9FnKOwUMnCK62ixW0Kd9Clw0/wgvh8+SqaDXMFvw3KqQ==, 2936 + } 2937 + cpu: [loong64] 2938 + os: [linux] 2939 + 2940 + "@rollup/rollup-linux-loong64-musl@4.59.1": 2941 + resolution: 2942 + { 2943 + integrity: sha512-SfpNXDzVTqs/riak4xXcLpq5gIQWsqGWMhN1AGRQKB4qGSs4r0sEs3ervXPcE1O9RsQ5bm8Muz6zmQpQnPss1g==, 2944 + } 2945 + cpu: [loong64] 2946 + os: [linux] 2947 + 2948 + "@rollup/rollup-linux-ppc64-gnu@4.59.1": 2949 + resolution: 2950 + { 2951 + integrity: sha512-LjaChED0wQnjKZU+tsmGbN+9nN1XhaWUkAlSbTdhpEseCS4a15f/Q8xC2BN4GDKRzhhLZpYtJBZr2NZhR0jvNw==, 2952 + } 2953 + cpu: [ppc64] 2954 + os: [linux] 2955 + 2956 + "@rollup/rollup-linux-ppc64-musl@4.59.1": 2957 + resolution: 2958 + { 2959 + integrity: sha512-ojW7iTJSIs4pwB2xV6QXGwNyDctvXOivYllttuPbXguuKDX5vwpqYJsHc6D2LZzjDGHML414Tuj3LvVPe1CT1A==, 2960 + } 2961 + cpu: [ppc64] 2962 + os: [linux] 2963 + 2964 + "@rollup/rollup-linux-riscv64-gnu@4.59.1": 2965 + resolution: 2966 + { 2967 + integrity: sha512-FP+Q6WTcxxvsr0wQczhSE+tOZvFPV8A/mUE6mhZYFW9/eea/y/XqAgRoLLMuE9Cz0hfX5bi7p116IWoB+P237A==, 2968 + } 2969 + cpu: [riscv64] 2970 + os: [linux] 2971 + 2972 + "@rollup/rollup-linux-riscv64-musl@4.59.1": 2973 + resolution: 2974 + { 2975 + integrity: sha512-L1uD9b/Ig8Z+rn1KttCJjwhN1FgjRMBKsPaBsDKkfUl7GfFq71pU4vWCnpOsGljycFEbkHWARZLf4lMYg3WOLw==, 2976 + } 2977 + cpu: [riscv64] 2978 + os: [linux] 2979 + 2980 + "@rollup/rollup-linux-s390x-gnu@4.59.1": 2981 + resolution: 2982 + { 2983 + integrity: sha512-EZc9NGTk/oSUzzOD4nYY4gIjteo2M3CiozX6t1IXGCOdgxJTlVu/7EdPeiqeHPSIrxkLhavqpBAUCfvC6vBOug==, 2984 + } 2985 + cpu: [s390x] 2986 + os: [linux] 2987 + 2988 + "@rollup/rollup-linux-x64-gnu@4.59.1": 2989 + resolution: 2990 + { 2991 + integrity: sha512-NQ9KyU1Anuy59L8+HHOKM++CoUxrQWrZWXRik4BJFm+7i5NP6q/SW43xIBr80zzt+PDBJ7LeNmloQGfa0JGk0w==, 2992 + } 2993 + cpu: [x64] 2994 + os: [linux] 2995 + 2996 + "@rollup/rollup-linux-x64-musl@4.59.1": 2997 + resolution: 2998 + { 2999 + integrity: sha512-GZkLk2t6naywsveSFBsEb0PLU+JC9ggVjbndsbG20VPhar6D1gkMfCx4NfP9owpovBXTN+eRdqGSkDGIxPHhmQ==, 3000 + } 3001 + cpu: [x64] 3002 + os: [linux] 3003 + 3004 + "@rollup/rollup-openbsd-x64@4.59.1": 3005 + resolution: 3006 + { 3007 + integrity: sha512-1hjG9Jpl2KDOetr64iQd8AZAEjkDUUK5RbDkYWsViYLC1op1oNzdjMJeFiofcGhqbNTaY2kfgqowE7DILifsrA==, 3008 + } 3009 + cpu: [x64] 3010 + os: [openbsd] 3011 + 3012 + "@rollup/rollup-openharmony-arm64@4.59.1": 3013 + resolution: 3014 + { 3015 + integrity: sha512-ARoKfflk0SiiYm3r1fmF73K/yB+PThmOwfWCk1sr7x/k9dc3uGLWuEE9if+Pw21el8MSpp3TMnG5vLNsJ/MMGQ==, 3016 + } 3017 + cpu: [arm64] 3018 + os: [openharmony] 3019 + 3020 + "@rollup/rollup-win32-arm64-msvc@4.59.1": 3021 + resolution: 3022 + { 3023 + integrity: sha512-oOST61G6VM45Mz2vdzWMr1s2slI7y9LqxEV5fCoWi2MDONmMvgsJVHSXxce/I2xOSZPTZ47nDPOl1tkwKWSHcw==, 3024 + } 3025 + cpu: [arm64] 3026 + os: [win32] 3027 + 3028 + "@rollup/rollup-win32-ia32-msvc@4.59.1": 3029 + resolution: 3030 + { 3031 + integrity: sha512-x5WgLi5dWpRz7WclKBGEF15LcWTh0ewrHM6Cq4A+WUbkysUMZNeqt05bwPonOQ3ihPS/WMhAZV5zB1DfnI4Sxg==, 3032 + } 3033 + cpu: [ia32] 3034 + os: [win32] 3035 + 3036 + "@rollup/rollup-win32-x64-gnu@4.59.1": 3037 + resolution: 3038 + { 3039 + integrity: sha512-wS+zHAJRVP5zOL0e+a3V3E/NTEwM2HEvvNKoDy5Xcfs0o8lljxn+EAFPkUsxihBdmDq1JWzXmmB9cbssCPdxxw==, 3040 + } 3041 + cpu: [x64] 3042 + os: [win32] 3043 + 3044 + "@rollup/rollup-win32-x64-msvc@4.59.1": 3045 + resolution: 3046 + { 3047 + integrity: sha512-rhHyrMeLpErT/C7BxcEsU4COHQUzHyrPYW5tOZUeUhziNtRuYxmDWvqQqzpuUt8xpOgmbKa1btGXfnA/ANVO+g==, 3048 + } 3049 + cpu: [x64] 3050 + os: [win32] 3051 + 2473 3052 "@rtsao/scc@1.1.0": 2474 3053 resolution: 2475 3054 { ··· 2488 3067 integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==, 2489 3068 } 2490 3069 engines: { node: ">=18" } 3070 + 3071 + "@standard-schema/spec@1.1.0": 3072 + resolution: 3073 + { 3074 + integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==, 3075 + } 2491 3076 2492 3077 "@standard-schema/utils@0.3.0": 2493 3078 resolution: ··· 2634 3219 integrity: sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==, 2635 3220 } 2636 3221 3222 + "@ts-morph/common@0.25.0": 3223 + resolution: 3224 + { 3225 + integrity: sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg==, 3226 + } 3227 + 2637 3228 "@ts-morph/common@0.27.0": 2638 3229 resolution: 2639 3230 { 2640 3231 integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==, 3232 + } 3233 + 3234 + "@ts-morph/common@0.28.1": 3235 + resolution: 3236 + { 3237 + integrity: sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==, 2641 3238 } 2642 3239 2643 3240 "@turbo/darwin-64@2.8.19": ··· 2700 3297 integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==, 2701 3298 } 2702 3299 3300 + "@types/body-parser@1.19.6": 3301 + resolution: 3302 + { 3303 + integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==, 3304 + } 3305 + 3306 + "@types/chai@5.2.3": 3307 + resolution: 3308 + { 3309 + integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==, 3310 + } 3311 + 3312 + "@types/connect@3.4.38": 3313 + resolution: 3314 + { 3315 + integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==, 3316 + } 3317 + 3318 + "@types/deep-eql@4.0.2": 3319 + resolution: 3320 + { 3321 + integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==, 3322 + } 3323 + 2703 3324 "@types/estree@1.0.8": 2704 3325 resolution: 2705 3326 { 2706 3327 integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, 3328 + } 3329 + 3330 + "@types/express-serve-static-core@5.1.1": 3331 + resolution: 3332 + { 3333 + integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==, 3334 + } 3335 + 3336 + "@types/express@5.0.6": 3337 + resolution: 3338 + { 3339 + integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==, 3340 + } 3341 + 3342 + "@types/http-errors@2.0.5": 3343 + resolution: 3344 + { 3345 + integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==, 2707 3346 } 2708 3347 2709 3348 "@types/json-schema@7.0.15": ··· 2724 3363 integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==, 2725 3364 } 2726 3365 3366 + "@types/qs@6.15.0": 3367 + resolution: 3368 + { 3369 + integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==, 3370 + } 3371 + 3372 + "@types/range-parser@1.2.7": 3373 + resolution: 3374 + { 3375 + integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==, 3376 + } 3377 + 2727 3378 "@types/react-dom@19.2.3": 2728 3379 resolution: 2729 3380 { ··· 2736 3387 resolution: 2737 3388 { 2738 3389 integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==, 3390 + } 3391 + 3392 + "@types/send@1.2.1": 3393 + resolution: 3394 + { 3395 + integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==, 3396 + } 3397 + 3398 + "@types/serve-static@2.2.0": 3399 + resolution: 3400 + { 3401 + integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==, 2739 3402 } 2740 3403 2741 3404 "@types/statuses@2.0.6": ··· 2991 3654 cpu: [x64] 2992 3655 os: [win32] 2993 3656 3657 + "@vitest/expect@4.1.0": 3658 + resolution: 3659 + { 3660 + integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==, 3661 + } 3662 + 3663 + "@vitest/mocker@4.1.0": 3664 + resolution: 3665 + { 3666 + integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==, 3667 + } 3668 + peerDependencies: 3669 + msw: ^2.4.9 3670 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 3671 + peerDependenciesMeta: 3672 + msw: 3673 + optional: true 3674 + vite: 3675 + optional: true 3676 + 3677 + "@vitest/pretty-format@4.1.0": 3678 + resolution: 3679 + { 3680 + integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==, 3681 + } 3682 + 3683 + "@vitest/runner@4.1.0": 3684 + resolution: 3685 + { 3686 + integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==, 3687 + } 3688 + 3689 + "@vitest/snapshot@4.1.0": 3690 + resolution: 3691 + { 3692 + integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==, 3693 + } 3694 + 3695 + "@vitest/spy@4.1.0": 3696 + resolution: 3697 + { 3698 + integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==, 3699 + } 3700 + 3701 + "@vitest/utils@4.1.0": 3702 + resolution: 3703 + { 3704 + integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==, 3705 + } 3706 + 3707 + abort-controller@3.0.0: 3708 + resolution: 3709 + { 3710 + integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==, 3711 + } 3712 + engines: { node: ">=6.5" } 3713 + 2994 3714 accepts@2.0.0: 2995 3715 resolution: 2996 3716 { ··· 3086 3806 } 3087 3807 engines: { node: ">=14" } 3088 3808 3809 + any-promise@1.3.0: 3810 + resolution: 3811 + { 3812 + integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, 3813 + } 3814 + 3089 3815 argparse@2.0.1: 3090 3816 resolution: 3091 3817 { ··· 3162 3888 } 3163 3889 engines: { node: ">= 0.4" } 3164 3890 3891 + assertion-error@2.0.1: 3892 + resolution: 3893 + { 3894 + integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==, 3895 + } 3896 + engines: { node: ">=12" } 3897 + 3165 3898 ast-types-flow@0.0.8: 3166 3899 resolution: 3167 3900 { ··· 3181 3914 integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==, 3182 3915 } 3183 3916 engines: { node: ">= 0.4" } 3917 + 3918 + atomic-sleep@1.0.0: 3919 + resolution: 3920 + { 3921 + integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==, 3922 + } 3923 + engines: { node: ">=8.0.0" } 3184 3924 3185 3925 available-typed-arrays@1.0.7: 3186 3926 resolution: ··· 3274 4014 integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==, 3275 4015 } 3276 4016 4017 + brace-expansion@2.0.2: 4018 + resolution: 4019 + { 4020 + integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==, 4021 + } 4022 + 3277 4023 brace-expansion@5.0.3: 3278 4024 resolution: 3279 4025 { ··· 3302 4048 integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, 3303 4049 } 3304 4050 4051 + buffer@6.0.3: 4052 + resolution: 4053 + { 4054 + integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==, 4055 + } 4056 + 3305 4057 bundle-name@4.1.0: 3306 4058 resolution: 3307 4059 { ··· 3309 4061 } 3310 4062 engines: { node: ">=18" } 3311 4063 4064 + bundle-require@5.1.0: 4065 + resolution: 4066 + { 4067 + integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==, 4068 + } 4069 + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } 4070 + peerDependencies: 4071 + esbuild: ">=0.18" 4072 + 3312 4073 bytes@3.1.2: 3313 4074 resolution: 3314 4075 { ··· 3316 4077 } 3317 4078 engines: { node: ">= 0.8" } 3318 4079 4080 + cac@6.7.14: 4081 + resolution: 4082 + { 4083 + integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==, 4084 + } 4085 + engines: { node: ">=8" } 4086 + 3319 4087 call-bind-apply-helpers@1.0.2: 3320 4088 resolution: 3321 4089 { ··· 3350 4118 integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==, 3351 4119 } 3352 4120 4121 + cborg@1.10.2: 4122 + resolution: 4123 + { 4124 + integrity: sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug==, 4125 + } 4126 + hasBin: true 4127 + 4128 + chai@6.2.2: 4129 + resolution: 4130 + { 4131 + integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==, 4132 + } 4133 + engines: { node: ">=18" } 4134 + 3353 4135 chalk@4.1.2: 3354 4136 resolution: 3355 4137 { ··· 3364 4146 } 3365 4147 engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 } 3366 4148 4149 + chokidar@4.0.3: 4150 + resolution: 4151 + { 4152 + integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==, 4153 + } 4154 + engines: { node: ">= 14.16.0" } 4155 + 3367 4156 chownr@1.1.4: 3368 4157 resolution: 3369 4158 { ··· 3463 4252 } 3464 4253 engines: { node: ">=20" } 3465 4254 4255 + commander@4.1.1: 4256 + resolution: 4257 + { 4258 + integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, 4259 + } 4260 + engines: { node: ">= 6" } 4261 + 4262 + commander@9.5.0: 4263 + resolution: 4264 + { 4265 + integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==, 4266 + } 4267 + engines: { node: ^12.20.0 || >=14 } 4268 + 3466 4269 comment-parser@1.4.5: 3467 4270 resolution: 3468 4271 { ··· 3475 4278 { 3476 4279 integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, 3477 4280 } 4281 + 4282 + confbox@0.1.8: 4283 + resolution: 4284 + { 4285 + integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==, 4286 + } 4287 + 4288 + consola@3.4.2: 4289 + resolution: 4290 + { 4291 + integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==, 4292 + } 4293 + engines: { node: ^14.18.0 || >=16.10.0 } 3478 4294 3479 4295 content-disposition@1.0.1: 3480 4296 resolution: ··· 3852 4668 } 3853 4669 engines: { node: ">= 0.4" } 3854 4670 4671 + es-module-lexer@2.0.0: 4672 + resolution: 4673 + { 4674 + integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==, 4675 + } 4676 + 3855 4677 es-object-atoms@1.1.1: 3856 4678 resolution: 3857 4679 { ··· 4120 4942 } 4121 4943 engines: { node: ">=4.0" } 4122 4944 4945 + estree-walker@3.0.3: 4946 + resolution: 4947 + { 4948 + integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==, 4949 + } 4950 + 4123 4951 esutils@2.0.3: 4124 4952 resolution: 4125 4953 { ··· 4134 4962 } 4135 4963 engines: { node: ">= 0.6" } 4136 4964 4965 + event-target-shim@5.0.1: 4966 + resolution: 4967 + { 4968 + integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==, 4969 + } 4970 + engines: { node: ">=6" } 4971 + 4137 4972 eventemitter3@5.0.4: 4138 4973 resolution: 4139 4974 { 4140 4975 integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==, 4141 4976 } 4142 4977 4978 + events@3.3.0: 4979 + resolution: 4980 + { 4981 + integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, 4982 + } 4983 + engines: { node: ">=0.8.x" } 4984 + 4143 4985 eventsource-parser@3.0.6: 4144 4986 resolution: 4145 4987 { ··· 4175 5017 } 4176 5018 engines: { node: ">=6" } 4177 5019 5020 + expect-type@1.3.0: 5021 + resolution: 5022 + { 5023 + integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==, 5024 + } 5025 + engines: { node: ">=12.0.0" } 5026 + 4178 5027 express-rate-limit@8.3.0: 4179 5028 resolution: 4180 5029 { ··· 4222 5071 { 4223 5072 integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, 4224 5073 } 5074 + 5075 + fast-redact@3.5.0: 5076 + resolution: 5077 + { 5078 + integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==, 5079 + } 5080 + engines: { node: ">=6" } 4225 5081 4226 5082 fast-uri@3.1.0: 4227 5083 resolution: ··· 4301 5157 } 4302 5158 engines: { node: ">=10" } 4303 5159 5160 + fix-dts-default-cjs-exports@1.0.1: 5161 + resolution: 5162 + { 5163 + integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==, 5164 + } 5165 + 4304 5166 flat-cache@4.0.1: 4305 5167 resolution: 4306 5168 { ··· 5086 5948 integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==, 5087 5949 } 5088 5950 5951 + joycon@3.1.1: 5952 + resolution: 5953 + { 5954 + integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, 5955 + } 5956 + engines: { node: ">=10" } 5957 + 5089 5958 js-tokens@4.0.0: 5090 5959 resolution: 5091 5960 { ··· 5238 6107 cpu: [arm64] 5239 6108 os: [android] 5240 6109 6110 + lightningcss-android-arm64@1.32.0: 6111 + resolution: 6112 + { 6113 + integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==, 6114 + } 6115 + engines: { node: ">= 12.0.0" } 6116 + cpu: [arm64] 6117 + os: [android] 6118 + 5241 6119 lightningcss-darwin-arm64@1.31.1: 5242 6120 resolution: 5243 6121 { ··· 5247 6125 cpu: [arm64] 5248 6126 os: [darwin] 5249 6127 6128 + lightningcss-darwin-arm64@1.32.0: 6129 + resolution: 6130 + { 6131 + integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==, 6132 + } 6133 + engines: { node: ">= 12.0.0" } 6134 + cpu: [arm64] 6135 + os: [darwin] 6136 + 5250 6137 lightningcss-darwin-x64@1.31.1: 5251 6138 resolution: 5252 6139 { ··· 5256 6143 cpu: [x64] 5257 6144 os: [darwin] 5258 6145 6146 + lightningcss-darwin-x64@1.32.0: 6147 + resolution: 6148 + { 6149 + integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==, 6150 + } 6151 + engines: { node: ">= 12.0.0" } 6152 + cpu: [x64] 6153 + os: [darwin] 6154 + 5259 6155 lightningcss-freebsd-x64@1.31.1: 5260 6156 resolution: 5261 6157 { ··· 5265 6161 cpu: [x64] 5266 6162 os: [freebsd] 5267 6163 6164 + lightningcss-freebsd-x64@1.32.0: 6165 + resolution: 6166 + { 6167 + integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==, 6168 + } 6169 + engines: { node: ">= 12.0.0" } 6170 + cpu: [x64] 6171 + os: [freebsd] 6172 + 5268 6173 lightningcss-linux-arm-gnueabihf@1.31.1: 5269 6174 resolution: 5270 6175 { ··· 5274 6179 cpu: [arm] 5275 6180 os: [linux] 5276 6181 6182 + lightningcss-linux-arm-gnueabihf@1.32.0: 6183 + resolution: 6184 + { 6185 + integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==, 6186 + } 6187 + engines: { node: ">= 12.0.0" } 6188 + cpu: [arm] 6189 + os: [linux] 6190 + 5277 6191 lightningcss-linux-arm64-gnu@1.31.1: 5278 6192 resolution: 5279 6193 { ··· 5283 6197 cpu: [arm64] 5284 6198 os: [linux] 5285 6199 6200 + lightningcss-linux-arm64-gnu@1.32.0: 6201 + resolution: 6202 + { 6203 + integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==, 6204 + } 6205 + engines: { node: ">= 12.0.0" } 6206 + cpu: [arm64] 6207 + os: [linux] 6208 + 5286 6209 lightningcss-linux-arm64-musl@1.31.1: 5287 6210 resolution: 5288 6211 { 5289 6212 integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==, 6213 + } 6214 + engines: { node: ">= 12.0.0" } 6215 + cpu: [arm64] 6216 + os: [linux] 6217 + 6218 + lightningcss-linux-arm64-musl@1.32.0: 6219 + resolution: 6220 + { 6221 + integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==, 5290 6222 } 5291 6223 engines: { node: ">= 12.0.0" } 5292 6224 cpu: [arm64] ··· 5301 6233 cpu: [x64] 5302 6234 os: [linux] 5303 6235 6236 + lightningcss-linux-x64-gnu@1.32.0: 6237 + resolution: 6238 + { 6239 + integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==, 6240 + } 6241 + engines: { node: ">= 12.0.0" } 6242 + cpu: [x64] 6243 + os: [linux] 6244 + 5304 6245 lightningcss-linux-x64-musl@1.31.1: 5305 6246 resolution: 5306 6247 { ··· 5310 6251 cpu: [x64] 5311 6252 os: [linux] 5312 6253 6254 + lightningcss-linux-x64-musl@1.32.0: 6255 + resolution: 6256 + { 6257 + integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==, 6258 + } 6259 + engines: { node: ">= 12.0.0" } 6260 + cpu: [x64] 6261 + os: [linux] 6262 + 5313 6263 lightningcss-win32-arm64-msvc@1.31.1: 5314 6264 resolution: 5315 6265 { ··· 5319 6269 cpu: [arm64] 5320 6270 os: [win32] 5321 6271 6272 + lightningcss-win32-arm64-msvc@1.32.0: 6273 + resolution: 6274 + { 6275 + integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==, 6276 + } 6277 + engines: { node: ">= 12.0.0" } 6278 + cpu: [arm64] 6279 + os: [win32] 6280 + 5322 6281 lightningcss-win32-x64-msvc@1.31.1: 5323 6282 resolution: 5324 6283 { ··· 5328 6287 cpu: [x64] 5329 6288 os: [win32] 5330 6289 6290 + lightningcss-win32-x64-msvc@1.32.0: 6291 + resolution: 6292 + { 6293 + integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==, 6294 + } 6295 + engines: { node: ">= 12.0.0" } 6296 + cpu: [x64] 6297 + os: [win32] 6298 + 5331 6299 lightningcss@1.31.1: 5332 6300 resolution: 5333 6301 { ··· 5335 6303 } 5336 6304 engines: { node: ">= 12.0.0" } 5337 6305 6306 + lightningcss@1.32.0: 6307 + resolution: 6308 + { 6309 + integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==, 6310 + } 6311 + engines: { node: ">= 12.0.0" } 6312 + 6313 + lilconfig@3.1.3: 6314 + resolution: 6315 + { 6316 + integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==, 6317 + } 6318 + engines: { node: ">=14" } 6319 + 5338 6320 lines-and-columns@1.2.4: 5339 6321 resolution: 5340 6322 { ··· 5355 6337 integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==, 5356 6338 } 5357 6339 engines: { node: ">=20.0.0" } 6340 + 6341 + load-tsconfig@0.2.5: 6342 + resolution: 6343 + { 6344 + integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==, 6345 + } 6346 + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } 5358 6347 5359 6348 locate-path@6.0.0: 5360 6349 resolution: ··· 5505 6494 integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==, 5506 6495 } 5507 6496 6497 + minimatch@9.0.9: 6498 + resolution: 6499 + { 6500 + integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==, 6501 + } 6502 + engines: { node: ">=16 || 14 >=14.17" } 6503 + 5508 6504 minimist@1.2.8: 5509 6505 resolution: 5510 6506 { ··· 5517 6513 integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==, 5518 6514 } 5519 6515 6516 + mlly@1.8.2: 6517 + resolution: 6518 + { 6519 + integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==, 6520 + } 6521 + 5520 6522 ms@2.1.3: 5521 6523 resolution: 5522 6524 { ··· 5554 6556 integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==, 5555 6557 } 5556 6558 engines: { node: ^18.17.0 || >=20.5.0 } 6559 + 6560 + mz@2.7.0: 6561 + resolution: 6562 + { 6563 + integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, 6564 + } 5557 6565 5558 6566 nano-spawn@2.0.0: 5559 6567 resolution: ··· 5742 6750 } 5743 6751 engines: { node: ">= 0.4" } 5744 6752 6753 + obug@2.1.1: 6754 + resolution: 6755 + { 6756 + integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==, 6757 + } 6758 + 6759 + on-exit-leak-free@2.1.2: 6760 + resolution: 6761 + { 6762 + integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==, 6763 + } 6764 + engines: { node: ">=14.0.0" } 6765 + 5745 6766 on-finished@2.4.1: 5746 6767 resolution: 5747 6768 { ··· 5902 6923 integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==, 5903 6924 } 5904 6925 6926 + pathe@2.0.3: 6927 + resolution: 6928 + { 6929 + integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, 6930 + } 6931 + 5905 6932 picocolors@1.1.1: 5906 6933 resolution: 5907 6934 { ··· 5930 6957 engines: { node: ">=0.10" } 5931 6958 hasBin: true 5932 6959 6960 + pino-abstract-transport@1.2.0: 6961 + resolution: 6962 + { 6963 + integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==, 6964 + } 6965 + 6966 + pino-std-serializers@6.2.2: 6967 + resolution: 6968 + { 6969 + integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==, 6970 + } 6971 + 6972 + pino@8.21.0: 6973 + resolution: 6974 + { 6975 + integrity: sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==, 6976 + } 6977 + hasBin: true 6978 + 6979 + pirates@4.0.7: 6980 + resolution: 6981 + { 6982 + integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, 6983 + } 6984 + engines: { node: ">= 6" } 6985 + 5933 6986 pkce-challenge@5.0.1: 5934 6987 resolution: 5935 6988 { ··· 5937 6990 } 5938 6991 engines: { node: ">=16.20.0" } 5939 6992 6993 + pkg-types@1.3.1: 6994 + resolution: 6995 + { 6996 + integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==, 6997 + } 6998 + 5940 6999 possible-typed-array-names@1.1.0: 5941 7000 resolution: 5942 7001 { ··· 5944 7003 } 5945 7004 engines: { node: ">= 0.4" } 5946 7005 7006 + postcss-load-config@6.0.1: 7007 + resolution: 7008 + { 7009 + integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==, 7010 + } 7011 + engines: { node: ">= 18" } 7012 + peerDependencies: 7013 + jiti: ">=1.21.0" 7014 + postcss: ">=8.0.9" 7015 + tsx: ^4.8.1 7016 + yaml: ^2.4.2 7017 + peerDependenciesMeta: 7018 + jiti: 7019 + optional: true 7020 + postcss: 7021 + optional: true 7022 + tsx: 7023 + optional: true 7024 + yaml: 7025 + optional: true 7026 + 5947 7027 postcss-selector-parser@7.1.1: 5948 7028 resolution: 5949 7029 { ··· 5962 7042 resolution: 5963 7043 { 5964 7044 integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==, 7045 + } 7046 + engines: { node: ^10 || ^12 || >=14 } 7047 + 7048 + postcss@8.5.8: 7049 + resolution: 7050 + { 7051 + integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==, 5965 7052 } 5966 7053 engines: { node: ^10 || ^12 || >=14 } 5967 7054 ··· 6003 7090 } 6004 7091 engines: { node: ">=18" } 6005 7092 7093 + process-warning@3.0.0: 7094 + resolution: 7095 + { 7096 + integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==, 7097 + } 7098 + 7099 + process@0.11.10: 7100 + resolution: 7101 + { 7102 + integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==, 7103 + } 7104 + engines: { node: ">= 0.6.0" } 7105 + 6006 7106 prompts@2.4.2: 6007 7107 resolution: 6008 7108 { ··· 6047 7147 resolution: 6048 7148 { 6049 7149 integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, 7150 + } 7151 + 7152 + quick-format-unescaped@4.0.4: 7153 + resolution: 7154 + { 7155 + integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==, 6050 7156 } 6051 7157 6052 7158 radix-ui@1.4.3: ··· 6162 7268 } 6163 7269 engines: { node: ">= 6" } 6164 7270 7271 + readable-stream@4.7.0: 7272 + resolution: 7273 + { 7274 + integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==, 7275 + } 7276 + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } 7277 + 7278 + readdirp@4.1.2: 7279 + resolution: 7280 + { 7281 + integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==, 7282 + } 7283 + engines: { node: ">= 14.18.0" } 7284 + 7285 + real-require@0.2.0: 7286 + resolution: 7287 + { 7288 + integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==, 7289 + } 7290 + engines: { node: ">= 12.13.0" } 7291 + 6165 7292 recast@0.23.11: 6166 7293 resolution: 6167 7294 { ··· 6204 7331 } 6205 7332 engines: { node: ">=4" } 6206 7333 7334 + resolve-from@5.0.0: 7335 + resolution: 7336 + { 7337 + integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, 7338 + } 7339 + engines: { node: ">=8" } 7340 + 6207 7341 resolve-pkg-maps@1.0.0: 6208 7342 resolution: 6209 7343 { ··· 6252 7386 integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==, 6253 7387 } 6254 7388 7389 + rolldown@1.0.0-rc.10: 7390 + resolution: 7391 + { 7392 + integrity: sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA==, 7393 + } 7394 + engines: { node: ^20.19.0 || >=22.12.0 } 7395 + hasBin: true 7396 + 7397 + rollup@4.59.1: 7398 + resolution: 7399 + { 7400 + integrity: sha512-iZKH8BeoCwTCBTZBZWQQMreekd4mdomwdjIQ40GC1oZm6o+8PnNMIxFOiCsGMWeS8iDJ7KZcl7KwmKk/0HOQpA==, 7401 + } 7402 + engines: { node: ">=18.0.0", npm: ">=8.0.0" } 7403 + hasBin: true 7404 + 6255 7405 router@2.2.0: 6256 7406 resolution: 6257 7407 { ··· 6298 7448 integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==, 6299 7449 } 6300 7450 engines: { node: ">= 0.4" } 7451 + 7452 + safe-stable-stringify@2.5.0: 7453 + resolution: 7454 + { 7455 + integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==, 7456 + } 7457 + engines: { node: ">=10" } 6301 7458 6302 7459 safer-buffer@2.1.2: 6303 7460 resolution: ··· 6423 7580 } 6424 7581 engines: { node: ">= 0.4" } 6425 7582 7583 + siginfo@2.0.0: 7584 + resolution: 7585 + { 7586 + integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==, 7587 + } 7588 + 6426 7589 signal-exit@3.0.7: 6427 7590 resolution: 6428 7591 { ··· 6468 7631 } 6469 7632 engines: { node: ">= 18" } 6470 7633 7634 + sonic-boom@3.8.1: 7635 + resolution: 7636 + { 7637 + integrity: sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==, 7638 + } 7639 + 6471 7640 sonner@2.0.7: 6472 7641 resolution: 6473 7642 { ··· 6490 7659 integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, 6491 7660 } 6492 7661 engines: { node: ">=0.10.0" } 7662 + 7663 + source-map@0.7.6: 7664 + resolution: 7665 + { 7666 + integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==, 7667 + } 7668 + engines: { node: ">= 12" } 7669 + 7670 + split2@4.2.0: 7671 + resolution: 7672 + { 7673 + integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==, 7674 + } 7675 + engines: { node: ">= 10.x" } 6493 7676 6494 7677 stable-hash-x@0.2.0: 6495 7678 resolution: ··· 6504 7687 integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==, 6505 7688 } 6506 7689 7690 + stackback@0.0.2: 7691 + resolution: 7692 + { 7693 + integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, 7694 + } 7695 + 6507 7696 statuses@2.0.2: 6508 7697 resolution: 6509 7698 { 6510 7699 integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==, 6511 7700 } 6512 7701 engines: { node: ">= 0.8" } 7702 + 7703 + std-env@4.0.0: 7704 + resolution: 7705 + { 7706 + integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==, 7707 + } 6513 7708 6514 7709 stdin-discarder@0.2.2: 6515 7710 resolution: ··· 6685 7880 babel-plugin-macros: 6686 7881 optional: true 6687 7882 7883 + sucrase@3.35.1: 7884 + resolution: 7885 + { 7886 + integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==, 7887 + } 7888 + engines: { node: ">=16 || 14 >=14.17" } 7889 + hasBin: true 7890 + 6688 7891 supports-color@7.2.0: 6689 7892 resolution: 6690 7893 { ··· 6738 7941 } 6739 7942 engines: { node: ">=6" } 6740 7943 7944 + thenify-all@1.6.0: 7945 + resolution: 7946 + { 7947 + integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, 7948 + } 7949 + engines: { node: ">=0.8" } 7950 + 7951 + thenify@3.3.1: 7952 + resolution: 7953 + { 7954 + integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, 7955 + } 7956 + 7957 + thread-stream@2.7.0: 7958 + resolution: 7959 + { 7960 + integrity: sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==, 7961 + } 7962 + 6741 7963 tiny-invariant@1.3.3: 6742 7964 resolution: 6743 7965 { 6744 7966 integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==, 6745 7967 } 6746 7968 7969 + tinybench@2.9.0: 7970 + resolution: 7971 + { 7972 + integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==, 7973 + } 7974 + 7975 + tinyexec@0.3.2: 7976 + resolution: 7977 + { 7978 + integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==, 7979 + } 7980 + 6747 7981 tinyexec@1.0.2: 6748 7982 resolution: 6749 7983 { ··· 6758 7992 } 6759 7993 engines: { node: ">=12.0.0" } 6760 7994 7995 + tinyrainbow@3.1.0: 7996 + resolution: 7997 + { 7998 + integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==, 7999 + } 8000 + engines: { node: ">=14.0.0" } 8001 + 6761 8002 tlds@1.261.0: 6762 8003 resolution: 6763 8004 { ··· 6799 8040 } 6800 8041 engines: { node: ">=16" } 6801 8042 8043 + tree-kill@1.2.2: 8044 + resolution: 8045 + { 8046 + integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==, 8047 + } 8048 + hasBin: true 8049 + 6802 8050 ts-api-utils@2.4.0: 6803 8051 resolution: 6804 8052 { ··· 6808 8056 peerDependencies: 6809 8057 typescript: ">=4.8.4" 6810 8058 8059 + ts-interface-checker@0.1.13: 8060 + resolution: 8061 + { 8062 + integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, 8063 + } 8064 + 8065 + ts-morph@24.0.0: 8066 + resolution: 8067 + { 8068 + integrity: sha512-2OAOg/Ob5yx9Et7ZX4CvTCc0UFoZHwLEJ+dpDPSUi5TgwwlTlX47w+iFRrEwzUZwYACjq83cgjS/Da50Ga37uw==, 8069 + } 8070 + 6811 8071 ts-morph@26.0.0: 6812 8072 resolution: 6813 8073 { 6814 8074 integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==, 6815 8075 } 6816 8076 8077 + ts-morph@27.0.2: 8078 + resolution: 8079 + { 8080 + integrity: sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w==, 8081 + } 8082 + 6817 8083 tsconfig-paths@3.15.0: 6818 8084 resolution: 6819 8085 { ··· 6832 8098 { 6833 8099 integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, 6834 8100 } 8101 + 8102 + tsup@8.5.1: 8103 + resolution: 8104 + { 8105 + integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==, 8106 + } 8107 + engines: { node: ">=18" } 8108 + hasBin: true 8109 + peerDependencies: 8110 + "@microsoft/api-extractor": ^7.36.0 8111 + "@swc/core": ^1 8112 + postcss: ^8.4.12 8113 + typescript: ">=4.5.0" 8114 + peerDependenciesMeta: 8115 + "@microsoft/api-extractor": 8116 + optional: true 8117 + "@swc/core": 8118 + optional: true 8119 + postcss: 8120 + optional: true 8121 + typescript: 8122 + optional: true 6835 8123 6836 8124 tsx@4.21.0: 6837 8125 resolution: ··· 6927 8215 engines: { node: ">=14.17" } 6928 8216 hasBin: true 6929 8217 8218 + ufo@1.6.3: 8219 + resolution: 8220 + { 8221 + integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==, 8222 + } 8223 + 6930 8224 uint8arrays@3.0.0: 6931 8225 resolution: 6932 8226 { ··· 7061 8355 } 7062 8356 engines: { node: ^20.17.0 || >=22.9.0 } 7063 8357 8358 + varint@6.0.0: 8359 + resolution: 8360 + { 8361 + integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==, 8362 + } 8363 + 7064 8364 vary@1.1.2: 7065 8365 resolution: 7066 8366 { ··· 7068 8368 } 7069 8369 engines: { node: ">= 0.8" } 7070 8370 8371 + vite@8.0.1: 8372 + resolution: 8373 + { 8374 + integrity: sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==, 8375 + } 8376 + engines: { node: ^20.19.0 || >=22.12.0 } 8377 + hasBin: true 8378 + peerDependencies: 8379 + "@types/node": ^20.19.0 || >=22.12.0 8380 + "@vitejs/devtools": ^0.1.0 8381 + esbuild: ^0.27.0 8382 + jiti: ">=1.21.0" 8383 + less: ^4.0.0 8384 + sass: ^1.70.0 8385 + sass-embedded: ^1.70.0 8386 + stylus: ">=0.54.8" 8387 + sugarss: ^5.0.0 8388 + terser: ^5.16.0 8389 + tsx: ^4.8.1 8390 + yaml: ^2.4.2 8391 + peerDependenciesMeta: 8392 + "@types/node": 8393 + optional: true 8394 + "@vitejs/devtools": 8395 + optional: true 8396 + esbuild: 8397 + optional: true 8398 + jiti: 8399 + optional: true 8400 + less: 8401 + optional: true 8402 + sass: 8403 + optional: true 8404 + sass-embedded: 8405 + optional: true 8406 + stylus: 8407 + optional: true 8408 + sugarss: 8409 + optional: true 8410 + terser: 8411 + optional: true 8412 + tsx: 8413 + optional: true 8414 + yaml: 8415 + optional: true 8416 + 8417 + vitest@4.1.0: 8418 + resolution: 8419 + { 8420 + integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==, 8421 + } 8422 + engines: { node: ^20.0.0 || ^22.0.0 || >=24.0.0 } 8423 + hasBin: true 8424 + peerDependencies: 8425 + "@edge-runtime/vm": "*" 8426 + "@opentelemetry/api": ^1.9.0 8427 + "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 8428 + "@vitest/browser-playwright": 4.1.0 8429 + "@vitest/browser-preview": 4.1.0 8430 + "@vitest/browser-webdriverio": 4.1.0 8431 + "@vitest/ui": 4.1.0 8432 + happy-dom: "*" 8433 + jsdom: "*" 8434 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 8435 + peerDependenciesMeta: 8436 + "@edge-runtime/vm": 8437 + optional: true 8438 + "@opentelemetry/api": 8439 + optional: true 8440 + "@types/node": 8441 + optional: true 8442 + "@vitest/browser-playwright": 8443 + optional: true 8444 + "@vitest/browser-preview": 8445 + optional: true 8446 + "@vitest/browser-webdriverio": 8447 + optional: true 8448 + "@vitest/ui": 8449 + optional: true 8450 + happy-dom: 8451 + optional: true 8452 + jsdom: 8453 + optional: true 8454 + 7071 8455 walk-up-path@4.0.0: 7072 8456 resolution: 7073 8457 { ··· 7126 8510 engines: { node: ^16.13.0 || >=18.0.0 } 7127 8511 hasBin: true 7128 8512 8513 + why-is-node-running@2.3.0: 8514 + resolution: 8515 + { 8516 + integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==, 8517 + } 8518 + engines: { node: ">=8" } 8519 + hasBin: true 8520 + 7129 8521 word-wrap@1.2.5: 7130 8522 resolution: 7131 8523 { ··· 7160 8552 integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, 7161 8553 } 7162 8554 8555 + ws@8.20.0: 8556 + resolution: 8557 + { 8558 + integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==, 8559 + } 8560 + engines: { node: ">=10.0.0" } 8561 + peerDependencies: 8562 + bufferutil: ^4.0.1 8563 + utf-8-validate: ">=5.0.2" 8564 + peerDependenciesMeta: 8565 + bufferutil: 8566 + optional: true 8567 + utf-8-validate: 8568 + optional: true 8569 + 7163 8570 wsl-utils@0.3.1: 7164 8571 resolution: 7165 8572 { ··· 7202 8609 } 7203 8610 engines: { node: ">=12" } 7204 8611 8612 + yesno@0.4.0: 8613 + resolution: 8614 + { 8615 + integrity: sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA==, 8616 + } 8617 + 7205 8618 yocto-queue@0.1.0: 7206 8619 resolution: 7207 8620 { ··· 7229 8642 integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==, 7230 8643 } 7231 8644 peerDependencies: 7232 - zod: ^3.25 || ^4 8645 + zod: 4.3.6 7233 8646 7234 8647 zod-validation-error@4.0.2: 7235 8648 resolution: ··· 7238 8651 } 7239 8652 engines: { node: ">=18.0.0" } 7240 8653 peerDependencies: 7241 - zod: ^3.25.0 || ^4.0.0 7242 - 7243 - zod@3.25.76: 7244 - resolution: 7245 - { 7246 - integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, 7247 - } 8654 + zod: 4.3.6 7248 8655 7249 8656 zod@4.3.6: 7250 8657 resolution: ··· 7283 8690 package-manager-detector: 1.6.0 7284 8691 tinyexec: 1.0.2 7285 8692 8693 + "@atproto-labs/did-resolver@0.2.5": 8694 + dependencies: 8695 + "@atproto-labs/fetch": 0.2.3 8696 + "@atproto-labs/pipe": 0.1.1 8697 + "@atproto-labs/simple-store": 0.3.0 8698 + "@atproto-labs/simple-store-memory": 0.1.4 8699 + "@atproto/did": 0.2.4 8700 + zod: 4.3.6 8701 + 7286 8702 "@atproto-labs/did-resolver@0.2.6": 7287 8703 dependencies: 7288 8704 "@atproto-labs/fetch": 0.2.3 ··· 7290 8706 "@atproto-labs/simple-store": 0.3.0 7291 8707 "@atproto-labs/simple-store-memory": 0.1.4 7292 8708 "@atproto/did": 0.3.0 7293 - zod: 3.25.76 8709 + zod: 4.3.6 7294 8710 7295 8711 "@atproto-labs/fetch-node@0.2.0": 7296 8712 dependencies: ··· 7314 8730 "@atproto-labs/simple-store": 0.3.0 7315 8731 "@atproto-labs/simple-store-memory": 0.1.4 7316 8732 "@atproto/did": 0.3.0 7317 - zod: 3.25.76 8733 + zod: 4.3.6 7318 8734 7319 8735 "@atproto-labs/identity-resolver@0.3.6": 7320 8736 dependencies: ··· 7339 8755 await-lock: 2.2.2 7340 8756 multiformats: 9.9.0 7341 8757 tlds: 1.261.0 7342 - zod: 3.25.76 8758 + zod: 4.3.6 7343 8759 7344 8760 "@atproto/common-web@0.4.18": 7345 8761 dependencies: 7346 8762 "@atproto/lex-data": 0.0.13 7347 8763 "@atproto/lex-json": 0.0.13 7348 - "@atproto/syntax": 0.5.0 7349 - zod: 3.25.76 8764 + "@atproto/syntax": 0.5.1 8765 + zod: 4.3.6 8766 + 8767 + "@atproto/common-web@0.4.19": 8768 + dependencies: 8769 + "@atproto/lex-data": 0.0.14 8770 + "@atproto/lex-json": 0.0.14 8771 + "@atproto/syntax": 0.5.1 8772 + zod: 4.3.6 8773 + 8774 + "@atproto/common@0.5.15": 8775 + dependencies: 8776 + "@atproto/common-web": 0.4.19 8777 + "@atproto/lex-cbor": 0.0.15 8778 + "@atproto/lex-data": 0.0.14 8779 + multiformats: 9.9.0 8780 + pino: 8.21.0 7350 8781 7351 8782 "@atproto/crypto@0.4.5": 7352 8783 dependencies: ··· 7354 8785 "@noble/hashes": 1.8.0 7355 8786 uint8arrays: 3.0.0 7356 8787 8788 + "@atproto/did@0.2.4": 8789 + dependencies: 8790 + zod: 4.3.6 8791 + 7357 8792 "@atproto/did@0.3.0": 7358 8793 dependencies: 7359 - zod: 3.25.76 8794 + zod: 4.3.6 7360 8795 7361 8796 "@atproto/identity@0.4.12": 7362 8797 dependencies: ··· 7372 8807 dependencies: 7373 8808 "@atproto/jwk": 0.6.0 7374 8809 "@atproto/jwk-jose": 0.1.11 7375 - zod: 3.25.76 8810 + zod: 4.3.6 7376 8811 7377 8812 "@atproto/jwk@0.6.0": 7378 8813 dependencies: 7379 8814 multiformats: 9.9.0 7380 - zod: 3.25.76 8815 + zod: 4.3.6 8816 + 8817 + "@atproto/lex-builder@0.0.11": 8818 + dependencies: 8819 + "@atproto/lex-document": 0.0.10 8820 + "@atproto/lex-schema": 0.0.9 8821 + prettier: 3.8.1 8822 + ts-morph: 27.0.2 8823 + tslib: 2.8.1 8824 + 8825 + "@atproto/lex-cbor@0.0.15": 8826 + dependencies: 8827 + "@atproto/lex-data": 0.0.14 8828 + tslib: 2.8.1 8829 + 8830 + "@atproto/lex-cbor@0.0.8": 8831 + dependencies: 8832 + "@atproto/lex-data": 0.0.8 8833 + tslib: 2.8.1 8834 + 8835 + "@atproto/lex-cli@0.9.9": 8836 + dependencies: 8837 + "@atproto/lexicon": 0.6.2 8838 + "@atproto/syntax": 0.5.1 8839 + chalk: 4.1.2 8840 + commander: 9.5.0 8841 + prettier: 3.8.1 8842 + ts-morph: 24.0.0 8843 + yesno: 0.4.0 8844 + zod: 4.3.6 8845 + 8846 + "@atproto/lex-client@0.0.9": 8847 + dependencies: 8848 + "@atproto/lex-data": 0.0.8 8849 + "@atproto/lex-json": 0.0.8 8850 + "@atproto/lex-schema": 0.0.9 8851 + tslib: 2.8.1 7381 8852 7382 8853 "@atproto/lex-data@0.0.13": 7383 8854 dependencies: ··· 7386 8857 uint8arrays: 3.0.0 7387 8858 unicode-segmenter: 0.14.5 7388 8859 8860 + "@atproto/lex-data@0.0.14": 8861 + dependencies: 8862 + multiformats: 9.9.0 8863 + tslib: 2.8.1 8864 + uint8arrays: 3.0.0 8865 + unicode-segmenter: 0.14.5 8866 + 8867 + "@atproto/lex-data@0.0.8": 8868 + dependencies: 8869 + "@atproto/syntax": 0.4.2 8870 + multiformats: 9.9.0 8871 + tslib: 2.8.1 8872 + uint8arrays: 3.0.0 8873 + unicode-segmenter: 0.14.5 8874 + 8875 + "@atproto/lex-document@0.0.10": 8876 + dependencies: 8877 + "@atproto/lex-schema": 0.0.9 8878 + core-js: 3.48.0 8879 + tslib: 2.8.1 8880 + 8881 + "@atproto/lex-installer@0.0.11": 8882 + dependencies: 8883 + "@atproto/lex-builder": 0.0.11 8884 + "@atproto/lex-cbor": 0.0.8 8885 + "@atproto/lex-data": 0.0.8 8886 + "@atproto/lex-document": 0.0.10 8887 + "@atproto/lex-resolver": 0.0.10 8888 + "@atproto/lex-schema": 0.0.9 8889 + "@atproto/syntax": 0.4.2 8890 + tslib: 2.8.1 8891 + 7389 8892 "@atproto/lex-json@0.0.13": 7390 8893 dependencies: 7391 8894 "@atproto/lex-data": 0.0.13 7392 8895 tslib: 2.8.1 7393 8896 8897 + "@atproto/lex-json@0.0.14": 8898 + dependencies: 8899 + "@atproto/lex-data": 0.0.14 8900 + tslib: 2.8.1 8901 + 8902 + "@atproto/lex-json@0.0.8": 8903 + dependencies: 8904 + "@atproto/lex-data": 0.0.8 8905 + tslib: 2.8.1 8906 + 8907 + "@atproto/lex-resolver@0.0.10": 8908 + dependencies: 8909 + "@atproto-labs/did-resolver": 0.2.5 8910 + "@atproto/crypto": 0.4.5 8911 + "@atproto/lex-client": 0.0.9 8912 + "@atproto/lex-data": 0.0.8 8913 + "@atproto/lex-document": 0.0.10 8914 + "@atproto/lex-schema": 0.0.9 8915 + "@atproto/repo": 0.8.12 8916 + "@atproto/syntax": 0.4.2 8917 + tslib: 2.8.1 8918 + 8919 + "@atproto/lex-schema@0.0.9": 8920 + dependencies: 8921 + "@atproto/lex-data": 0.0.8 8922 + "@atproto/syntax": 0.4.2 8923 + tslib: 2.8.1 8924 + 8925 + "@atproto/lex@0.0.11": 8926 + dependencies: 8927 + "@atproto/lex-builder": 0.0.11 8928 + "@atproto/lex-client": 0.0.9 8929 + "@atproto/lex-data": 0.0.8 8930 + "@atproto/lex-installer": 0.0.11 8931 + "@atproto/lex-json": 0.0.8 8932 + "@atproto/lex-schema": 0.0.9 8933 + tslib: 2.8.1 8934 + yargs: 17.7.2 8935 + 7394 8936 "@atproto/lexicon@0.6.1": 7395 8937 dependencies: 7396 8938 "@atproto/common-web": 0.4.18 7397 8939 "@atproto/syntax": 0.4.3 7398 8940 iso-datestring-validator: 2.2.2 7399 8941 multiformats: 9.9.0 7400 - zod: 3.25.76 8942 + zod: 4.3.6 8943 + 8944 + "@atproto/lexicon@0.6.2": 8945 + dependencies: 8946 + "@atproto/common-web": 0.4.19 8947 + "@atproto/syntax": 0.5.1 8948 + iso-datestring-validator: 2.2.2 8949 + multiformats: 9.9.0 8950 + zod: 4.3.6 7401 8951 7402 8952 "@atproto/oauth-client-node@0.3.17": 7403 8953 dependencies: ··· 7425 8975 "@atproto/xrpc": 0.7.7 7426 8976 core-js: 3.48.0 7427 8977 multiformats: 9.9.0 7428 - zod: 3.25.76 8978 + zod: 4.3.6 7429 8979 7430 8980 "@atproto/oauth-types@0.6.3": 7431 8981 dependencies: 7432 8982 "@atproto/did": 0.3.0 7433 8983 "@atproto/jwk": 0.6.0 7434 - zod: 3.25.76 8984 + zod: 4.3.6 8985 + 8986 + "@atproto/repo@0.8.12": 8987 + dependencies: 8988 + "@atproto/common": 0.5.15 8989 + "@atproto/common-web": 0.4.18 8990 + "@atproto/crypto": 0.4.5 8991 + "@atproto/lexicon": 0.6.1 8992 + "@ipld/dag-cbor": 7.0.3 8993 + multiformats: 9.9.0 8994 + uint8arrays: 3.0.0 8995 + varint: 6.0.0 8996 + zod: 4.3.6 8997 + 8998 + "@atproto/syntax@0.3.4": {} 8999 + 9000 + "@atproto/syntax@0.4.2": {} 7435 9001 7436 9002 "@atproto/syntax@0.4.3": 7437 9003 dependencies: 7438 9004 tslib: 2.8.1 7439 9005 7440 - "@atproto/syntax@0.5.0": 9006 + "@atproto/syntax@0.5.1": 7441 9007 dependencies: 7442 9008 tslib: 2.8.1 7443 9009 9010 + "@atproto/tap@0.1.3": 9011 + dependencies: 9012 + "@atproto/common": 0.5.15 9013 + "@atproto/lex": 0.0.11 9014 + "@atproto/syntax": 0.4.3 9015 + "@atproto/ws-client": 0.0.4 9016 + ws: 8.20.0 9017 + zod: 4.3.6 9018 + transitivePeerDependencies: 9019 + - bufferutil 9020 + - utf-8-validate 9021 + 9022 + "@atproto/ws-client@0.0.4": 9023 + dependencies: 9024 + "@atproto/common": 0.5.15 9025 + ws: 8.20.0 9026 + transitivePeerDependencies: 9027 + - bufferutil 9028 + - utf-8-validate 9029 + 7444 9030 "@atproto/xrpc@0.7.7": 7445 9031 dependencies: 7446 9032 "@atproto/lexicon": 0.6.1 7447 - zod: 3.25.76 9033 + zod: 4.3.6 7448 9034 7449 9035 "@babel/code-frame@7.29.0": 7450 9036 dependencies: ··· 7950 9536 optionalDependencies: 7951 9537 "@types/node": 20.19.37 7952 9538 9539 + "@ipld/dag-cbor@7.0.3": 9540 + dependencies: 9541 + cborg: 1.10.2 9542 + multiformats: 9.9.0 9543 + 7953 9544 "@jridgewell/gen-mapping@0.3.13": 7954 9545 dependencies: 7955 9546 "@jridgewell/sourcemap-codec": 1.5.5 ··· 7979 9570 - "@types/node" 7980 9571 - supports-color 7981 9572 - typescript 7982 - 7983 - "@modelcontextprotocol/sdk@1.27.1(zod@3.25.76)": 7984 - dependencies: 7985 - "@hono/node-server": 1.19.11(hono@4.12.5) 7986 - ajv: 8.18.0 7987 - ajv-formats: 3.0.1(ajv@8.18.0) 7988 - content-type: 1.0.5 7989 - cors: 2.8.6 7990 - cross-spawn: 7.0.6 7991 - eventsource: 3.0.7 7992 - eventsource-parser: 3.0.6 7993 - express: 5.2.1 7994 - express-rate-limit: 8.3.0(express@5.2.1) 7995 - hono: 4.12.5 7996 - jose: 6.1.3 7997 - json-schema-typed: 8.0.2 7998 - pkce-challenge: 5.0.1 7999 - raw-body: 3.0.2 8000 - zod: 3.25.76 8001 - zod-to-json-schema: 3.25.1(zod@3.25.76) 8002 - transitivePeerDependencies: 8003 - - supports-color 8004 9573 8005 9574 "@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)": 8006 9575 dependencies: ··· 8107 9676 outvariant: 1.4.3 8108 9677 8109 9678 "@open-draft/until@2.1.0": {} 9679 + 9680 + "@oxc-project/types@0.120.0": {} 8110 9681 8111 9682 "@oxc-resolver/binding-android-arm-eabi@11.19.1": 8112 9683 optional: true ··· 8919 10490 8920 10491 "@radix-ui/rect@1.1.1": {} 8921 10492 10493 + "@rolldown/binding-android-arm64@1.0.0-rc.10": 10494 + optional: true 10495 + 10496 + "@rolldown/binding-darwin-arm64@1.0.0-rc.10": 10497 + optional: true 10498 + 10499 + "@rolldown/binding-darwin-x64@1.0.0-rc.10": 10500 + optional: true 10501 + 10502 + "@rolldown/binding-freebsd-x64@1.0.0-rc.10": 10503 + optional: true 10504 + 10505 + "@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10": 10506 + optional: true 10507 + 10508 + "@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10": 10509 + optional: true 10510 + 10511 + "@rolldown/binding-linux-arm64-musl@1.0.0-rc.10": 10512 + optional: true 10513 + 10514 + "@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10": 10515 + optional: true 10516 + 10517 + "@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10": 10518 + optional: true 10519 + 10520 + "@rolldown/binding-linux-x64-gnu@1.0.0-rc.10": 10521 + optional: true 10522 + 10523 + "@rolldown/binding-linux-x64-musl@1.0.0-rc.10": 10524 + optional: true 10525 + 10526 + "@rolldown/binding-openharmony-arm64@1.0.0-rc.10": 10527 + optional: true 10528 + 10529 + "@rolldown/binding-wasm32-wasi@1.0.0-rc.10": 10530 + dependencies: 10531 + "@napi-rs/wasm-runtime": 1.1.1 10532 + optional: true 10533 + 10534 + "@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10": 10535 + optional: true 10536 + 10537 + "@rolldown/binding-win32-x64-msvc@1.0.0-rc.10": 10538 + optional: true 10539 + 10540 + "@rolldown/pluginutils@1.0.0-rc.10": {} 10541 + 10542 + "@rollup/rollup-android-arm-eabi@4.59.1": 10543 + optional: true 10544 + 10545 + "@rollup/rollup-android-arm64@4.59.1": 10546 + optional: true 10547 + 10548 + "@rollup/rollup-darwin-arm64@4.59.1": 10549 + optional: true 10550 + 10551 + "@rollup/rollup-darwin-x64@4.59.1": 10552 + optional: true 10553 + 10554 + "@rollup/rollup-freebsd-arm64@4.59.1": 10555 + optional: true 10556 + 10557 + "@rollup/rollup-freebsd-x64@4.59.1": 10558 + optional: true 10559 + 10560 + "@rollup/rollup-linux-arm-gnueabihf@4.59.1": 10561 + optional: true 10562 + 10563 + "@rollup/rollup-linux-arm-musleabihf@4.59.1": 10564 + optional: true 10565 + 10566 + "@rollup/rollup-linux-arm64-gnu@4.59.1": 10567 + optional: true 10568 + 10569 + "@rollup/rollup-linux-arm64-musl@4.59.1": 10570 + optional: true 10571 + 10572 + "@rollup/rollup-linux-loong64-gnu@4.59.1": 10573 + optional: true 10574 + 10575 + "@rollup/rollup-linux-loong64-musl@4.59.1": 10576 + optional: true 10577 + 10578 + "@rollup/rollup-linux-ppc64-gnu@4.59.1": 10579 + optional: true 10580 + 10581 + "@rollup/rollup-linux-ppc64-musl@4.59.1": 10582 + optional: true 10583 + 10584 + "@rollup/rollup-linux-riscv64-gnu@4.59.1": 10585 + optional: true 10586 + 10587 + "@rollup/rollup-linux-riscv64-musl@4.59.1": 10588 + optional: true 10589 + 10590 + "@rollup/rollup-linux-s390x-gnu@4.59.1": 10591 + optional: true 10592 + 10593 + "@rollup/rollup-linux-x64-gnu@4.59.1": 10594 + optional: true 10595 + 10596 + "@rollup/rollup-linux-x64-musl@4.59.1": 10597 + optional: true 10598 + 10599 + "@rollup/rollup-openbsd-x64@4.59.1": 10600 + optional: true 10601 + 10602 + "@rollup/rollup-openharmony-arm64@4.59.1": 10603 + optional: true 10604 + 10605 + "@rollup/rollup-win32-arm64-msvc@4.59.1": 10606 + optional: true 10607 + 10608 + "@rollup/rollup-win32-ia32-msvc@4.59.1": 10609 + optional: true 10610 + 10611 + "@rollup/rollup-win32-x64-gnu@4.59.1": 10612 + optional: true 10613 + 10614 + "@rollup/rollup-win32-x64-msvc@4.59.1": 10615 + optional: true 10616 + 8922 10617 "@rtsao/scc@1.1.0": {} 8923 10618 8924 10619 "@sec-ant/readable-stream@0.4.1": {} 8925 10620 8926 10621 "@sindresorhus/merge-streams@4.0.0": {} 10622 + 10623 + "@standard-schema/spec@1.1.0": {} 8927 10624 8928 10625 "@standard-schema/utils@0.3.0": {} 8929 10626 ··· 9000 10697 postcss: 8.5.6 9001 10698 tailwindcss: 4.2.1 9002 10699 10700 + "@ts-morph/common@0.25.0": 10701 + dependencies: 10702 + minimatch: 9.0.9 10703 + path-browserify: 1.0.1 10704 + tinyglobby: 0.2.15 10705 + 9003 10706 "@ts-morph/common@0.27.0": 9004 10707 dependencies: 9005 10708 fast-glob: 3.3.3 9006 10709 minimatch: 10.2.4 9007 10710 path-browserify: 1.0.1 10711 + 10712 + "@ts-morph/common@0.28.1": 10713 + dependencies: 10714 + minimatch: 10.2.4 10715 + path-browserify: 1.0.1 10716 + tinyglobby: 0.2.15 9008 10717 9009 10718 "@turbo/darwin-64@2.8.19": 9010 10719 optional: true ··· 9033 10742 dependencies: 9034 10743 "@types/node": 20.19.37 9035 10744 10745 + "@types/body-parser@1.19.6": 10746 + dependencies: 10747 + "@types/connect": 3.4.38 10748 + "@types/node": 20.19.37 10749 + 10750 + "@types/chai@5.2.3": 10751 + dependencies: 10752 + "@types/deep-eql": 4.0.2 10753 + assertion-error: 2.0.1 10754 + 10755 + "@types/connect@3.4.38": 10756 + dependencies: 10757 + "@types/node": 20.19.37 10758 + 10759 + "@types/deep-eql@4.0.2": {} 10760 + 9036 10761 "@types/estree@1.0.8": {} 9037 10762 10763 + "@types/express-serve-static-core@5.1.1": 10764 + dependencies: 10765 + "@types/node": 20.19.37 10766 + "@types/qs": 6.15.0 10767 + "@types/range-parser": 1.2.7 10768 + "@types/send": 1.2.1 10769 + 10770 + "@types/express@5.0.6": 10771 + dependencies: 10772 + "@types/body-parser": 1.19.6 10773 + "@types/express-serve-static-core": 5.1.1 10774 + "@types/serve-static": 2.2.0 10775 + 10776 + "@types/http-errors@2.0.5": {} 10777 + 9038 10778 "@types/json-schema@7.0.15": {} 9039 10779 9040 10780 "@types/json5@0.0.29": {} ··· 9043 10783 dependencies: 9044 10784 undici-types: 6.21.0 9045 10785 10786 + "@types/qs@6.15.0": {} 10787 + 10788 + "@types/range-parser@1.2.7": {} 10789 + 9046 10790 "@types/react-dom@19.2.3(@types/react@19.2.14)": 9047 10791 dependencies: 9048 10792 "@types/react": 19.2.14 ··· 9050 10794 "@types/react@19.2.14": 9051 10795 dependencies: 9052 10796 csstype: 3.2.3 10797 + 10798 + "@types/send@1.2.1": 10799 + dependencies: 10800 + "@types/node": 20.19.37 10801 + 10802 + "@types/serve-static@2.2.0": 10803 + dependencies: 10804 + "@types/http-errors": 2.0.5 10805 + "@types/node": 20.19.37 9053 10806 9054 10807 "@types/statuses@2.0.6": {} 9055 10808 ··· 9205 10958 "@unrs/resolver-binding-win32-x64-msvc@1.11.1": 9206 10959 optional: true 9207 10960 10961 + "@vitest/expect@4.1.0": 10962 + dependencies: 10963 + "@standard-schema/spec": 1.1.0 10964 + "@types/chai": 5.2.3 10965 + "@vitest/spy": 4.1.0 10966 + "@vitest/utils": 4.1.0 10967 + chai: 6.2.2 10968 + tinyrainbow: 3.1.0 10969 + 10970 + "@vitest/mocker@4.1.0(msw@2.12.10(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.1(@types/node@20.19.37)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))": 10971 + dependencies: 10972 + "@vitest/spy": 4.1.0 10973 + estree-walker: 3.0.3 10974 + magic-string: 0.30.21 10975 + optionalDependencies: 10976 + msw: 2.12.10(@types/node@20.19.37)(typescript@5.9.3) 10977 + vite: 8.0.1(@types/node@20.19.37)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) 10978 + 10979 + "@vitest/pretty-format@4.1.0": 10980 + dependencies: 10981 + tinyrainbow: 3.1.0 10982 + 10983 + "@vitest/runner@4.1.0": 10984 + dependencies: 10985 + "@vitest/utils": 4.1.0 10986 + pathe: 2.0.3 10987 + 10988 + "@vitest/snapshot@4.1.0": 10989 + dependencies: 10990 + "@vitest/pretty-format": 4.1.0 10991 + "@vitest/utils": 4.1.0 10992 + magic-string: 0.30.21 10993 + pathe: 2.0.3 10994 + 10995 + "@vitest/spy@4.1.0": {} 10996 + 10997 + "@vitest/utils@4.1.0": 10998 + dependencies: 10999 + "@vitest/pretty-format": 4.1.0 11000 + convert-source-map: 2.0.0 11001 + tinyrainbow: 3.1.0 11002 + 11003 + abort-controller@3.0.0: 11004 + dependencies: 11005 + event-target-shim: 5.0.1 11006 + 9208 11007 accepts@2.0.0: 9209 11008 dependencies: 9210 11009 mime-types: 3.0.2 ··· 9251 11050 ansi-styles@6.2.3: {} 9252 11051 9253 11052 ansis@4.2.0: {} 11053 + 11054 + any-promise@1.3.0: {} 9254 11055 9255 11056 argparse@2.0.1: {} 9256 11057 ··· 9327 11128 get-intrinsic: 1.3.0 9328 11129 is-array-buffer: 3.0.5 9329 11130 11131 + assertion-error@2.0.1: {} 11132 + 9330 11133 ast-types-flow@0.0.8: {} 9331 11134 9332 11135 ast-types@0.16.1: ··· 9335 11138 9336 11139 async-function@1.0.0: {} 9337 11140 11141 + atomic-sleep@1.0.0: {} 11142 + 9338 11143 available-typed-arrays@1.0.7: 9339 11144 dependencies: 9340 11145 possible-typed-array-names: 1.1.0 ··· 9391 11196 balanced-match: 1.0.2 9392 11197 concat-map: 0.0.1 9393 11198 11199 + brace-expansion@2.0.2: 11200 + dependencies: 11201 + balanced-match: 1.0.2 11202 + 9394 11203 brace-expansion@5.0.3: 9395 11204 dependencies: 9396 11205 balanced-match: 4.0.4 ··· 9412 11221 base64-js: 1.5.1 9413 11222 ieee754: 1.2.1 9414 11223 11224 + buffer@6.0.3: 11225 + dependencies: 11226 + base64-js: 1.5.1 11227 + ieee754: 1.2.1 11228 + 9415 11229 bundle-name@4.1.0: 9416 11230 dependencies: 9417 11231 run-applescript: 7.1.0 9418 11232 11233 + bundle-require@5.1.0(esbuild@0.27.3): 11234 + dependencies: 11235 + esbuild: 0.27.3 11236 + load-tsconfig: 0.2.5 11237 + 9419 11238 bytes@3.1.2: {} 11239 + 11240 + cac@6.7.14: {} 9420 11241 9421 11242 call-bind-apply-helpers@1.0.2: 9422 11243 dependencies: ··· 9439 11260 9440 11261 caniuse-lite@1.0.30001774: {} 9441 11262 11263 + cborg@1.10.2: {} 11264 + 11265 + chai@6.2.2: {} 11266 + 9442 11267 chalk@4.1.2: 9443 11268 dependencies: 9444 11269 ansi-styles: 4.3.0 9445 11270 supports-color: 7.2.0 9446 11271 9447 11272 chalk@5.6.2: {} 11273 + 11274 + chokidar@4.0.3: 11275 + dependencies: 11276 + readdirp: 4.1.2 9448 11277 9449 11278 chownr@1.1.4: {} 9450 11279 ··· 9489 11318 9490 11319 commander@14.0.3: {} 9491 11320 11321 + commander@4.1.1: {} 11322 + 11323 + commander@9.5.0: {} 11324 + 9492 11325 comment-parser@1.4.5: {} 9493 11326 9494 11327 concat-map@0.0.1: {} 11328 + 11329 + confbox@0.1.8: {} 11330 + 11331 + consola@3.4.2: {} 9495 11332 9496 11333 content-disposition@1.0.1: {} 9497 11334 ··· 9732 11569 iterator.prototype: 1.1.5 9733 11570 safe-array-concat: 1.1.3 9734 11571 11572 + es-module-lexer@2.0.0: {} 11573 + 9735 11574 es-object-atoms@1.1.1: 9736 11575 dependencies: 9737 11576 es-errors: 1.3.0 ··· 9788 11627 9789 11628 escape-string-regexp@4.0.0: {} 9790 11629 9791 - eslint-config-next@16.1.7(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3): 11630 + eslint-config-next@16.1.7(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3): 9792 11631 dependencies: 9793 11632 "@next/eslint-plugin-next": 16.1.7 9794 11633 eslint: 9.39.3(jiti@2.6.1) 9795 11634 eslint-import-resolver-node: 0.3.9 9796 11635 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.3(jiti@2.6.1)) 9797 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)) 11636 + eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)) 9798 11637 eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.3(jiti@2.6.1)) 9799 11638 eslint-plugin-react: 7.37.5(eslint@9.39.3(jiti@2.6.1)) 9800 11639 eslint-plugin-react-hooks: 7.0.1(eslint@9.39.3(jiti@2.6.1)) ··· 9838 11677 tinyglobby: 0.2.15 9839 11678 unrs-resolver: 1.11.1 9840 11679 optionalDependencies: 9841 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)) 11680 + eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)) 9842 11681 eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)) 9843 11682 transitivePeerDependencies: 9844 11683 - supports-color 9845 11684 9846 - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)): 11685 + eslint-module-utils@2.12.1(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)): 9847 11686 dependencies: 9848 11687 debug: 3.2.7 9849 11688 optionalDependencies: 9850 - "@typescript-eslint/parser": 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) 9851 11689 eslint: 9.39.3(jiti@2.6.1) 9852 11690 eslint-import-resolver-node: 0.3.9 9853 11691 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.3(jiti@2.6.1)) ··· 9873 11711 transitivePeerDependencies: 9874 11712 - supports-color 9875 11713 9876 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)): 11714 + eslint-plugin-import@2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)): 9877 11715 dependencies: 9878 11716 "@rtsao/scc": 1.1.0 9879 11717 array-includes: 3.1.9 ··· 9884 11722 doctrine: 2.1.0 9885 11723 eslint: 9.39.3(jiti@2.6.1) 9886 11724 eslint-import-resolver-node: 0.3.9 9887 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)) 11725 + eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.3(jiti@2.6.1)) 9888 11726 hasown: 2.0.2 9889 11727 is-core-module: 2.16.1 9890 11728 is-glob: 4.0.3 ··· 9895 11733 semver: 6.3.1 9896 11734 string.prototype.trimend: 1.0.9 9897 11735 tsconfig-paths: 3.15.0 9898 - optionalDependencies: 9899 - "@typescript-eslint/parser": 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) 9900 11736 transitivePeerDependencies: 9901 11737 - eslint-import-resolver-typescript 9902 11738 - eslint-import-resolver-webpack ··· 10023 11859 estraverse: 5.3.0 10024 11860 10025 11861 estraverse@5.3.0: {} 11862 + 11863 + estree-walker@3.0.3: 11864 + dependencies: 11865 + "@types/estree": 1.0.8 10026 11866 10027 11867 esutils@2.0.3: {} 10028 11868 10029 11869 etag@1.8.1: {} 10030 11870 11871 + event-target-shim@5.0.1: {} 11872 + 10031 11873 eventemitter3@5.0.4: {} 11874 + 11875 + events@3.3.0: {} 10032 11876 10033 11877 eventsource-parser@3.0.6: {} 10034 11878 ··· 10064 11908 yoctocolors: 2.1.2 10065 11909 10066 11910 expand-template@2.0.3: {} 11911 + 11912 + expect-type@1.3.0: {} 10067 11913 10068 11914 express-rate-limit@8.3.0(express@5.2.1): 10069 11915 dependencies: ··· 10125 11971 10126 11972 fast-levenshtein@2.0.6: {} 10127 11973 11974 + fast-redact@3.5.0: {} 11975 + 10128 11976 fast-uri@3.1.0: {} 10129 11977 10130 11978 fastq@1.20.1: ··· 10173 12021 dependencies: 10174 12022 locate-path: 6.0.0 10175 12023 path-exists: 4.0.0 12024 + 12025 + fix-dts-default-cjs-exports@1.0.1: 12026 + dependencies: 12027 + magic-string: 0.30.21 12028 + mlly: 1.8.2 12029 + rollup: 4.59.1 10176 12030 10177 12031 flat-cache@4.0.1: 10178 12032 dependencies: ··· 10558 12412 10559 12413 jose@6.1.3: {} 10560 12414 12415 + joycon@3.1.1: {} 12416 + 10561 12417 js-tokens@4.0.0: {} 10562 12418 10563 12419 js-yaml@4.1.1: ··· 10639 12495 lightningcss-android-arm64@1.31.1: 10640 12496 optional: true 10641 12497 12498 + lightningcss-android-arm64@1.32.0: 12499 + optional: true 12500 + 10642 12501 lightningcss-darwin-arm64@1.31.1: 10643 12502 optional: true 10644 12503 12504 + lightningcss-darwin-arm64@1.32.0: 12505 + optional: true 12506 + 10645 12507 lightningcss-darwin-x64@1.31.1: 10646 12508 optional: true 10647 12509 12510 + lightningcss-darwin-x64@1.32.0: 12511 + optional: true 12512 + 10648 12513 lightningcss-freebsd-x64@1.31.1: 10649 12514 optional: true 10650 12515 12516 + lightningcss-freebsd-x64@1.32.0: 12517 + optional: true 12518 + 10651 12519 lightningcss-linux-arm-gnueabihf@1.31.1: 12520 + optional: true 12521 + 12522 + lightningcss-linux-arm-gnueabihf@1.32.0: 10652 12523 optional: true 10653 12524 10654 12525 lightningcss-linux-arm64-gnu@1.31.1: 10655 12526 optional: true 10656 12527 12528 + lightningcss-linux-arm64-gnu@1.32.0: 12529 + optional: true 12530 + 10657 12531 lightningcss-linux-arm64-musl@1.31.1: 10658 12532 optional: true 10659 12533 12534 + lightningcss-linux-arm64-musl@1.32.0: 12535 + optional: true 12536 + 10660 12537 lightningcss-linux-x64-gnu@1.31.1: 10661 12538 optional: true 10662 12539 12540 + lightningcss-linux-x64-gnu@1.32.0: 12541 + optional: true 12542 + 10663 12543 lightningcss-linux-x64-musl@1.31.1: 10664 12544 optional: true 10665 12545 12546 + lightningcss-linux-x64-musl@1.32.0: 12547 + optional: true 12548 + 10666 12549 lightningcss-win32-arm64-msvc@1.31.1: 10667 12550 optional: true 10668 12551 12552 + lightningcss-win32-arm64-msvc@1.32.0: 12553 + optional: true 12554 + 10669 12555 lightningcss-win32-x64-msvc@1.31.1: 12556 + optional: true 12557 + 12558 + lightningcss-win32-x64-msvc@1.32.0: 10670 12559 optional: true 10671 12560 10672 12561 lightningcss@1.31.1: ··· 10685 12574 lightningcss-win32-arm64-msvc: 1.31.1 10686 12575 lightningcss-win32-x64-msvc: 1.31.1 10687 12576 12577 + lightningcss@1.32.0: 12578 + dependencies: 12579 + detect-libc: 2.1.2 12580 + optionalDependencies: 12581 + lightningcss-android-arm64: 1.32.0 12582 + lightningcss-darwin-arm64: 1.32.0 12583 + lightningcss-darwin-x64: 1.32.0 12584 + lightningcss-freebsd-x64: 1.32.0 12585 + lightningcss-linux-arm-gnueabihf: 1.32.0 12586 + lightningcss-linux-arm64-gnu: 1.32.0 12587 + lightningcss-linux-arm64-musl: 1.32.0 12588 + lightningcss-linux-x64-gnu: 1.32.0 12589 + lightningcss-linux-x64-musl: 1.32.0 12590 + lightningcss-win32-arm64-msvc: 1.32.0 12591 + lightningcss-win32-x64-msvc: 1.32.0 12592 + 12593 + lilconfig@3.1.3: {} 12594 + 10688 12595 lines-and-columns@1.2.4: {} 10689 12596 10690 12597 lint-staged@16.2.7: ··· 10705 12612 log-update: 6.1.0 10706 12613 rfdc: 1.4.1 10707 12614 wrap-ansi: 9.0.2 12615 + 12616 + load-tsconfig@0.2.5: {} 10708 12617 10709 12618 locate-path@6.0.0: 10710 12619 dependencies: ··· 10778 12687 dependencies: 10779 12688 brace-expansion: 1.1.12 10780 12689 12690 + minimatch@9.0.9: 12691 + dependencies: 12692 + brace-expansion: 2.0.2 12693 + 10781 12694 minimist@1.2.8: {} 10782 12695 10783 12696 mkdirp-classic@0.5.3: {} 12697 + 12698 + mlly@1.8.2: 12699 + dependencies: 12700 + acorn: 8.16.0 12701 + pathe: 2.0.3 12702 + pkg-types: 1.3.1 12703 + ufo: 1.6.3 10784 12704 10785 12705 ms@2.1.3: {} 10786 12706 ··· 10815 12735 10816 12736 mute-stream@2.0.0: {} 10817 12737 12738 + mz@2.7.0: 12739 + dependencies: 12740 + any-promise: 1.3.0 12741 + object-assign: 4.1.1 12742 + thenify-all: 1.6.0 12743 + 10818 12744 nano-spawn@2.0.0: {} 10819 12745 10820 12746 nanoid@3.3.11: {} ··· 10931 12857 define-properties: 1.2.1 10932 12858 es-object-atoms: 1.1.1 10933 12859 12860 + obug@2.1.1: {} 12861 + 12862 + on-exit-leak-free@2.1.2: {} 12863 + 10934 12864 on-finished@2.4.1: 10935 12865 dependencies: 10936 12866 ee-first: 1.1.1 ··· 11047 12977 11048 12978 path-to-regexp@8.3.0: {} 11049 12979 12980 + pathe@2.0.3: {} 12981 + 11050 12982 picocolors@1.1.1: {} 11051 12983 11052 12984 picomatch@2.3.1: {} ··· 11055 12987 11056 12988 pidtree@0.6.0: {} 11057 12989 12990 + pino-abstract-transport@1.2.0: 12991 + dependencies: 12992 + readable-stream: 4.7.0 12993 + split2: 4.2.0 12994 + 12995 + pino-std-serializers@6.2.2: {} 12996 + 12997 + pino@8.21.0: 12998 + dependencies: 12999 + atomic-sleep: 1.0.0 13000 + fast-redact: 3.5.0 13001 + on-exit-leak-free: 2.1.2 13002 + pino-abstract-transport: 1.2.0 13003 + pino-std-serializers: 6.2.2 13004 + process-warning: 3.0.0 13005 + quick-format-unescaped: 4.0.4 13006 + real-require: 0.2.0 13007 + safe-stable-stringify: 2.5.0 13008 + sonic-boom: 3.8.1 13009 + thread-stream: 2.7.0 13010 + 13011 + pirates@4.0.7: {} 13012 + 11058 13013 pkce-challenge@5.0.1: {} 11059 13014 13015 + pkg-types@1.3.1: 13016 + dependencies: 13017 + confbox: 0.1.8 13018 + mlly: 1.8.2 13019 + pathe: 2.0.3 13020 + 11060 13021 possible-typed-array-names@1.1.0: {} 11061 13022 13023 + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.2): 13024 + dependencies: 13025 + lilconfig: 3.1.3 13026 + optionalDependencies: 13027 + jiti: 2.6.1 13028 + postcss: 8.5.8 13029 + tsx: 4.21.0 13030 + yaml: 2.8.2 13031 + 11062 13032 postcss-selector-parser@7.1.1: 11063 13033 dependencies: 11064 13034 cssesc: 3.0.0 ··· 11076 13046 picocolors: 1.1.1 11077 13047 source-map-js: 1.2.1 11078 13048 13049 + postcss@8.5.8: 13050 + dependencies: 13051 + nanoid: 3.3.11 13052 + picocolors: 1.1.1 13053 + source-map-js: 1.2.1 13054 + 11079 13055 powershell-utils@0.1.0: {} 11080 13056 11081 13057 prebuild-install@7.1.3: ··· 11101 13077 dependencies: 11102 13078 parse-ms: 4.0.0 11103 13079 13080 + process-warning@3.0.0: {} 13081 + 13082 + process@0.11.10: {} 13083 + 11104 13084 prompts@2.4.2: 11105 13085 dependencies: 11106 13086 kleur: 3.0.3 ··· 11129 13109 side-channel: 1.1.0 11130 13110 11131 13111 queue-microtask@1.2.3: {} 13112 + 13113 + quick-format-unescaped@4.0.4: {} 11132 13114 11133 13115 radix-ui@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): 11134 13116 dependencies: ··· 11255 13237 string_decoder: 1.3.0 11256 13238 util-deprecate: 1.0.2 11257 13239 13240 + readable-stream@4.7.0: 13241 + dependencies: 13242 + abort-controller: 3.0.0 13243 + buffer: 6.0.3 13244 + events: 3.3.0 13245 + process: 0.11.10 13246 + string_decoder: 1.3.0 13247 + 13248 + readdirp@4.1.2: {} 13249 + 13250 + real-require@0.2.0: {} 13251 + 11258 13252 recast@0.23.11: 11259 13253 dependencies: 11260 13254 ast-types: 0.16.1 ··· 11289 13283 11290 13284 resolve-from@4.0.0: {} 11291 13285 13286 + resolve-from@5.0.0: {} 13287 + 11292 13288 resolve-pkg-maps@1.0.0: {} 11293 13289 11294 13290 resolve@1.22.11: ··· 11317 13313 11318 13314 rfdc@1.4.1: {} 11319 13315 13316 + rolldown@1.0.0-rc.10: 13317 + dependencies: 13318 + "@oxc-project/types": 0.120.0 13319 + "@rolldown/pluginutils": 1.0.0-rc.10 13320 + optionalDependencies: 13321 + "@rolldown/binding-android-arm64": 1.0.0-rc.10 13322 + "@rolldown/binding-darwin-arm64": 1.0.0-rc.10 13323 + "@rolldown/binding-darwin-x64": 1.0.0-rc.10 13324 + "@rolldown/binding-freebsd-x64": 1.0.0-rc.10 13325 + "@rolldown/binding-linux-arm-gnueabihf": 1.0.0-rc.10 13326 + "@rolldown/binding-linux-arm64-gnu": 1.0.0-rc.10 13327 + "@rolldown/binding-linux-arm64-musl": 1.0.0-rc.10 13328 + "@rolldown/binding-linux-ppc64-gnu": 1.0.0-rc.10 13329 + "@rolldown/binding-linux-s390x-gnu": 1.0.0-rc.10 13330 + "@rolldown/binding-linux-x64-gnu": 1.0.0-rc.10 13331 + "@rolldown/binding-linux-x64-musl": 1.0.0-rc.10 13332 + "@rolldown/binding-openharmony-arm64": 1.0.0-rc.10 13333 + "@rolldown/binding-wasm32-wasi": 1.0.0-rc.10 13334 + "@rolldown/binding-win32-arm64-msvc": 1.0.0-rc.10 13335 + "@rolldown/binding-win32-x64-msvc": 1.0.0-rc.10 13336 + 13337 + rollup@4.59.1: 13338 + dependencies: 13339 + "@types/estree": 1.0.8 13340 + optionalDependencies: 13341 + "@rollup/rollup-android-arm-eabi": 4.59.1 13342 + "@rollup/rollup-android-arm64": 4.59.1 13343 + "@rollup/rollup-darwin-arm64": 4.59.1 13344 + "@rollup/rollup-darwin-x64": 4.59.1 13345 + "@rollup/rollup-freebsd-arm64": 4.59.1 13346 + "@rollup/rollup-freebsd-x64": 4.59.1 13347 + "@rollup/rollup-linux-arm-gnueabihf": 4.59.1 13348 + "@rollup/rollup-linux-arm-musleabihf": 4.59.1 13349 + "@rollup/rollup-linux-arm64-gnu": 4.59.1 13350 + "@rollup/rollup-linux-arm64-musl": 4.59.1 13351 + "@rollup/rollup-linux-loong64-gnu": 4.59.1 13352 + "@rollup/rollup-linux-loong64-musl": 4.59.1 13353 + "@rollup/rollup-linux-ppc64-gnu": 4.59.1 13354 + "@rollup/rollup-linux-ppc64-musl": 4.59.1 13355 + "@rollup/rollup-linux-riscv64-gnu": 4.59.1 13356 + "@rollup/rollup-linux-riscv64-musl": 4.59.1 13357 + "@rollup/rollup-linux-s390x-gnu": 4.59.1 13358 + "@rollup/rollup-linux-x64-gnu": 4.59.1 13359 + "@rollup/rollup-linux-x64-musl": 4.59.1 13360 + "@rollup/rollup-openbsd-x64": 4.59.1 13361 + "@rollup/rollup-openharmony-arm64": 4.59.1 13362 + "@rollup/rollup-win32-arm64-msvc": 4.59.1 13363 + "@rollup/rollup-win32-ia32-msvc": 4.59.1 13364 + "@rollup/rollup-win32-x64-gnu": 4.59.1 13365 + "@rollup/rollup-win32-x64-msvc": 4.59.1 13366 + fsevents: 2.3.3 13367 + 11320 13368 router@2.2.0: 11321 13369 dependencies: 11322 13370 debug: 4.4.3 ··· 11354 13402 es-errors: 1.3.0 11355 13403 is-regex: 1.2.1 11356 13404 13405 + safe-stable-stringify@2.5.0: {} 13406 + 11357 13407 safer-buffer@2.1.2: {} 11358 13408 11359 13409 scheduler@0.27.0: {} ··· 11419 13469 "@babel/plugin-transform-typescript": 7.28.6(@babel/core@7.29.0) 11420 13470 "@babel/preset-typescript": 7.28.5(@babel/core@7.29.0) 11421 13471 "@dotenvx/dotenvx": 1.52.0 11422 - "@modelcontextprotocol/sdk": 1.27.1(zod@3.25.76) 13472 + "@modelcontextprotocol/sdk": 1.27.1(zod@4.3.6) 11423 13473 "@types/validate-npm-package-name": 4.0.2 11424 13474 browserslist: 4.28.1 11425 13475 commander: 14.0.3 ··· 11446 13496 ts-morph: 26.0.0 11447 13497 tsconfig-paths: 4.2.0 11448 13498 validate-npm-package-name: 7.0.2 11449 - zod: 3.25.76 11450 - zod-to-json-schema: 3.25.1(zod@3.25.76) 13499 + zod: 4.3.6 13500 + zod-to-json-schema: 3.25.1(zod@4.3.6) 11451 13501 transitivePeerDependencies: 11452 13502 - "@cfworker/json-schema" 11453 13503 - "@types/node" ··· 11521 13571 side-channel-map: 1.0.1 11522 13572 side-channel-weakmap: 1.0.2 11523 13573 13574 + siginfo@2.0.0: {} 13575 + 11524 13576 signal-exit@3.0.7: {} 11525 13577 11526 13578 signal-exit@4.1.0: {} ··· 11542 13594 11543 13595 smol-toml@1.6.0: {} 11544 13596 13597 + sonic-boom@3.8.1: 13598 + dependencies: 13599 + atomic-sleep: 1.0.0 13600 + 11545 13601 sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): 11546 13602 dependencies: 11547 13603 react: 19.2.4 ··· 11551 13607 11552 13608 source-map@0.6.1: {} 11553 13609 13610 + source-map@0.7.6: {} 13611 + 13612 + split2@4.2.0: {} 13613 + 11554 13614 stable-hash-x@0.2.0: {} 11555 13615 11556 13616 stable-hash@0.0.5: {} 11557 13617 13618 + stackback@0.0.2: {} 13619 + 11558 13620 statuses@2.0.2: {} 13621 + 13622 + std-env@4.0.0: {} 11559 13623 11560 13624 stdin-discarder@0.2.2: {} 11561 13625 ··· 11672 13736 optionalDependencies: 11673 13737 "@babel/core": 7.29.0 11674 13738 13739 + sucrase@3.35.1: 13740 + dependencies: 13741 + "@jridgewell/gen-mapping": 0.3.13 13742 + commander: 4.1.1 13743 + lines-and-columns: 1.2.4 13744 + mz: 2.7.0 13745 + pirates: 4.0.7 13746 + tinyglobby: 0.2.15 13747 + ts-interface-checker: 0.1.13 13748 + 11675 13749 supports-color@7.2.0: 11676 13750 dependencies: 11677 13751 has-flag: 4.0.0 ··· 11701 13775 inherits: 2.0.4 11702 13776 readable-stream: 3.6.2 11703 13777 13778 + thenify-all@1.6.0: 13779 + dependencies: 13780 + thenify: 3.3.1 13781 + 13782 + thenify@3.3.1: 13783 + dependencies: 13784 + any-promise: 1.3.0 13785 + 13786 + thread-stream@2.7.0: 13787 + dependencies: 13788 + real-require: 0.2.0 13789 + 11704 13790 tiny-invariant@1.3.3: {} 11705 13791 13792 + tinybench@2.9.0: {} 13793 + 13794 + tinyexec@0.3.2: {} 13795 + 11706 13796 tinyexec@1.0.2: {} 11707 13797 11708 13798 tinyglobby@0.2.15: 11709 13799 dependencies: 11710 13800 fdir: 6.5.0(picomatch@4.0.3) 11711 13801 picomatch: 4.0.3 13802 + 13803 + tinyrainbow@3.1.0: {} 11712 13804 11713 13805 tlds@1.261.0: {} 11714 13806 ··· 11728 13820 dependencies: 11729 13821 tldts: 7.0.23 11730 13822 13823 + tree-kill@1.2.2: {} 13824 + 11731 13825 ts-api-utils@2.4.0(typescript@5.9.3): 11732 13826 dependencies: 11733 13827 typescript: 5.9.3 11734 13828 13829 + ts-interface-checker@0.1.13: {} 13830 + 13831 + ts-morph@24.0.0: 13832 + dependencies: 13833 + "@ts-morph/common": 0.25.0 13834 + code-block-writer: 13.0.3 13835 + 11735 13836 ts-morph@26.0.0: 11736 13837 dependencies: 11737 13838 "@ts-morph/common": 0.27.0 11738 13839 code-block-writer: 13.0.3 11739 13840 13841 + ts-morph@27.0.2: 13842 + dependencies: 13843 + "@ts-morph/common": 0.28.1 13844 + code-block-writer: 13.0.3 13845 + 11740 13846 tsconfig-paths@3.15.0: 11741 13847 dependencies: 11742 13848 "@types/json5": 0.0.29 ··· 11752 13858 11753 13859 tslib@2.8.1: {} 11754 13860 13861 + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): 13862 + dependencies: 13863 + bundle-require: 5.1.0(esbuild@0.27.3) 13864 + cac: 6.7.14 13865 + chokidar: 4.0.3 13866 + consola: 3.4.2 13867 + debug: 4.4.3 13868 + esbuild: 0.27.3 13869 + fix-dts-default-cjs-exports: 1.0.1 13870 + joycon: 3.1.1 13871 + picocolors: 1.1.1 13872 + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.2) 13873 + resolve-from: 5.0.0 13874 + rollup: 4.59.1 13875 + source-map: 0.7.6 13876 + sucrase: 3.35.1 13877 + tinyexec: 0.3.2 13878 + tinyglobby: 0.2.15 13879 + tree-kill: 1.2.2 13880 + optionalDependencies: 13881 + postcss: 8.5.8 13882 + typescript: 5.9.3 13883 + transitivePeerDependencies: 13884 + - jiti 13885 + - supports-color 13886 + - tsx 13887 + - yaml 13888 + 11755 13889 tsx@4.21.0: 11756 13890 dependencies: 11757 13891 esbuild: 0.27.3 ··· 11834 13968 11835 13969 typescript@5.9.3: {} 11836 13970 13971 + ufo@1.6.3: {} 13972 + 11837 13973 uint8arrays@3.0.0: 11838 13974 dependencies: 11839 13975 multiformats: 9.9.0 ··· 11918 14054 11919 14055 validate-npm-package-name@7.0.2: {} 11920 14056 14057 + varint@6.0.0: {} 14058 + 11921 14059 vary@1.1.2: {} 11922 14060 14061 + vite@8.0.1(@types/node@20.19.37)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2): 14062 + dependencies: 14063 + lightningcss: 1.32.0 14064 + picomatch: 4.0.3 14065 + postcss: 8.5.8 14066 + rolldown: 1.0.0-rc.10 14067 + tinyglobby: 0.2.15 14068 + optionalDependencies: 14069 + "@types/node": 20.19.37 14070 + esbuild: 0.27.3 14071 + fsevents: 2.3.3 14072 + jiti: 2.6.1 14073 + tsx: 4.21.0 14074 + yaml: 2.8.2 14075 + 14076 + vitest@4.1.0(@types/node@20.19.37)(msw@2.12.10(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.1(@types/node@20.19.37)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): 14077 + dependencies: 14078 + "@vitest/expect": 4.1.0 14079 + "@vitest/mocker": 4.1.0(msw@2.12.10(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.1(@types/node@20.19.37)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) 14080 + "@vitest/pretty-format": 4.1.0 14081 + "@vitest/runner": 4.1.0 14082 + "@vitest/snapshot": 4.1.0 14083 + "@vitest/spy": 4.1.0 14084 + "@vitest/utils": 4.1.0 14085 + es-module-lexer: 2.0.0 14086 + expect-type: 1.3.0 14087 + magic-string: 0.30.21 14088 + obug: 2.1.1 14089 + pathe: 2.0.3 14090 + picomatch: 4.0.3 14091 + std-env: 4.0.0 14092 + tinybench: 2.9.0 14093 + tinyexec: 1.0.2 14094 + tinyglobby: 0.2.15 14095 + tinyrainbow: 3.1.0 14096 + vite: 8.0.1(@types/node@20.19.37)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) 14097 + why-is-node-running: 2.3.0 14098 + optionalDependencies: 14099 + "@types/node": 20.19.37 14100 + transitivePeerDependencies: 14101 + - msw 14102 + 11923 14103 walk-up-path@4.0.0: {} 11924 14104 11925 14105 web-streams-polyfill@3.3.3: {} ··· 11973 14153 dependencies: 11974 14154 isexe: 3.1.5 11975 14155 14156 + why-is-node-running@2.3.0: 14157 + dependencies: 14158 + siginfo: 2.0.0 14159 + stackback: 0.0.2 14160 + 11976 14161 word-wrap@1.2.5: {} 11977 14162 11978 14163 wrap-ansi@6.2.0: ··· 11995 14180 11996 14181 wrappy@1.0.2: {} 11997 14182 14183 + ws@8.20.0: {} 14184 + 11998 14185 wsl-utils@0.3.1: 11999 14186 dependencies: 12000 14187 is-wsl: 3.1.1 ··· 12018 14205 y18n: 5.0.8 12019 14206 yargs-parser: 21.1.1 12020 14207 14208 + yesno@0.4.0: {} 14209 + 12021 14210 yocto-queue@0.1.0: {} 12022 14211 12023 14212 yoctocolors-cjs@2.1.3: {} 12024 14213 12025 14214 yoctocolors@2.1.2: {} 12026 14215 12027 - zod-to-json-schema@3.25.1(zod@3.25.76): 12028 - dependencies: 12029 - zod: 3.25.76 12030 - 12031 14216 zod-to-json-schema@3.25.1(zod@4.3.6): 12032 14217 dependencies: 12033 14218 zod: 4.3.6 ··· 12035 14220 zod-validation-error@4.0.2(zod@4.3.6): 12036 14221 dependencies: 12037 14222 zod: 4.3.6 12038 - 12039 - zod@3.25.76: {} 12040 14223 12041 14224 zod@4.3.6: {} 12042 14225
+16 -2
turbo.json
··· 3 3 "tasks": { 4 4 "build": { 5 5 "dependsOn": ["^build"], 6 - "env": ["NEXT_PUBLIC_URL", "PRIVATE_KEY", "DATABASE_PATH"], 7 - "outputs": [".next/**", "!.next/cache/**"] 6 + "env": [ 7 + "NEXT_PUBLIC_URL", 8 + "NEXT_PUBLIC_APPVIEW_URL", 9 + "PRIVATE_KEY", 10 + "DATABASE_PATH", 11 + "TAP_URL", 12 + "TAP_ADMIN_PASSWORD" 13 + ], 14 + "outputs": [".next/**", "!.next/cache/**", "dist/**"] 8 15 }, 9 16 "lint": { 10 17 "dependsOn": ["^build"] 11 18 }, 12 19 "typecheck": { 13 20 "dependsOn": ["^build"] 21 + }, 22 + "test": { 23 + "dependsOn": ["^build"] 24 + }, 25 + "test:watch": { 26 + "cache": false, 27 + "persistent": true 14 28 }, 15 29 "knip": {}, 16 30 "dev": {