From a60b2f9301f029747806fac3ed2c8e7ed714f78f Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Sun, 12 Oct 2025 23:52:05 +0300 Subject: [PATCH] Revert "Merge pull request #8 from tsirysndr/chore/migrate-to-bun" This reverts commit 4ec6bb5f70b047edafe1f60e3dfb5995829dbe76, reversing changes made to 1d902f131e5fe056b9e506e36ce86f44631e085c. --- apps/api/package.json | 30 +++--- apps/api/src/db.ts | 6 +- apps/api/src/index.ts | 1 + .../types/app/rocksky/apikey/createApikey.ts | 2 +- .../types/app/rocksky/apikey/updateApikey.ts | 2 +- .../types/app/rocksky/like/dislikeShout.ts | 2 +- .../types/app/rocksky/like/dislikeSong.ts | 2 +- .../types/app/rocksky/like/likeShout.ts | 2 +- .../types/app/rocksky/like/likeSong.ts | 2 +- .../app/rocksky/scrobble/createScrobble.ts | 2 +- .../types/app/rocksky/shout/createShout.ts | 2 +- .../types/app/rocksky/shout/replyShout.ts | 2 +- .../types/app/rocksky/shout/reportShout.ts | 2 +- .../types/app/rocksky/song/createSong.ts | 2 +- .../lexicon/types/app/rocksky/spotify/next.ts | 2 +- .../types/app/rocksky/spotify/pause.ts | 2 +- .../lexicon/types/app/rocksky/spotify/play.ts | 2 +- .../types/app/rocksky/spotify/previous.ts | 2 +- apps/api/src/nowplaying/nowplaying.service.ts | 92 +++++++++---------- apps/api/src/profiling.ts | 13 +++ apps/api/src/sqliteKv.ts | 11 +-- apps/api/src/tealfm/index.ts | 10 +- apps/api/tsconfig.json | 2 +- bun.lock | 37 ++++---- package.json | 1 - 25 files changed, 125 insertions(+), 108 deletions(-) create mode 100644 apps/api/src/profiling.ts diff --git a/apps/api/package.json b/apps/api/package.json index 668cc6fd..74a6a4be 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -6,21 +6,21 @@ "module": "dist/index.js", "scripts": { "lexgen": "lex gen-server ./src/lexicon ./src/tealfm/lexicons/teal/**/* ./lexicons/**/* ./lexicons/* ./src/tealfm/lexicons/**/*", - "dev": "concurrently 'bun --watch ./src/index.ts' 'bun --watch ./src/server.ts'", - "prod": "bun ./src/index.ts", + "dev": "concurrently 'tsx --watch ./src/index.ts' 'tsx --watch ./src/server.ts'", + "prod": "tsx ./src/index.ts", "build": "pkgroll", - "sync": "bun ./src/scripts/sync.ts", - "meili:sync": "bun ./src/scripts/meili.ts", - "sync:library": "bun ./src/scripts/sync-library.ts", - "avatar": "bun ./src/scripts/avatar.ts", - "genres": "bun ./src/scripts/genres.ts", + "sync": "tsx ./src/scripts/sync.ts", + "meili:sync": "tsx ./src/scripts/meili.ts", + "sync:library": "tsx ./src/scripts/sync-library.ts", + "avatar": "tsx ./src/scripts/avatar.ts", + "genres": "tsx ./src/scripts/genres.ts", "pkl:eval": "pkl eval -f json", - "pkl:gen": "bun ./scripts/pkl.ts", - "dev:xrpc": "bun --watch ./src/server.ts", - "prod:xrpc": "bun ./src/server.ts", + "pkl:gen": "tsx ./scripts/pkl.ts", + "dev:xrpc": "tsx --watch ./src/server.ts", + "prod:xrpc": "tsx ./src/server.ts", "db:migrate": "drizzle-kit migrate", "db:gen-migration": "drizzle-kit generate", - "prod:all": "concurrently 'bun ./src/index.ts' 'bun ./src/server.ts'", + "prod:all": "concurrently 'tsx ./src/index.ts' 'tsx ./src/server.ts'", "format": "biome format src", "lint": "biome lint src" }, @@ -28,7 +28,6 @@ "@atproto/api": "^0.13.31", "@atproto/common": "^0.4.6", "@atproto/identity": "^0.4.5", - "@atproto/jwk-jose": "0.1.8", "@atproto/lex-cli": "^0.5.6", "@atproto/lexicon": "^0.4.5", "@atproto/oauth-client-node": "^0.2.14", @@ -45,8 +44,10 @@ "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-node": "^0.200.0", "@opentelemetry/semantic-conventions": "^1.32.0", + "@pyroscope/nodejs": "^0.4.5", "assert": "^2.1.0", "axios": "^1.7.9", + "better-sqlite3": "^11.8.1", "chalk": "^5.4.1", "chanfana": "^2.0.2", "cors": "^2.8.5", @@ -62,8 +63,7 @@ "http-proxy-middleware": "^3.0.5", "iron-session": "^8.0.4", "jsonwebtoken": "^9.0.2", - "kysely": "^0.28.8", - "kysely-bun-sqlite": "^0.4.0", + "kysely": "^0.27.5", "lodash": "^4.17.21", "nats": "^2.29.2", "pg": "^8.13.3", @@ -78,7 +78,6 @@ "devDependencies": { "@biomejs/biome": "^2.2.3", "@pkl-community/pkl": "^0.28.2", - "@types/bun": "^1.3.0", "@types/express": "^5.0.2", "@types/lodash": "^4.17.17", "@types/node": "^22.13.0", @@ -87,6 +86,7 @@ "concurrently": "^9.2.0", "drizzle-kit": "^0.31.1", "pkgroll": "^2.6.1", + "tsx": "^4.19.2", "zx": "^8.5.4" }, "exports": { diff --git a/apps/api/src/db.ts b/apps/api/src/db.ts index 8513a707..502cf758 100644 --- a/apps/api/src/db.ts +++ b/apps/api/src/db.ts @@ -1,11 +1,11 @@ -import { Database as SqliteDb } from "bun:sqlite"; +import SqliteDb from "better-sqlite3"; import { Kysely, type Migration, type MigrationProvider, Migrator, + SqliteDialect, } from "kysely"; -import { BunSqliteDialect } from "kysely-bun-sqlite"; // Types @@ -79,7 +79,7 @@ migrations["001"] = { export const createDb = (location: string): Database => { return new Kysely({ - dialect: new BunSqliteDialect({ + dialect: new SqliteDialect({ database: new SqliteDb(location), }), }); diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 6b5221ad..870cbd38 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -24,6 +24,7 @@ import dropbox from "./dropbox/app"; import googledrive from "./googledrive/app"; import { env } from "./lib/env"; import { requestCounter, requestDuration } from "./metrics"; +import "./profiling"; import albumTracks from "./schema/album-tracks"; import albums from "./schema/albums"; import artistTracks from "./schema/artist-tracks"; diff --git a/apps/api/src/lexicon/types/app/rocksky/apikey/createApikey.ts b/apps/api/src/lexicon/types/app/rocksky/apikey/createApikey.ts index 5e12653e..361b4902 100644 --- a/apps/api/src/lexicon/types/app/rocksky/apikey/createApikey.ts +++ b/apps/api/src/lexicon/types/app/rocksky/apikey/createApikey.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyApikeyDefs from "./defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The name of the API key. */ diff --git a/apps/api/src/lexicon/types/app/rocksky/apikey/updateApikey.ts b/apps/api/src/lexicon/types/app/rocksky/apikey/updateApikey.ts index 639a3d05..98edcefb 100644 --- a/apps/api/src/lexicon/types/app/rocksky/apikey/updateApikey.ts +++ b/apps/api/src/lexicon/types/app/rocksky/apikey/updateApikey.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyApikeyDefs from "./defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The ID of the API key to update. */ diff --git a/apps/api/src/lexicon/types/app/rocksky/like/dislikeShout.ts b/apps/api/src/lexicon/types/app/rocksky/like/dislikeShout.ts index cce29e93..666c305a 100644 --- a/apps/api/src/lexicon/types/app/rocksky/like/dislikeShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/like/dislikeShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "../shout/defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The unique identifier of the shout to dislike */ diff --git a/apps/api/src/lexicon/types/app/rocksky/like/dislikeSong.ts b/apps/api/src/lexicon/types/app/rocksky/like/dislikeSong.ts index ac21497a..2e7efea3 100644 --- a/apps/api/src/lexicon/types/app/rocksky/like/dislikeSong.ts +++ b/apps/api/src/lexicon/types/app/rocksky/like/dislikeSong.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskySongDefs from "../song/defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The unique identifier of the song to dislike */ diff --git a/apps/api/src/lexicon/types/app/rocksky/like/likeShout.ts b/apps/api/src/lexicon/types/app/rocksky/like/likeShout.ts index 8d652876..46307d1d 100644 --- a/apps/api/src/lexicon/types/app/rocksky/like/likeShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/like/likeShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "../shout/defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The unique identifier of the shout to like */ diff --git a/apps/api/src/lexicon/types/app/rocksky/like/likeSong.ts b/apps/api/src/lexicon/types/app/rocksky/like/likeSong.ts index 3f36fdb9..b0f4d600 100644 --- a/apps/api/src/lexicon/types/app/rocksky/like/likeSong.ts +++ b/apps/api/src/lexicon/types/app/rocksky/like/likeSong.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskySongDefs from "../song/defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The unique identifier of the song to like */ diff --git a/apps/api/src/lexicon/types/app/rocksky/scrobble/createScrobble.ts b/apps/api/src/lexicon/types/app/rocksky/scrobble/createScrobble.ts index 507ad0e3..b746c4ea 100644 --- a/apps/api/src/lexicon/types/app/rocksky/scrobble/createScrobble.ts +++ b/apps/api/src/lexicon/types/app/rocksky/scrobble/createScrobble.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyScrobbleDefs from "./defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The title of the track being scrobbled */ diff --git a/apps/api/src/lexicon/types/app/rocksky/shout/createShout.ts b/apps/api/src/lexicon/types/app/rocksky/shout/createShout.ts index 8e4df585..b51daaa3 100644 --- a/apps/api/src/lexicon/types/app/rocksky/shout/createShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/shout/createShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "./defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The content of the shout */ diff --git a/apps/api/src/lexicon/types/app/rocksky/shout/replyShout.ts b/apps/api/src/lexicon/types/app/rocksky/shout/replyShout.ts index f4f5e9bb..83800a07 100644 --- a/apps/api/src/lexicon/types/app/rocksky/shout/replyShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/shout/replyShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "./defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The unique identifier of the shout to reply to */ diff --git a/apps/api/src/lexicon/types/app/rocksky/shout/reportShout.ts b/apps/api/src/lexicon/types/app/rocksky/shout/reportShout.ts index b71fefbd..fb808117 100644 --- a/apps/api/src/lexicon/types/app/rocksky/shout/reportShout.ts +++ b/apps/api/src/lexicon/types/app/rocksky/shout/reportShout.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskyShoutDefs from "./defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The unique identifier of the shout to report */ diff --git a/apps/api/src/lexicon/types/app/rocksky/song/createSong.ts b/apps/api/src/lexicon/types/app/rocksky/song/createSong.ts index 791c6966..f196c2e4 100644 --- a/apps/api/src/lexicon/types/app/rocksky/song/createSong.ts +++ b/apps/api/src/lexicon/types/app/rocksky/song/createSong.ts @@ -9,7 +9,7 @@ import { CID } from "multiformats/cid"; import type { HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; import type * as AppRockskySongDefs from "./defs"; -export type QueryParams = {}; +export type QueryParams = {} export interface InputSchema { /** The title of the song */ diff --git a/apps/api/src/lexicon/types/app/rocksky/spotify/next.ts b/apps/api/src/lexicon/types/app/rocksky/spotify/next.ts index c404dc11..66110356 100644 --- a/apps/api/src/lexicon/types/app/rocksky/spotify/next.ts +++ b/apps/api/src/lexicon/types/app/rocksky/spotify/next.ts @@ -8,7 +8,7 @@ import { isObj, hasProp } from "../../../../util"; import { CID } from "multiformats/cid"; import { type HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; -export type QueryParams = {}; +export type QueryParams = {} export type InputSchema = undefined; export type HandlerInput = undefined; diff --git a/apps/api/src/lexicon/types/app/rocksky/spotify/pause.ts b/apps/api/src/lexicon/types/app/rocksky/spotify/pause.ts index c404dc11..66110356 100644 --- a/apps/api/src/lexicon/types/app/rocksky/spotify/pause.ts +++ b/apps/api/src/lexicon/types/app/rocksky/spotify/pause.ts @@ -8,7 +8,7 @@ import { isObj, hasProp } from "../../../../util"; import { CID } from "multiformats/cid"; import { type HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; -export type QueryParams = {}; +export type QueryParams = {} export type InputSchema = undefined; export type HandlerInput = undefined; diff --git a/apps/api/src/lexicon/types/app/rocksky/spotify/play.ts b/apps/api/src/lexicon/types/app/rocksky/spotify/play.ts index c404dc11..66110356 100644 --- a/apps/api/src/lexicon/types/app/rocksky/spotify/play.ts +++ b/apps/api/src/lexicon/types/app/rocksky/spotify/play.ts @@ -8,7 +8,7 @@ import { isObj, hasProp } from "../../../../util"; import { CID } from "multiformats/cid"; import { type HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; -export type QueryParams = {}; +export type QueryParams = {} export type InputSchema = undefined; export type HandlerInput = undefined; diff --git a/apps/api/src/lexicon/types/app/rocksky/spotify/previous.ts b/apps/api/src/lexicon/types/app/rocksky/spotify/previous.ts index c404dc11..66110356 100644 --- a/apps/api/src/lexicon/types/app/rocksky/spotify/previous.ts +++ b/apps/api/src/lexicon/types/app/rocksky/spotify/previous.ts @@ -8,7 +8,7 @@ import { isObj, hasProp } from "../../../../util"; import { CID } from "multiformats/cid"; import { type HandlerAuth, HandlerPipeThrough } from "@atproto/xrpc-server"; -export type QueryParams = {}; +export type QueryParams = {} export type InputSchema = undefined; export type HandlerInput = undefined; diff --git a/apps/api/src/nowplaying/nowplaying.service.ts b/apps/api/src/nowplaying/nowplaying.service.ts index d1875e80..4709a055 100644 --- a/apps/api/src/nowplaying/nowplaying.service.ts +++ b/apps/api/src/nowplaying/nowplaying.service.ts @@ -26,7 +26,7 @@ import tealfm from "../tealfm"; export async function putArtistRecord( track: Track, - agent: Agent, + agent: Agent ): Promise { const rkey = TID.nextStr(); const record: Artist.Record = { @@ -62,7 +62,7 @@ export async function putArtistRecord( export async function putAlbumRecord( track: Track, - agent: Agent, + agent: Agent ): Promise { const rkey = TID.nextStr(); @@ -103,7 +103,7 @@ export async function putAlbumRecord( export async function putSongRecord( track: Track, - agent: Agent, + agent: Agent ): Promise { const rkey = TID.nextStr(); @@ -158,7 +158,7 @@ export async function putSongRecord( async function putScrobbleRecord( track: Track, - agent: Agent, + agent: Agent ): Promise { const rkey = TID.nextStr(); @@ -276,8 +276,8 @@ export async function publishScrobble(ctx: Context, id: string) { .where( and( eq(artistAlbums.albumId, scrobble.album.id), - eq(artistAlbums.artistId, scrobble.artist.id), - ), + eq(artistAlbums.artistId, scrobble.artist.id) + ) ) .limit(1) .then((rows) => rows[0]), @@ -440,12 +440,12 @@ export async function publishScrobble(ctx: Context, id: string) { }, }), null, - 2, + 2 ); ctx.nc.publish( "rocksky.scrobble", - Buffer.from(message.replaceAll("sha_256", "sha256")), + Buffer.from(message.replaceAll("sha_256", "sha256")) ); const trackMessage = JSON.stringify( @@ -492,12 +492,12 @@ export async function publishScrobble(ctx: Context, id: string) { xata_createdat: artist_album.createdAt.toISOString(), xata_updatedat: artist_album.updatedAt.toISOString(), }, - }), + }) ); ctx.nc.publish( "rocksky.track", - Buffer.from(trackMessage.replaceAll("sha_256", "sha256")), + Buffer.from(trackMessage.replaceAll("sha_256", "sha256")) ); } @@ -505,7 +505,7 @@ export async function scrobbleTrack( ctx: Context, track: Track, agent: Agent, - userDid: string, + userDid: string ): Promise { // check if scrobble already exists (user did + timestamp) const scrobbleTime = dayjs.unix(track.timestamp || dayjs().unix()); @@ -524,8 +524,8 @@ export async function scrobbleTrack( eq(tracks.title, track.title), eq(tracks.artist, track.artist), gte(scrobbles.timestamp, scrobbleTime.subtract(60, "seconds").toDate()), - lte(scrobbles.timestamp, scrobbleTime.add(60, "seconds").toDate()), - ), + lte(scrobbles.timestamp, scrobbleTime.add(60, "seconds").toDate()) + ) ) .limit(1) .then((rows) => rows[0]); @@ -533,8 +533,8 @@ export async function scrobbleTrack( if (existingScrobble) { console.log( `Scrobble already exists for ${chalk.cyan(track.title)} at ${chalk.cyan( - scrobbleTime.format("YYYY-MM-DD HH:mm:ss"), - )}`, + scrobbleTime.format("YYYY-MM-DD HH:mm:ss") + )}` ); return; } @@ -547,10 +547,10 @@ export async function scrobbleTrack( tracks.sha256, createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); @@ -564,8 +564,8 @@ export async function scrobbleTrack( albums.sha256, createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); @@ -586,8 +586,8 @@ export async function scrobbleTrack( artists.sha256, createHash("sha256") .update(track.albumArtist.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); @@ -618,7 +618,7 @@ export async function scrobbleTrack( artist: track.artist.split(",").map((a) => ({ name: a.trim() })), name: track.title, album: track.album, - }, + } ); if (!mbTrack?.trackMBID) { @@ -647,8 +647,8 @@ export async function scrobbleTrack( albums.sha256, createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); @@ -664,10 +664,10 @@ export async function scrobbleTrack( tracks.sha256, createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); @@ -681,7 +681,7 @@ export async function scrobbleTrack( if (existingTrack) { console.log( - `Song found: ${chalk.cyan(existingTrack.id)} - ${track.title}, after ${chalk.magenta(tries)} tries`, + `Song found: ${chalk.cyan(existingTrack.id)} - ${track.title}, after ${chalk.magenta(tries)} tries` ); } @@ -694,13 +694,13 @@ export async function scrobbleTrack( artists.sha256, createHash("sha256") .update(track.albumArtist.toLowerCase()) - .digest("hex"), + .digest("hex") ), eq( artists.sha256, - createHash("sha256").update(track.artist.toLowerCase()).digest("hex"), - ), - ), + createHash("sha256").update(track.artist.toLowerCase()).digest("hex") + ) + ) ) .limit(1) .then((rows) => rows[0]); @@ -715,7 +715,7 @@ export async function scrobbleTrack( .innerJoin(artists, eq(userArtists.artistId, artists.id)) .innerJoin(users, eq(userArtists.userId, users.id)) .where( - and(eq(artists.id, existingArtist?.id || ""), eq(users.did, userDid)), + and(eq(artists.id, existingArtist?.id || ""), eq(users.did, userDid)) ) .limit(1) .then((rows) => rows[0]); @@ -750,17 +750,17 @@ export async function scrobbleTrack( tracks.sha256, createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); while (!existingTrack?.artistUri && !existingTrack?.albumUri && tries < 30) { console.log( - `Artist uri not ready, trying again: ${chalk.magenta(tries + 1)}`, + `Artist uri not ready, trying again: ${chalk.magenta(tries + 1)}` ); existingTrack = await ctx.db .select() @@ -770,10 +770,10 @@ export async function scrobbleTrack( tracks.sha256, createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); @@ -788,8 +788,8 @@ export async function scrobbleTrack( artists.sha256, createHash("sha256") .update(track.albumArtist.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); @@ -812,8 +812,8 @@ export async function scrobbleTrack( albums.sha256, createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .limit(1) .then((rows) => rows[0]); @@ -843,7 +843,7 @@ export async function scrobbleTrack( if (existingTrack?.artistUri) { console.log( - `Artist uri ready: ${chalk.cyan(existingTrack.id)} - ${track.title}, after ${chalk.magenta(tries)} tries`, + `Artist uri ready: ${chalk.cyan(existingTrack.id)} - ${track.title}, after ${chalk.magenta(tries)} tries` ); } diff --git a/apps/api/src/profiling.ts b/apps/api/src/profiling.ts new file mode 100644 index 00000000..856b3adc --- /dev/null +++ b/apps/api/src/profiling.ts @@ -0,0 +1,13 @@ +import Pyroscope from "@pyroscope/nodejs"; + +Pyroscope.init({ + serverAddress: "http://localhost:4040", + appName: "rocksky-api", + // Enable CPU time collection for wall profiles + // This is required for CPU profiling functionality + // wall: { + // collectCpuTime: true + // } +}); + +Pyroscope.start(); diff --git a/apps/api/src/sqliteKv.ts b/apps/api/src/sqliteKv.ts index 665d3084..fab414df 100644 --- a/apps/api/src/sqliteKv.ts +++ b/apps/api/src/sqliteKv.ts @@ -1,6 +1,5 @@ -import { Database } from "bun:sqlite"; -import { Kysely } from "kysely"; -import { BunSqliteDialect } from "kysely-bun-sqlite"; +import Database from "better-sqlite3"; +import { Kysely, SqliteDialect } from "kysely"; import { defineDriver } from "unstorage"; interface TableSchema { @@ -39,13 +38,13 @@ export default defineDriver< throw new Error("SQLite location is required"); } - const sqlite = new Database(location); + const sqlite = new Database(location, { fileMustExist: false }); // Enable WAL mode - sqlite.run("PRAGMA journal_mode = WAL;"); + sqlite.pragma("journal_mode = WAL"); _db = new Kysely({ - dialect: new BunSqliteDialect({ + dialect: new SqliteDialect({ database: sqlite, }), }); diff --git a/apps/api/src/tealfm/index.ts b/apps/api/src/tealfm/index.ts index 56da8a33..f146e35a 100644 --- a/apps/api/src/tealfm/index.ts +++ b/apps/api/src/tealfm/index.ts @@ -20,7 +20,7 @@ async function getRecentPlays(agent: Agent, limit = 5) { async function publishPlayingNow( agent: Agent, track: MusicbrainzTrack, - duration: number, + duration: number ) { try { // wait 60 seconds to ensure the track is actually being played @@ -34,15 +34,15 @@ async function publishPlayingNow( // diff in seconds less than 60 Math.abs( new Date(record.playedTime).getTime() - - new Date(track.timestamp).getTime(), + new Date(track.timestamp).getTime() ) < 60000 ); }); if (alreadyPlayed) { console.log( `Track ${chalk.cyan(track.name)} by ${chalk.cyan( - track.artist.map((a) => a.name).join(", "), - )} already played recently. Skipping...`, + track.artist.map((a) => a.name).join(", ") + )} already played recently. Skipping...` ); return; } @@ -88,7 +88,7 @@ async function publishPlayingNow( async function publishStatus( agent: Agent, track: MusicbrainzTrack, - duration: number, + duration: number ) { const item: PlayView = { trackName: track.name, diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 40346049..8beb9616 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -22,7 +22,7 @@ "target": "esnext", "module": "esnext", "types": [ - "@types/bun", + "@types/node", "@types/service-worker-mock", "@cloudflare/workers-types/2023-07-01" ] diff --git a/bun.lock b/bun.lock index 5752803b..ec58ce7b 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,6 @@ "name": "rocksky", "devDependencies": { "@biomejs/biome": "^2.2.3", - "@types/bun": "^1.3.0", "prettier": "^3.5.3", "turbo": "^2.5.8", }, @@ -17,7 +16,6 @@ "@atproto/api": "^0.13.31", "@atproto/common": "^0.4.6", "@atproto/identity": "^0.4.5", - "@atproto/jwk-jose": "0.1.8", "@atproto/lex-cli": "^0.5.6", "@atproto/lexicon": "^0.4.5", "@atproto/oauth-client-node": "^0.2.14", @@ -34,8 +32,10 @@ "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-node": "^0.200.0", "@opentelemetry/semantic-conventions": "^1.32.0", + "@pyroscope/nodejs": "^0.4.5", "assert": "^2.1.0", "axios": "^1.7.9", + "better-sqlite3": "^11.8.1", "chalk": "^5.4.1", "chanfana": "^2.0.2", "cors": "^2.8.5", @@ -51,8 +51,7 @@ "http-proxy-middleware": "^3.0.5", "iron-session": "^8.0.4", "jsonwebtoken": "^9.0.2", - "kysely": "^0.28.8", - "kysely-bun-sqlite": "^0.4.0", + "kysely": "^0.27.5", "lodash": "^4.17.21", "nats": "^2.29.2", "pg": "^8.13.3", @@ -67,7 +66,6 @@ "devDependencies": { "@biomejs/biome": "^2.2.3", "@pkl-community/pkl": "^0.28.2", - "@types/bun": "^1.3.0", "@types/express": "^5.0.2", "@types/lodash": "^4.17.17", "@types/node": "^22.13.0", @@ -76,6 +74,7 @@ "concurrently": "^9.2.0", "drizzle-kit": "^0.31.1", "pkgroll": "^2.6.1", + "tsx": "^4.19.2", "zx": "^8.5.4", }, }, @@ -502,6 +501,8 @@ "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], + "@datadog/pprof": ["@datadog/pprof@5.8.2", "", { "dependencies": { "delay": "^5.0.0", "node-gyp-build": "<4.0", "p-limit": "^3.1.0", "pprof-format": "^2.1.0", "source-map": "^0.7.4" } }, "sha512-M+bO4v4TaxYK6k2qJBxnhf7Vh25Wode64y4LfxzGs5kLTFr8eFTp6HJai3/af7U5gjTHX/4s+CHv2bxja97pbw=="], + "@date-io/core": ["@date-io/core@2.17.0", "", {}, "sha512-+EQE8xZhRM/hsY0CDTVyayMDDY5ihc4MqXCrPxooKw19yAzUIC6uUqsZeaOFNL9YKTNxYKrJP5DFgE8o5xRCOw=="], "@date-io/date-fns": ["@date-io/date-fns@2.17.0", "", { "dependencies": { "@date-io/core": "^2.17.0" }, "peerDependencies": { "date-fns": "^2.0.0" }, "optionalPeers": ["date-fns"] }, "sha512-L0hWZ/mTpy3Gx/xXJ5tq5CzHo0L7ry6KEO9/w/JWiFWFLZgiNVo3ex92gOl3zmzjHqY/3Ev+5sehAr8UnGLEng=="], @@ -918,6 +919,8 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + "@pyroscope/nodejs": ["@pyroscope/nodejs@0.4.5", "", { "dependencies": { "@datadog/pprof": "^5.4.1", "debug": "^4.3.3", "p-limit": "^3.1.0", "regenerator-runtime": "^0.13.11", "source-map": "^0.7.3" } }, "sha512-39YVwmLA2QhmLEd/yZjkjvAdU16kH0CiH6KY4wd1O4Lz7CszLW3/q2b33RAegdpnFmu8pPMhDcrPl/79mkjI0g=="], + "@redis/bloom": ["@redis/bloom@1.2.0", "", { "peerDependencies": { "@redis/client": "^1.0.0" } }, "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg=="], "@redis/client": ["@redis/client@1.6.1", "", { "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", "yallist": "4.0.0" } }, "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw=="], @@ -1214,8 +1217,6 @@ "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], - "@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="], - "@types/bunyan": ["@types/bunyan@1.8.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ=="], "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], @@ -1410,7 +1411,7 @@ "better-opn": ["better-opn@3.0.2", "", { "dependencies": { "open": "^8.0.4" } }, "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ=="], - "better-sqlite3": ["better-sqlite3@12.4.1", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-3yVdyZhklTiNrtg+4WqHpJpFDd+WHTg2oM7UcR80GqL05AOV0xEJzc6qNvFYoEtE+hRp1n9MpN6/+4yhlGkDXQ=="], + "better-sqlite3": ["better-sqlite3@11.10.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ=="], "bignumber.js": ["bignumber.js@9.3.0", "", {}, "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA=="], @@ -1440,8 +1441,6 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="], - "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], @@ -1480,7 +1479,7 @@ "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], "chromatic": ["chromatic@11.29.0", "", { "peerDependencies": { "@chromatic-com/cypress": "^0.*.* || ^1.0.0", "@chromatic-com/playwright": "^0.*.* || ^1.0.0" }, "optionalPeers": ["@chromatic-com/cypress", "@chromatic-com/playwright"], "bin": { "chroma": "dist/bin.js", "chromatic": "dist/bin.js", "chromatic-cli": "dist/bin.js" } }, "sha512-yisBlntp9hHVj19lIQdpTlcYIXuU9H/DbFuu6tyWHmj6hWT2EtukCCcxYXL78XdQt1vm2GfIrtgtKpj/Rzmo4A=="], @@ -1652,6 +1651,8 @@ "delaunator": ["delaunator@4.0.1", "", {}, "sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag=="], + "delay": ["delay@5.0.0", "", {}, "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw=="], + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], @@ -2058,9 +2059,7 @@ "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - "kysely": ["kysely@0.28.8", "", {}, "sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA=="], - - "kysely-bun-sqlite": ["kysely-bun-sqlite@0.4.0", "", { "dependencies": { "bun-types": "^1.1.31" }, "peerDependencies": { "kysely": "^0.28.2" } }, "sha512-2EkQE5sT4ewiw7IWfJsAkpxJ/QPVKXKO5sRYI/xjjJIJlECuOdtG+ssYM0twZJySrdrmuildNPFYVreyu1EdZg=="], + "kysely": ["kysely@0.27.6", "", {}, "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ=="], "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], @@ -2208,6 +2207,8 @@ "node-fetch-native": ["node-fetch-native@1.6.6", "", {}, "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ=="], + "node-gyp-build": ["node-gyp-build@3.9.0", "", { "bin": { "node-gyp-build": "./bin.js", "node-gyp-build-test": "./build-test.js", "node-gyp-build-optional": "./optional.js" } }, "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A=="], + "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.1.1", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-test": "build-test.js", "node-gyp-build-optional-packages-optional": "optional.js" } }, "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw=="], "node-mock-http": ["node-mock-http@1.0.0", "", {}, "sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ=="], @@ -2336,6 +2337,8 @@ "potpack": ["potpack@1.0.2", "", {}, "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ=="], + "pprof-format": ["pprof-format@2.1.0", "", {}, "sha512-0+G5bHH0RNr8E5hoZo/zJYsL92MhkZjwrHp3O2IxmY8RJL9ooKeuZ8Tm0ZNBw5sGZ9TiM71sthTjWoR2Vf5/xw=="], + "preact": ["preact@10.26.9", "", {}, "sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA=="], "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], @@ -2458,6 +2461,8 @@ "redis": ["redis@4.7.1", "", { "dependencies": { "@redis/bloom": "1.2.0", "@redis/client": "1.6.1", "@redis/graph": "1.1.1", "@redis/json": "1.0.7", "@redis/search": "1.2.0", "@redis/time-series": "1.1.0" } }, "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ=="], + "regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="], + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], @@ -3200,12 +3205,12 @@ "table/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], + "tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + "tar/mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "tar-fs/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], - "tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "type-is/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], diff --git a/package.json b/package.json index 43658606..de38cafc 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "version": "0.0.0", "devDependencies": { "@biomejs/biome": "^2.2.3", - "@types/bun": "^1.3.0", "prettier": "^3.5.3", "turbo": "^2.5.8" }, -- 2.51.2