diff --git a/Dockerfile b/Dockerfile index 45eae1c..5d79643 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,6 @@ RUN pnpm install --prod --frozen-lockfile FROM base AS build RUN pnpm install --frozen-lockfile RUN pnpm run tailwind:build -RUN pnpm run generate RUN pnpm run build FROM base diff --git a/README.md b/README.md index 0efd813..2269533 100644 --- a/README.md +++ b/README.md @@ -12,25 +12,20 @@ Skymoth is an open source service which allows you to share the content you post - Reposting text (and handle threads) - Reposting (multiple) images with alt descriptions -## Things to do +## Migrating from <= v0.3.2 to > v0.4.0 -- More media reposting options -- Taking Bluesky posts over to Mastodon (this is quite rough thanks to rate limits) -- A better frontend (I know, I usually do UI/UX myself but this was not the priority here) -- Per instance polling intervals +With v0.4.0 Drizzle will be the new ORM of choice. Thus Prisma and its migration tracking table +will be dropped accordingly. To make the upgrading process go smoothly, Skymoth checks if all migrations +from Prisma have been applied before migrating. If you have an instance running on a version below v0.3.2 +upgrade to v0.3.2 first before upgrading to v0.4.0 and above. + +Additionally, Drizzle will execute its migrations automatically on app startup, so there is no need to run `pnpm migrate` +after an update. ## Development For development using [Cachix Devenv](https://devenv.sh/) is strongly advised. -After setting up, you can just enter this projects shell. - -Before starting the project you need to copy the `.env.local` over to `.env`: - -```bash -cp .env.local .env -``` - -and modify it to to your needs. Then install all javascript dependencies by executing +After setting up, you can just enter this projects shell just run: ```bash pnpm install @@ -42,15 +37,6 @@ Don't worry, if set up correctly the development shell you are in should contain devenv up ``` -after starting you may need to run - -```bash -pnpm migrate -pnpm generate -``` - -to apply all migrations. - ## FAQ ### Is this free to use? diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..9b981fb --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'drizzle-kit'; +export default defineConfig({ + dialect: 'postgresql', + out: './drizzle', + schema: './drizzle/schema.ts', + dbCredentials: { + url: process.env.POSTGRES_URL!, + }, + // Print all statements + verbose: true, + // Always ask for confirmation + strict: true, +}); \ No newline at end of file diff --git a/drizzle/0000_shallow_puck.sql b/drizzle/0000_shallow_puck.sql new file mode 100644 index 0000000..f736a11 --- /dev/null +++ b/drizzle/0000_shallow_puck.sql @@ -0,0 +1,46 @@ +CREATE TYPE "public"."RelayCriteria" AS ENUM('all', 'favedBySelf', 'containsMarker', 'notContainsMarker');--> statement-breakpoint +CREATE TYPE "public"."StatusVisibility" AS ENUM('public', 'unlisted', 'private', 'direct');--> statement-breakpoint +CREATE TABLE "MastodonInstance" ( + "id" text PRIMARY KEY NOT NULL, + "urlEncoded" text NOT NULL, + "url" text NOT NULL, + "applicationId" text NOT NULL, + "applicationSecret" text NOT NULL, + "createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL, + "updatedAt" timestamp(3) NOT NULL +); +--> statement-breakpoint +CREATE TABLE "Repost" ( + "id" text PRIMARY KEY NOT NULL, + "createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL, + "userId" text NOT NULL, + "tootId" text NOT NULL, + "bsRootUri" text NOT NULL, + "bsRootCid" text NOT NULL, + "bsParentUri" text NOT NULL, + "bsParentCid" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE "User" ( + "id" text PRIMARY KEY NOT NULL, + "createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL, + "updatedAt" timestamp(3) NOT NULL, + "lastTootTime" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL, + "name" text NOT NULL, + "mastodonUid" text NOT NULL, + "mastodonToken" text NOT NULL, + "blueskyToken" text, + "blueskyHandle" text, + "blueskySession" jsonb, + "blueskySessionEvent" text, + "mastodonInstanceId" text NOT NULL, + "blueskyPDS" text DEFAULT 'https://bsky.social', + "relayCriteria" "RelayCriteria" DEFAULT 'all' NOT NULL, + "relayMarker" text DEFAULT '' NOT NULL, + "relayVisibility" "StatusVisibility"[] DEFAULT '{"public"}' +); +--> statement-breakpoint +ALTER TABLE "Repost" ADD CONSTRAINT "Repost_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint +ALTER TABLE "User" ADD CONSTRAINT "User_mastodonInstanceId_fkey" FOREIGN KEY ("mastodonInstanceId") REFERENCES "public"."MastodonInstance"("id") ON DELETE restrict ON UPDATE cascade;--> statement-breakpoint +CREATE UNIQUE INDEX "MastodonInstance_urlEncoded_key" ON "MastodonInstance" USING btree ("urlEncoded" text_ops);--> statement-breakpoint +CREATE UNIQUE INDEX "MastodonInstance_url_key" ON "MastodonInstance" USING btree ("url" text_ops); \ No newline at end of file diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000..efc4d55 --- /dev/null +++ b/drizzle/meta/0000_snapshot.json @@ -0,0 +1,335 @@ +{ + "id": "58cc204b-20a1-46ec-bdd9-af80b2d707f0", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.MastodonInstance": { + "name": "MastodonInstance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "urlEncoded": { + "name": "urlEncoded", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationSecret": { + "name": "applicationSecret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "MastodonInstance_urlEncoded_key": { + "name": "MastodonInstance_urlEncoded_key", + "columns": [ + { + "expression": "urlEncoded", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "MastodonInstance_url_key": { + "name": "MastodonInstance_url_key", + "columns": [ + { + "expression": "url", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.Repost": { + "name": "Repost", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tootId": { + "name": "tootId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bsRootUri": { + "name": "bsRootUri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bsRootCid": { + "name": "bsRootCid", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bsParentUri": { + "name": "bsParentUri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bsParentCid": { + "name": "bsParentCid", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "Repost_userId_fkey": { + "name": "Repost_userId_fkey", + "tableFrom": "Repost", + "tableTo": "User", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.User": { + "name": "User", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "lastTootTime": { + "name": "lastTootTime", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mastodonUid": { + "name": "mastodonUid", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mastodonToken": { + "name": "mastodonToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "blueskyToken": { + "name": "blueskyToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "blueskyHandle": { + "name": "blueskyHandle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "blueskySession": { + "name": "blueskySession", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "blueskySessionEvent": { + "name": "blueskySessionEvent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mastodonInstanceId": { + "name": "mastodonInstanceId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "blueskyPDS": { + "name": "blueskyPDS", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'https://bsky.social'" + }, + "relayCriteria": { + "name": "relayCriteria", + "type": "RelayCriteria", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'all'" + }, + "relayMarker": { + "name": "relayMarker", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "relayVisibility": { + "name": "relayVisibility", + "type": "StatusVisibility[]", + "primaryKey": false, + "notNull": false, + "default": "'{\"public\"}'" + } + }, + "indexes": {}, + "foreignKeys": { + "User_mastodonInstanceId_fkey": { + "name": "User_mastodonInstanceId_fkey", + "tableFrom": "User", + "tableTo": "MastodonInstance", + "columnsFrom": [ + "mastodonInstanceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.RelayCriteria": { + "name": "RelayCriteria", + "schema": "public", + "values": [ + "all", + "favedBySelf", + "containsMarker", + "notContainsMarker" + ] + }, + "public.StatusVisibility": { + "name": "StatusVisibility", + "schema": "public", + "values": [ + "public", + "unlisted", + "private", + "direct" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 0000000..340b938 --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1737818942346, + "tag": "0000_shallow_puck", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/drizzle/relations.ts b/drizzle/relations.ts new file mode 100644 index 0000000..87fadb9 --- /dev/null +++ b/drizzle/relations.ts @@ -0,0 +1,21 @@ +import { relations } from "drizzle-orm/relations"; +import { mastodonInstance, user, repost } from "./schema"; + +export const userRelations = relations(user, ({one, many}) => ({ + mastodonInstance: one(mastodonInstance, { + fields: [user.mastodonInstanceId], + references: [mastodonInstance.id] + }), + reposts: many(repost), +})); + +export const mastodonInstanceRelations = relations(mastodonInstance, ({many}) => ({ + users: many(user), +})); + +export const repostRelations = relations(repost, ({one}) => ({ + user: one(user, { + fields: [repost.userId], + references: [user.id] + }), +})); \ No newline at end of file diff --git a/drizzle/schema.ts b/drizzle/schema.ts new file mode 100644 index 0000000..24c116b --- /dev/null +++ b/drizzle/schema.ts @@ -0,0 +1,60 @@ +import { pgTable, varchar, timestamp, text, integer, uniqueIndex, foreignKey, jsonb, pgEnum } from "drizzle-orm/pg-core" +import { randomUUID } from "node:crypto"; + +export const relayCriteria = pgEnum("RelayCriteria", ['all', 'favedBySelf', 'containsMarker', 'notContainsMarker']) +export const statusVisibility = pgEnum("StatusVisibility", ['public', 'unlisted', 'private', 'direct']) + +export const mastodonInstance = pgTable("MastodonInstance", { + id: text().primaryKey().notNull().$defaultFn(() => randomUUID()), + urlEncoded: text().notNull(), + url: text().notNull(), + applicationId: text().notNull(), + applicationSecret: text().notNull(), + createdAt: timestamp({ precision: 3, mode: 'date' }).notNull().defaultNow(), + updatedAt: timestamp({ precision: 3, mode: 'date' }).notNull().defaultNow(), +}, (table) => [ + uniqueIndex("MastodonInstance_urlEncoded_key").using("btree", table.urlEncoded.asc().nullsLast().op("text_ops")), + uniqueIndex("MastodonInstance_url_key").using("btree", table.url.asc().nullsLast().op("text_ops")), +]); + +export const repost = pgTable("Repost", { + id: text().primaryKey().notNull().$defaultFn(() => randomUUID()), + createdAt: timestamp({ precision: 3, mode: 'date' }).defaultNow(), + userId: text().notNull(), + tootId: text().notNull(), + bsRootUri: text().notNull(), + bsRootCid: text().notNull(), + bsParentUri: text().notNull(), + bsParentCid: text().notNull(), +}, (table) => [ + foreignKey({ + columns: [table.userId], + foreignColumns: [user.id], + name: "Repost_userId_fkey" + }).onUpdate("cascade").onDelete("cascade"), +]); + +export const user = pgTable("User", { + id: text().primaryKey().notNull().$defaultFn(() => randomUUID()), + createdAt: timestamp({ precision: 3, mode: 'date' }).defaultNow().notNull(), + updatedAt: timestamp({ precision: 3, mode: 'date' }).defaultNow().notNull(), + lastTootTime: timestamp({ precision: 3, mode: 'date' }).defaultNow().notNull(), + name: text().notNull(), + mastodonUid: text().notNull(), + mastodonToken: text().notNull(), + blueskyToken: text(), + blueskyHandle: text(), + blueskySession: jsonb(), + blueskySessionEvent: text(), + mastodonInstanceId: text().notNull(), + blueskyPDS: text().default('https://bsky.social'), + relayCriteria: relayCriteria().default('all').notNull(), + relayMarker: text().default('').notNull(), + relayVisibility: statusVisibility().array().default(['public']), +}, (table) => [ + foreignKey({ + columns: [table.mastodonInstanceId], + foreignColumns: [mastodonInstance.id], + name: "User_mastodonInstanceId_fkey" + }).onUpdate("cascade").onDelete("restrict"), +]); diff --git a/example.compose.yml b/example.compose.yml index b6b4ef3..2c87311 100644 --- a/example.compose.yml +++ b/example.compose.yml @@ -12,10 +12,19 @@ services: - "3000:3000" links: - db + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/health"] + interval: 1m + timeout: 5s + start_period: 2m + start_interval: 5s + retries: 60 skymoth-scheduler: depends_on: db: condition: service_healthy + skymoth: + condition: service_healthy build: . restart: always env_file: .env diff --git a/index.ts b/index.ts index feb306d..e9bde0d 100644 --- a/index.ts +++ b/index.ts @@ -12,8 +12,8 @@ import { nodeProfilingIntegration } from "@sentry/profiling-node"; import { readFileSync } from 'fs'; import { join as pathJoin } from 'path'; import { printInfo } from './lib/utils'; - -const { ADDRESS = 'localhost', PORT = '3000' } = process.env; +import { client, db } from './lib/db'; +import { migrationHelper } from './lib/migration'; declare module "@fastify/jwt" { interface FastifyJWT { @@ -30,63 +30,71 @@ export const app = Fastify({ logger: true }) -if (process.env.SENTRY_DSN) { - Sentry.init({ - dsn: process.env.SENTRY_DSN, - integrations: [ - nodeProfilingIntegration(), - ], - tracesSampleRate: 1.0, - profilesSampleRate: 1.0, - }); -} - -let version = "development" - -const gitRevPath = pathJoin(__dirname, '.git-rev') -if (require('fs').existsSync(gitRevPath)) { - version = readFileSync(gitRevPath, 'utf-8').trim() -} - -app.register(fastifyCookie) -app.register(fastifyFormbody) -app.register(fastifyView, { - engine: { - liquid: new Liquid({ - root: join(__dirname, "views"), - extname: ".liquid", - globals: { - version, - } - }) - }, - root: join(__dirname, "views"), - production: false, - maxCache: 0, - options: { - noCache: true, - }, -}); - -app.register(require('@fastify/static'), { - root: join(__dirname, 'public'), -}) +client.connect(); -app.register(fastifyJwt, { - secret: process.env.JWT_SECRET ?? 'this_shoudl_not_be_used_in_production', - cookie: { - cookieName: 'token', - signed: false, +migrationHelper().then(() => { + const { ADDRESS = 'localhost', PORT = '3000' } = process.env; + + if (process.env.SENTRY_DSN) { + Sentry.init({ + dsn: process.env.SENTRY_DSN, + integrations: [ + nodeProfilingIntegration(), + ], + tracesSampleRate: 1.0, + profilesSampleRate: 1.0, + }); } -}) - -app.register(routesRoot) -app.register(routesUser) - -app.listen({ host: ADDRESS, port: parseInt(PORT, 10) }, function (err, address) { - if (err) { - app.log.error(err) + + let version = "development" + + const gitRevPath = pathJoin(__dirname, '.git-rev') + if (require('fs').existsSync(gitRevPath)) { + version = readFileSync(gitRevPath, 'utf-8').trim() } -}) - -printInfo(); \ No newline at end of file + + app.register(fastifyCookie) + app.register(fastifyFormbody) + app.register(fastifyView, { + engine: { + liquid: new Liquid({ + root: join(__dirname, "views"), + extname: ".liquid", + globals: { + version, + } + }) + }, + root: join(__dirname, "views"), + production: false, + maxCache: 0, + options: { + noCache: true, + }, + }); + + app.register(require('@fastify/static'), { + root: join(__dirname, 'public'), + }) + + app.register(fastifyJwt, { + secret: process.env.JWT_SECRET ?? 'this_shoudl_not_be_used_in_production', + cookie: { + cookieName: 'token', + signed: false, + } + }) + + app.register(routesRoot) + app.register(routesUser) + + app.listen({ host: ADDRESS, port: parseInt(PORT, 10) }, function (err, address) { + if (err) { + app.log.error(err) + } + }) + + printInfo(); +}).catch((err) => { + console.error(err); +}) \ No newline at end of file diff --git a/lib/bluesky.ts b/lib/bluesky.ts index 5dcc4af..66ca6b3 100644 --- a/lib/bluesky.ts +++ b/lib/bluesky.ts @@ -3,8 +3,7 @@ import { Entity } from "megalodon" import { fetchImageToBytes, logSchedulerEvent, mastodonHtmlToText, splitTextBluesky } from "./utils"; import sharp from "sharp"; import { Attachment } from "megalodon/lib/src/entities/attachment"; -import { db } from "./db"; -import { JsonObject } from "@prisma/client/runtime/library"; +import { clearBlueskyCreds, clearBluskySession, db, persistBlueskySession } from "./db"; import { ResponseType, XRPCError } from '@atproto/xrpc' @@ -18,36 +17,10 @@ export async function intiBlueskyAgent(url: string, handle: string, password: st logSchedulerEvent(user.name, user.mastodonInstance.url, "SESSION_PERSIST", `${evt}`) if (evt === 'expired' || evt === 'create-failed') { logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "clearing session") - db.user.update({ - where: { - id: user.id - }, - data: { - blueskySession: null, - blueskySessionEvent: null, - } - }).then(() => { - logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "session cleared") - }).catch((err) => { - logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "could not clear session") - console.error(err) - }) + clearBluskySession(user); } else { logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "persisting session") - db.user.update({ - where: { - id: user.id - }, - data: { - blueskySession: sess as unknown as JsonObject, - blueskySessionEvent: evt - } - }).then(() => { - logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "session persisted") - }).catch((err) => { - logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "could not persist session") - console.error(err) - }) + persistBlueskySession(user, evt, sess); } }, }) @@ -72,22 +45,7 @@ export async function intiBlueskyAgent(url: string, handle: string, password: st if((err as XRPCError).status == ResponseType.AuthRequired) { // invalidate creds to prevent further login attempts resulting in rate limiting logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "invalid creds") - db.user.update({ - where: { - id: user.id - }, - data: { - blueskySession: null, - blueskySessionEvent: null, - blueskyToken: null, - blueskyHandle: null - } - }).then(() => { - logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "bluesky creds invalidated") - }).catch((err) => { - logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "could not clear creds") - console.error(err) - }) + clearBlueskyCreds(user) } else if ((err as XRPCError).status == ResponseType.RateLimitExceeded) { logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "login rate limited") } else { @@ -159,12 +117,25 @@ export async function generateBlueskyPostFromMastodon(content: string, client: A encoding: mimeType! }) + let width = 1200; + let height = 1200; + if (media.meta) { + if (media.meta.original) { + width = media.meta.original.width || width; + height = media.meta.original.height || height; + } else { + width = media.meta.width || width; + height = media.meta.height || height; + } + } + + images.push({ image: res.data.blob, alt: media.description ? media.description : '', aspectRatio: { - width: media.meta.width || media.meta.original.width, - height: media.meta.height || media.meta.original.height, + width: width, + height: height } }); } diff --git a/lib/db.ts b/lib/db.ts index 2a31163..a21debf 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -1,75 +1,326 @@ -import { ReplyRef } from '@atproto/api/dist/client/types/app/bsky/feed/post'; -import { PrismaClient } from "@prisma/client"; -export const db = new PrismaClient(); +import { ReplyRef } from "@atproto/api/dist/client/types/app/bsky/feed/post"; +import { logSchedulerEvent } from "./utils"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { Client } from "pg"; +import * as schema from "./../drizzle/schema"; +import * as relations from "./../drizzle/relations"; +import { count, eq } from "drizzle-orm"; +import { AtpSessionData } from "@atproto/api"; + +export const client = new Client({ + connectionString: process.env.POSTGRES_URL, +}); + +export const db = drizzle(client, { schema: { ...schema, ...relations } }); export async function getUserByMastodonUid(userId: string, instanceId: string) { - return await db.user.findFirst({ - where: { - mastodonUid: userId, - mastodonInstanceId: instanceId - } - }); + return await db.query.user.findFirst({ + where: (user, { eq }) => + eq(user.mastodonUid, userId) && eq(user.mastodonInstanceId, instanceId), + }); } export async function getInstanceByDomain(url: string) { - return await db.mastodonInstance.findFirst({ - where: { - url: url - } - }) + return await db.query.mastodonInstance.findFirst({ + where: (instance, { eq }) => eq(instance.url, url), + }); } export async function updateLastPostTime(userId: string, postTime: Date) { - const user = await db.user.findFirst({ - where: { - id: userId - } + const user = await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.id, userId), + }); + if (!user) return; + if (new Date(user?.lastTootTime) > postTime) return; + return await db + .update(schema.user) + .set({ + updatedAt: new Date(), + lastTootTime: postTime, + }) + .where(eq(schema.user.id, userId)); +} + +export async function storeRepostRecord( + userId: string, + tootId: string, + repRef: ReplyRef +) { + return await db.insert(schema.repost).values({ + userId: userId, + tootId: tootId, + bsParentCid: repRef.parent.cid, + bsRootCid: repRef.root.cid, + bsRootUri: repRef.root.uri, + bsParentUri: repRef.parent.uri, + }).returning(); +} + +export async function findParentToot( + userId: string, + tootId: string +): Promise { + const repost = await db.query.repost.findFirst({ + where: (repost, { eq }) => + eq(repost.userId, userId) && eq(repost.tootId, tootId), + }); + + if (!repost) return null; + + const repRef: ReplyRef = { + root: { + cid: repost.bsRootCid, + uri: repost.bsRootUri, + }, + parent: { + cid: repost.bsParentCid, + uri: repost.bsParentUri, + }, + }; + + return repRef; +} + +export async function persistBlueskySession( + user: any, + evt: string, + sess?: AtpSessionData +) { + return await db + .update(schema.user) + .set({ + updatedAt: new Date(), + blueskySession: sess, + blueskySessionEvent: evt, + }) + .where(eq(schema.user.id, user.id)) + .then(() => { + logSchedulerEvent( + user.name, + user.mastodonInstance.url, + "AGENT", + "session persisted" + ); + }) + .catch((err) => { + logSchedulerEvent( + user.name, + user.mastodonInstance.url, + "AGENT", + "could not persist session" + ); + console.error(err); + }); +} + +export async function clearBluskySession(user: any) { + return await db + .update(schema.user) + .set({ + updatedAt: new Date(), + blueskySession: null, + blueskySessionEvent: null, + }) + .where(eq(schema.user.id, user.id)) + .then(() => { + logSchedulerEvent( + user.name, + user.mastodonInstance.url, + "AGENT", + "session cleared" + ); + }) + .catch((err) => { + logSchedulerEvent( + user.name, + user.mastodonInstance.url, + "AGENT", + "could not clear session" + ); + console.error(err); + }); +} + +export async function clearBlueskyCreds(user: any) { + return await db + .update(schema.user) + .set({ + updatedAt: new Date(), + blueskySession: null, + blueskySessionEvent: null, + blueskyToken: null, + blueskyHandle: null, }) - if (!user) return - if (user?.lastTootTime > postTime) return - return await db.user.update({ - where: { - id: userId - }, - data: { - lastTootTime: postTime - } + .where(eq(schema.user.id, user.id)) + .then(() => { + logSchedulerEvent( + user.name, + user.mastodonInstance.url, + "AGENT", + "bluesky creds invalidated" + ); }) + .catch((err) => { + logSchedulerEvent( + user.name, + user.mastodonInstance.url, + "AGENT", + "could not clear creds" + ); + console.error(err); + }); +} + +export async function findUsers() { + return await db.query.user.findMany({ + with: { + mastodonInstance: true, + }, + }); +} + +export async function findUserById( + userid: any, + withMastodonInstance: boolean = false +) { + return await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.id, userid), + with: withMastodonInstance ? { mastodonInstance: true } : undefined, + }); } -export async function storeRepostRecord(userId: string, tootId: string, repRef: ReplyRef) { - return await db.repost.create({ - data: { - userId: userId, - tootId: tootId, - bsParentCid: repRef.parent.cid, - bsRootCid: repRef.root.cid, - bsRootUri: repRef.root.uri, - bsParentUri: repRef.parent.uri - }, +export async function getAllUserInformation(userId: string) { + return await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.id, userId), + columns: { + createdAt: true, + updatedAt: true, + mastodonUid: true, + mastodonToken: false, + name: true, + lastTootTime: true, + blueskyHandle: true, + blueskyToken: false, + blueskySession: true, + blueskyPDS: true, + }, + }); +} + +export async function deleteUser(user: any) { + return await db.delete(schema.user).where(eq(schema.user.id, user.id)) + .then(() => { + logSchedulerEvent( + user.name, + "---", + "CREDENTIAL_CHECK", + "User deleted" + ); }) + .catch((err) => { + logSchedulerEvent( + user.name, + "---", + "CREDENTIAL_CHECK", + "Could not delete user" + ); + console.error(err); + }); } -export async function findParentToot(userId: string, tootId: string): Promise { - const repost = await db.repost.findFirst({ - where: { - userId: userId, - tootId: tootId - } +export async function getMastodonInstanceUsers() { + return await db + .select({ + id: schema.mastodonInstance.id, + url: schema.mastodonInstance.url, + count: count(schema.user.id), }) + .from(schema.mastodonInstance) + .leftJoin(schema.user, eq(schema.user.mastodonInstanceId, schema.mastodonInstance.id)) + .groupBy(schema.mastodonInstance.id); +} - if (!repost) return null - - const repRef: ReplyRef = { - root: { - cid: repost.bsRootCid, - uri: repost.bsRootUri - }, - parent: { - cid: repost.bsParentCid, - uri: repost.bsParentUri - } - } - - return repRef -} \ No newline at end of file +export async function deleteMastodonInstance(instance: any) { + return await db.delete(schema.mastodonInstance).where(eq(schema.mastodonInstance.id, instance.id)) + .then(() => { + logSchedulerEvent( + "SYSTEM", + instance.url, + "INSTANCE_USERS", + "Instance deleted" + ); + }) + .catch((err) => { + logSchedulerEvent( + "SYSTEM", + instance.url, + "INSTANCE_USERS", + "Could not delete instance" + ); + console.error(err); + }); +} + +export async function persistBlueskyCreds( + userId: any, + handle: string, + token: string, + pds: string +) { + return await db.update(schema.user).set({ + updatedAt: new Date(), + blueskyHandle: handle, + blueskyToken: token, + blueskyPDS: pds, + }).where(eq(schema.user.id, userId)).returning(); +} + +export async function updateRelaySettings( + userId: any, + relayCriteria: any, + relayMarker: string, + relayVisibility: any +) { + return await db.update(schema.user).set({ + updatedAt: new Date(), + relayCriteria: relayCriteria, + relayMarker: relayMarker, + relayVisibility: relayVisibility, + }).where(eq(schema.user.id, userId)).returning(); +} + +export async function createMastodonInstance( + instanceDomain: string, + appData: any +) { + return await db.insert(schema.mastodonInstance).values({ + updatedAt: new Date(), + url: instanceDomain, + urlEncoded: btoa(instanceDomain), + applicationId: appData.client_id, + applicationSecret: appData.client_secret, + }).returning(); +} + +export async function createUser( + instanceId: any, + verifiedCredentials: any, + token: any +) { + return await db.insert(schema.user).values({ + updatedAt: new Date(), + mastodonInstanceId: instanceId, + mastodonUid: verifiedCredentials.data.id, + mastodonToken: token.access_token, + name: verifiedCredentials.data.username, + lastTootTime: new Date(), + }).returning(); +} + +export async function updateUser(userId: any, token: any, name: string) { + return await db.update(schema.user).set({ + updatedAt: new Date(), + mastodonToken: token.access_token, + name: name, + }).where(eq(schema.user.id, userId)).returning(); +} diff --git a/lib/mastodon.ts b/lib/mastodon.ts index 16ca0b3..ec5f8ae 100644 --- a/lib/mastodon.ts +++ b/lib/mastodon.ts @@ -2,7 +2,6 @@ import { MegalodonInterface, Mastodon } from 'megalodon' import { Status } from 'megalodon/lib/src/entities/status'; import { Constraint } from "./constraint"; import { convert } from 'html-to-text'; -import { StatusVisibility } from '@prisma/client'; export function initMastodonAgent() { return new Mastodon('mastodon', @@ -16,14 +15,14 @@ export async function getUserIdFromMastodonHandle(handle: string, client: Megalo return a_data[0].id; } -function verifyThread(uid: string, status: Status, searchSpace: Status[], relayVisibility: StatusVisibility[], initialCall: boolean = false): boolean { +function verifyThread(uid: string, status: Status, searchSpace: Status[], relayVisibility: string[], initialCall: boolean = false): boolean { if (!status) return false; if (status.in_reply_to_account_id === uid && ( status.visibility === 'unlisted' || relayVisibility.includes(status.visibility) )) { return verifyThread( uid, - searchSpace.find((s) => s.id === status.in_reply_to_id), + searchSpace.find((s) => s.id === status.in_reply_to_id)!, searchSpace, relayVisibility, false @@ -35,7 +34,7 @@ function verifyThread(uid: string, status: Status, searchSpace: Status[], relayV } } -export async function getNewToots(client: Mastodon, uid: string, lastTootTime: Date, constraint: Constraint, relayVisibility: StatusVisibility[]) { +export async function getNewToots(client: Mastodon, uid: string, lastTootTime: Date, constraint: Constraint, relayVisibility: string[]) { const statuses = await client.getAccountStatuses(uid, { limit: 50, exclude_reblogs: true, diff --git a/lib/migration.ts b/lib/migration.ts new file mode 100644 index 0000000..4ce6952 --- /dev/null +++ b/lib/migration.ts @@ -0,0 +1,77 @@ +import { resolve } from "node:path"; +import { migrate } from "drizzle-orm/node-postgres/migrator"; +import { sql } from "drizzle-orm"; +import { db } from "./db"; + +const runPrismaToDrizzleMigrationScript = async (db: any) => { + return db.execute(sql` + CREATE SCHEMA drizzle; + + CREATE SEQUENCE drizzle."__drizzle_migrations_id_seq" + INCREMENT BY 1 + MINVALUE 1 + MAXVALUE 2147483647 + START 1 + CACHE 1 + NO CYCLE; + + CREATE TABLE drizzle."__drizzle_migrations" ( + id serial4 NOT NULL, + hash text NOT NULL, + created_at int8 NULL, + CONSTRAINT "__drizzle_migrations_pkey" PRIMARY KEY (id) + ); + + INSERT INTO drizzle."__drizzle_migrations" + (id, hash, created_at) + VALUES(1, '1ec46a86de694b1955fc7147a85248e628a60f4c7b8a4066125479d793ea4477', 1737818942346); + + ALTER TABLE "_prisma_migrations" DISABLE ROW LEVEL SECURITY; + + DROP TABLE "_prisma_migrations" CASCADE; + `); +}; + +const checkPrismaMigrationsTable = async (db: any) => { + try { + const result = await db.execute(sql` + SELECT FROM information_schema.tables + WHERE table_schema = 'public' + AND table_name = '_prisma_migrations'; + `); + return result.rows.length > 0; + } catch (e) { + return false; + } +}; + +const checkLastMigrationApplied = async (db: any) => { + const result = await db.execute(sql` + SELECT * FROM _prisma_migrations WHERE migration_name = '20241223001124_orphan_user_settings'; + `); + return result.rows.length > 0; +}; + +export async function migrationHelper() { + console.log("Migration helper started."); + + const prismaTablesExist = await checkPrismaMigrationsTable(db); + const lastPrismaMigrationApplied = prismaTablesExist + ? await checkLastMigrationApplied(db) + : false; + + if (prismaTablesExist && lastPrismaMigrationApplied) { + console.log("Migrating from Prisma to Drizzle!"); + await runPrismaToDrizzleMigrationScript(db); + console.log("Created Drizzle migrations table."); + } else if (prismaTablesExist && !lastPrismaMigrationApplied) { + console.error( + "Please upgrade to v0.3.2 with all migrations applied before running upgrading to this version." + ); + process.exit(1); + } else { + console.log("Applying fresh migration."); + } + migrate(db, { migrationsFolder: resolve(__dirname, "./../drizzle") }); + return; +} diff --git a/lib/tasks/cleanup.ts b/lib/tasks/cleanup.ts index 0f79bd4..83d4a09 100644 --- a/lib/tasks/cleanup.ts +++ b/lib/tasks/cleanup.ts @@ -2,18 +2,18 @@ import { Mastodon } from "megalodon"; import { domainToUrl, logSchedulerEvent } from "../utils"; import { db, + deleteMastodonInstance, + deleteUser, + findUsers, + getMastodonInstanceUsers, } from "../db"; export default async function cleanupJob() { console.log("Running scheduled job: verify instance app credentials..."); - const users = await db.user.findMany({ - include: { - mastodonInstance: true, - }, - }); + const users = await findUsers(); - users.forEach((user) => { + users.forEach((user: any) => { const userClient = new Mastodon( domainToUrl(user.mastodonInstance.url), user.mastodonToken @@ -41,50 +41,23 @@ export default async function cleanupJob() { "CREDENTIAL_CHECK", "Deleting user due to invalid credentials" ); - db.user.delete({ - where: { - id: user.id, - }, - }).then((res) => { - logSchedulerEvent( - user.name, - user.mastodonInstance.url, - "CREDENTIAL_CHECK", - "User deleted" - ); - }).catch((err) => { - logSchedulerEvent( - user.name, - user.mastodonInstance.url, - "CREDENTIAL_CHECK", - "Could not delete user" - ); - console.error(err); - }); + deleteUser(user); } }); }); - const instances = await db.mastodonInstance.findMany({ - include: { - _count: { - select: { - users: true, - }, - } - } - }) + const instances = await getMastodonInstanceUsers(); instances.forEach((instance) => { logSchedulerEvent( "SYSTEM", instance.url, "INSTANCE_USERS", - `${instance._count.users + `${instance.count } users` ); - if (instance._count.users === 0) { + if (instance.count === 0) { logSchedulerEvent( "SYSTEM", instance.url, @@ -92,26 +65,7 @@ export default async function cleanupJob() { "Deleting instance due to no users" ); - db.mastodonInstance.delete({ - where: { - id: instance.id, - }, - }).then((res) => { - logSchedulerEvent( - "SYSTEM", - instance.url, - "INSTANCE_USERS", - "Instance deleted" - ); - }).catch((err) => { - logSchedulerEvent( - "SYSTEM", - instance.url, - "INSTANCE_USERS", - "Could not delete instance" - ); - console.error(err); - }); + deleteMastodonInstance(instance); } }); } diff --git a/lib/tasks/mastodonToBluesky.ts b/lib/tasks/mastodonToBluesky.ts index ae16b86..4d4a0c8 100644 --- a/lib/tasks/mastodonToBluesky.ts +++ b/lib/tasks/mastodonToBluesky.ts @@ -8,19 +8,17 @@ import { updateLastPostTime, storeRepostRecord, findParentToot, + findUsers, + clearBlueskyCreds, } from "../db"; import { ReplyRef } from "@atproto/api/dist/client/types/app/bsky/feed/post"; export default async function taskMastodonToBluesky() { console.log("Running scheduled job: reposting to bluesky..."); - const users = await db.user.findMany({ - include: { - mastodonInstance: true, - }, - }); + const users = await findUsers() - users.forEach(async (user) => { + users.forEach(async (user: any) => { if (!user.blueskyHandle || !user.blueskyToken) { logSchedulerEvent( user.name, @@ -177,7 +175,7 @@ export default async function taskMastodonToBluesky() { if (repRef.root === undefined) repRef.root = result; repRef.parent = result; - } catch (err) { + } catch (err: any) { if(err.error === "AccountDeactivated") { logSchedulerEvent( user.name, @@ -186,22 +184,7 @@ export default async function taskMastodonToBluesky() { `Account deactivated, invalidating creds` ); - db.user.update({ - where: { - id: user.id - }, - data: { - blueskySession: null, - blueskySessionEvent: null, - blueskyToken: null, - blueskyHandle: null - } - }).then(() => { - logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "bluesky creds invalidated") - }).catch((err) => { - logSchedulerEvent(user.name, user.mastodonInstance.url, "AGENT", "could not clear creds") - console.error(err) - }) + clearBlueskyCreds(user) return; } diff --git a/lib/tasks/scheduler.ts b/lib/tasks/scheduler.ts index 39accbc..88f65ec 100644 --- a/lib/tasks/scheduler.ts +++ b/lib/tasks/scheduler.ts @@ -3,7 +3,9 @@ import taskMastodonToBluesky from "./mastodonToBluesky" import * as Sentry from '@sentry/node'; import { nodeProfilingIntegration } from "@sentry/profiling-node"; import cleanupJob from "./cleanup"; +import { client } from './../db'; +client.connect() if (process.env.SENTRY_DSN) { Sentry.init({ diff --git a/package.json b/package.json index 3b77319..e38af00 100644 --- a/package.json +++ b/package.json @@ -1,51 +1,52 @@ { "name": "skymoth", "scripts": { - "build": "tsc -p tsconfig.json && cp -r public dist/public && cp -r views dist/views", - "start": "prisma migrate deploy && node dist/index.js", + "build": "tsc -p tsconfig.json && cp -r public dist/public && cp -r views dist/views && cp -r drizzle/*.sql dist/drizzle && cp -r drizzle/meta dist/drizzle/meta", + "start": "node dist/index.js", "start:scheduler": "node dist/lib/tasks/scheduler.js", "dev": "pnpm run dev:server", "dev:server": "nodemon --exec ts-node index.ts", "dev:scheduler": "nodemon --exec ts-node lib/tasks/scheduler.ts", - "migrate": "prisma migrate dev", - "generate": "prisma generate", "tailwind:css": "concurrently \"tailwindcss -i ${PWD}/public/styles/tailwind.css -o ${PWD}/public/styles/style.css --watch\"", "tailwind:build": "tailwindcss -i ${PWD}/public/styles/tailwind.css -o ${PWD}/public/styles/style.css" }, "dependencies": { - "@atproto/api": "^0.13.23", + "@atproto/api": "^0.13.31", "@atproto/xrpc": "^0.6.5", - "@fastify/cookie": "^11.0.1", - "@fastify/formbody": "^8.0.1", - "@fastify/jwt": "^9.0.2", + "@fastify/cookie": "^11.0.2", + "@fastify/formbody": "^8.0.2", + "@fastify/jwt": "^9.0.3", "@fastify/schedule": "^5.0.2", "@fastify/session": "^11.0.2", "@fastify/static": "^8.0.3", - "@fastify/view": "^10.0.1", - "@prisma/client": "^6.0.1", - "@sentry/node": "^8.45.1", + "@fastify/view": "^10.0.2", + "@sentry/node": "^8.47.0", "@sentry/profiling-node": "^8.47.0", - "fastify": "^5.2.0", + "dotenv": "^16.4.7", + "drizzle-orm": "^0.38.4", + "fastify": "^5.2.1", "html-to-text": "^9.0.5", - "liquidjs": "^10.19.0", - "megalodon": "^10.0.7", - "node-html-parser": "^6.1.13", - "prisma": "^6.0.1", + "liquidjs": "^10.20.2", + "megalodon": "^10.1.1", + "node-html-parser": "^7.0.1", + "pg": "^8.13.1", "sharp": "^0.33.5", "toad-scheduler": "^3.0.1" }, "devDependencies": { - "@codedependant/semantic-release-docker": "^5.0.3", + "@codedependant/semantic-release-docker": "^5.1.0", "@tailwindcss/typography": "^0.5.15", "@types/html-to-text": "^9.0.4", + "@types/pg": "^8.11.11", "autoprefixer": "^10.4.20", - "concurrently": "^9.1.0", - "daisyui": "^4.12.20", - "nodemon": "^3.1.7", + "concurrently": "^9.1.2", + "daisyui": "^4.12.23", + "drizzle-kit": "^0.30.2", + "nodemon": "^3.1.9", "postcss": "^8.4.49", "postcss-cli": "^11.0.0", "semantic-release": "^24.2.0", - "tailwindcss": "^3.4.16", + "tailwindcss": "^3.4.17", "ts-node": "^10.9.2", "typescript": "^5.7.2" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5886e7..3e37fa4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,20 +9,20 @@ importers: .: dependencies: '@atproto/api': - specifier: ^0.13.23 - version: 0.13.23 + specifier: ^0.13.31 + version: 0.13.31 '@atproto/xrpc': specifier: ^0.6.5 version: 0.6.5 '@fastify/cookie': - specifier: ^11.0.1 - version: 11.0.1 + specifier: ^11.0.2 + version: 11.0.2 '@fastify/formbody': - specifier: ^8.0.1 - version: 8.0.1 + specifier: ^8.0.2 + version: 8.0.2 '@fastify/jwt': - specifier: ^9.0.2 - version: 9.0.2 + specifier: ^9.0.3 + version: 9.0.3 '@fastify/schedule': specifier: ^5.0.2 version: 5.0.2(toad-scheduler@3.0.1) @@ -33,35 +33,38 @@ importers: specifier: ^8.0.3 version: 8.0.3 '@fastify/view': - specifier: ^10.0.1 - version: 10.0.1 - '@prisma/client': - specifier: ^6.0.1 - version: 6.0.1(prisma@6.0.1) + specifier: ^10.0.2 + version: 10.0.2 '@sentry/node': - specifier: ^8.45.1 - version: 8.45.1 + specifier: ^8.47.0 + version: 8.47.0 '@sentry/profiling-node': specifier: ^8.47.0 version: 8.47.0 + dotenv: + specifier: ^16.4.7 + version: 16.4.7 + drizzle-orm: + specifier: ^0.38.4 + version: 0.38.4(@opentelemetry/api@1.9.0)(@prisma/client@6.0.1(prisma@6.0.1))(@types/pg@8.11.11)(pg@8.13.1)(prisma@6.0.1) fastify: - specifier: ^5.2.0 - version: 5.2.0 + specifier: ^5.2.1 + version: 5.2.1 html-to-text: specifier: ^9.0.5 version: 9.0.5 liquidjs: - specifier: ^10.19.0 - version: 10.19.0 + specifier: ^10.20.2 + version: 10.20.2 megalodon: - specifier: ^10.0.7 - version: 10.0.7 + specifier: ^10.1.1 + version: 10.1.1 node-html-parser: - specifier: ^6.1.13 - version: 6.1.13 - prisma: - specifier: ^6.0.1 - version: 6.0.1 + specifier: ^7.0.1 + version: 7.0.1 + pg: + specifier: ^8.13.1 + version: 8.13.1 sharp: specifier: ^0.33.5 version: 0.33.5 @@ -70,26 +73,32 @@ importers: version: 3.0.1 devDependencies: '@codedependant/semantic-release-docker': - specifier: ^5.0.3 - version: 5.0.3 + specifier: ^5.1.0 + version: 5.1.0 '@tailwindcss/typography': specifier: ^0.5.15 - version: 0.5.15(tailwindcss@3.4.16(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.7.2))) + version: 0.5.15(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.10)(typescript@5.7.2))) '@types/html-to-text': specifier: ^9.0.4 version: 9.0.4 + '@types/pg': + specifier: ^8.11.11 + version: 8.11.11 autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.49) concurrently: - specifier: ^9.1.0 - version: 9.1.0 + specifier: ^9.1.2 + version: 9.1.2 daisyui: - specifier: ^4.12.20 - version: 4.12.20(postcss@8.4.49) + specifier: ^4.12.23 + version: 4.12.23(postcss@8.4.49) + drizzle-kit: + specifier: ^0.30.2 + version: 0.30.2 nodemon: - specifier: ^3.1.7 - version: 3.1.7 + specifier: ^3.1.9 + version: 3.1.9 postcss: specifier: ^8.4.49 version: 8.4.49 @@ -100,36 +109,54 @@ importers: specifier: ^24.2.0 version: 24.2.0(typescript@5.7.2) tailwindcss: - specifier: ^3.4.16 - version: 3.4.16(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.7.2)) + specifier: ^3.4.17 + version: 3.4.17(ts-node@10.9.2(@types/node@22.10.10)(typescript@5.7.2)) ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@22.9.0)(typescript@5.7.2) + version: 10.9.2(@types/node@22.10.10)(typescript@5.7.2) typescript: specifier: ^5.7.2 version: 5.7.2 packages: + '@actions/core@1.11.1': + resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==} + + '@actions/exec@1.1.1': + resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==} + + '@actions/http-client@2.2.3': + resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==} + + '@actions/io@1.1.3': + resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@atproto/api@0.13.23': - resolution: {integrity: sha512-V1Z5kgfSsqlFaC14sjnZL1Psv/9Lq/YKW1w7TIBq948Rtq8l+c6BpGrOH2Ssdcphpqi4OSeSYRsmJJlD6GGJ5w==} + '@atproto/api@0.13.31': + resolution: {integrity: sha512-i2cUQuwe+3j8rgPJj4YWRjSQeJunGqJ3IzesnvbODjjZh3IS9jB80BZ/pTe/AvNg6JCBbqeWJjWDVKeFHaiZAw==} - '@atproto/common-web@0.3.1': - resolution: {integrity: sha512-N7wiTnus5vAr+lT//0y8m/FaHHLJ9LpGuEwkwDAeV3LCiPif4m/FS8x/QOYrx1PdZQwKso95RAPzCGWQBH5j6Q==} + '@atproto/common-web@0.3.2': + resolution: {integrity: sha512-Vx0JtL1/CssJbFAb0UOdvTrkbUautsDfHNOXNTcX2vyPIxH9xOameSqLLunM1hZnOQbJwyjmQCt6TV+bhnanDg==} '@atproto/lexicon@0.4.4': resolution: {integrity: sha512-QFEmr3rpj/RoAmfX9ALU/asBG/rsVtQZnw+9nOB1/AuIwoxXd+ZyndR6lVUc2+DL4GEjl6W2yvBru5xbQIZWyA==} + '@atproto/lexicon@0.4.5': + resolution: {integrity: sha512-fljWqMGKn+XWtTprBcS3F1hGBREnQYh6qYHv2sjENucc7REms1gtmZXSerB9N6pVeHVNOnXiILdukeAcic5OEw==} + '@atproto/syntax@0.3.1': resolution: {integrity: sha512-fzW0Mg1QUOVCWUD3RgEsDt6d1OZ6DdFmbKcDdbzUfh0t4rhtRAC05KbZYmxuMPWDAiJ4BbbQ5dkAc/mNypMXkw==} '@atproto/xrpc@0.6.5': resolution: {integrity: sha512-t6u8iPEVbWge5RhzKZDahSzNDYIAxUtop6Q/X/apAZY1rgreVU0/1sSvvRoRFH19d3UIKjYdLuwFqMi9w8nY3Q==} + '@atproto/xrpc@0.6.6': + resolution: {integrity: sha512-umXEYVMo9/pyIBoKmIAIi64RXDW9tSXY+wqztlQ6I2GZtjLfNZqmAWU+wADk3SxUe54mvjxxGyA4TtyGtDMfhA==} + '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -142,8 +169,8 @@ packages: resolution: {integrity: sha512-70Fmzlmn8EfCjjssls8N6E94quBUWnLhu4inPZU2pkwpc6ZvbErkLRvtkYl81KFCvVcuVC0X10QPZVNwjXo2KA==} engines: {node: '>= 14'} - '@codedependant/semantic-release-docker@5.0.3': - resolution: {integrity: sha512-tm0uMS+HalwyCzNzFQppFxGDmAN+VG6C6e/hphjn426ba6HBB/hzFV8TuSyOMoXcv5mperpDuk9FXGByhPm44w==} + '@codedependant/semantic-release-docker@5.1.0': + resolution: {integrity: sha512-Ok37Hrj3y2AeZA4nBHzXNPR+twZHbAnGY2vXV3V3MC9xP676PnP67eBpzP5zLodxBXqRFKixo8QiQhQJ8nnXbQ==} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -153,32 +180,323 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@drizzle-team/brocli@0.10.2': + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@emnapi/runtime@1.2.0': resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==} + '@esbuild-kit/core-utils@3.3.2': + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild-kit/esm-loader@2.6.5': + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild/aix-ppc64@0.19.12': + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.18.20': + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.19.12': + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.18.20': + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.19.12': + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.18.20': + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.19.12': + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.18.20': + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.19.12': + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.18.20': + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.19.12': + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.18.20': + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.19.12': + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.18.20': + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.19.12': + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.18.20': + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.19.12': + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.18.20': + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.19.12': + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.18.20': + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.19.12': + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.18.20': + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.19.12': + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.18.20': + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.19.12': + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.18.20': + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.19.12': + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.18.20': + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.19.12': + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.18.20': + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.19.12': + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.18.20': + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.19.12': + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.18.20': + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.19.12': + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.18.20': + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.19.12': + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.18.20': + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.19.12': + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.18.20': + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.19.12': + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.18.20': + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.19.12': + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.18.20': + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.19.12': + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@fastify/accept-negotiator@2.0.0': resolution: {integrity: sha512-/Sce/kBzuTxIq5tJh85nVNOq9wKD8s+viIgX0fFMDBdw95gnpf53qmF1oBgJym3cPFliWUuSloVg/1w/rH0FcQ==} - '@fastify/ajv-compiler@4.0.1': - resolution: {integrity: sha512-DxrBdgsjNLP0YM6W5Hd6/Fmj43S8zMKiFJYgi+Ri3htTGAowPVG/tG1wpnWLMjufEnehRivUCKZ1pLDIoZdTuw==} + '@fastify/ajv-compiler@4.0.2': + resolution: {integrity: sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ==} + + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} - '@fastify/cookie@11.0.1': - resolution: {integrity: sha512-n1Ooz4bgQ5LcOlJQboWPfsMNxIrGV0SgU85UkctdpTlCQE0mtA3rlspOPUdqk9ubiiZn053ucnia4DjTquI4/g==} + '@fastify/cookie@11.0.2': + resolution: {integrity: sha512-GWdwdGlgJxyvNv+QcKiGNevSspMQXncjMZ1J8IvuDQk0jvkzgWWZFNC2En3s+nHndZBGV8IbLwOI/sxCZw/mzA==} '@fastify/error@4.0.0': resolution: {integrity: sha512-OO/SA8As24JtT1usTUTKgGH7uLvhfwZPwlptRi2Dp5P4KKmJI3gvsZ8MIHnNwDs4sLf/aai5LzTyl66xr7qMxA==} - '@fastify/fast-json-stringify-compiler@5.0.1': - resolution: {integrity: sha512-f2d3JExJgFE3UbdFcpPwqNUEoHWmt8pAKf8f+9YuLESdefA0WgqxeT6DrGL4Yrf/9ihXNSKOqpjEmurV405meA==} + '@fastify/fast-json-stringify-compiler@5.0.2': + resolution: {integrity: sha512-YdR7gqlLg1xZAQa+SX4sMNzQHY5pC54fu9oC5aYSUqBhyn6fkLkrdtKlpVdCNPlwuUuXA1PjFTEmvMF6ZVXVGw==} + + '@fastify/formbody@8.0.2': + resolution: {integrity: sha512-84v5J2KrkXzjgBpYnaNRPqwgMsmY7ZDjuj0YVuMR3NXCJRCgKEZy/taSP1wUYGn0onfxJpLyRGDLa+NMaDJtnA==} + + '@fastify/forwarded@3.0.0': + resolution: {integrity: sha512-kJExsp4JCms7ipzg7SJ3y8DwmePaELHxKYtg+tZow+k0znUTf3cb+npgyqm8+ATZOdmfgfydIebPDWM172wfyA==} - '@fastify/formbody@8.0.1': - resolution: {integrity: sha512-LPrcadSIK8TrQk510Zdj56fnw7cyHq0/PW0YHGGM8ycGL4X7XAex+FKcwpzB4i5lF9eykc71a4EtcO9AEoByqw==} + '@fastify/jwt@9.0.3': + resolution: {integrity: sha512-5OjeozLzwhMhrOkadHG9FhS5S3wNVIN6ADhBJd/x3VJIWptlRdc1ORksA6NHJ1ihvuAb0IOVK9giaCZTelnMSg==} - '@fastify/jwt@9.0.2': - resolution: {integrity: sha512-/ppnbKVhxnHV08WZHpP2phH31eJ3FnyU43Sm8ERcYZwudcwqzmQ5+ptaqOvAyykIvfGmRC3R//0sc8HziJhnww==} + '@fastify/merge-json-schemas@0.2.1': + resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} - '@fastify/merge-json-schemas@0.1.1': - resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} + '@fastify/proxy-addr@5.0.0': + resolution: {integrity: sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==} '@fastify/schedule@5.0.2': resolution: {integrity: sha512-kNtADXfpNIQAGc/9bMxHSwUwpYKvZYoTWGVpTc1IgsjW15SBC9Xl2OVwUgmrDmW5iOknTyIS+XbY6LHaZBT4ww==} @@ -194,8 +512,8 @@ packages: '@fastify/static@8.0.3': resolution: {integrity: sha512-GHSoOVDIxEYEeVR5l044bRCuAKDErD/+9VE+Z9fnaTRr+DDz0Avrm4kKai1mHbPx6C0U7BVNthjd/gcMquZZUA==} - '@fastify/view@10.0.1': - resolution: {integrity: sha512-rXtBN0oVDmoRZAS7lelrCIahf+qFtlMOOas8VPdA7JvrJ9ChcF7e36pIUPU0Vbs3KmHxESUb7XatavUZEe/k5Q==} + '@fastify/view@10.0.2': + resolution: {integrity: sha512-tGjXFyDUMj5a+E8BBrQ2wpsVnpOfMq3cqy4WD8pnjWPE/HGNItBASUPoPUcX/QjPhxfuZZTYv2XdCmKXdcMZPw==} '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} @@ -644,9 +962,6 @@ packages: '@prisma/get-platform@6.0.1': resolution: {integrity: sha512-zspC9vlxAqx4E6epMPMLLBMED2VD8axDe8sPnquZ8GOsn6tiacWK0oxrGK4UAHYzYUVuMVUApJbdXB2dFpLhvg==} - '@prisma/instrumentation@5.19.1': - resolution: {integrity: sha512-VLnzMQq7CWroL5AeaW0Py2huiNKeoMfCH3SUxstdzPrlWQi6UQ9UrfcbUkNHlVFqOMacqy8X/8YtE0kuKDpD9w==} - '@prisma/instrumentation@5.22.0': resolution: {integrity: sha512-LxccF392NN37ISGxIurUljZSh1YWnphO34V5a0+T7FVQG2u9bhAXRTJpgmQ3483woVhkraQZFF7cbRrpbw/F4Q==} @@ -688,32 +1003,14 @@ packages: peerDependencies: semantic-release: '>=20.1.0' - '@sentry/core@8.45.1': - resolution: {integrity: sha512-1fGmkr0paZshh38mD29c4CfkRkgFoYDaAGyDLoGYfTbEph/lU8RHB2HWzN93McqNdMEhl1DRRyqIasUZoPlqSA==} - engines: {node: '>=14.18'} - '@sentry/core@8.47.0': resolution: {integrity: sha512-iSEJZMe3DOcqBFZQAqgA3NB2lCWBc4Gv5x/SCri/TVg96wAlss4VrUunSI2Mp0J4jJ5nJcJ2ChqHSBAU48k3FA==} engines: {node: '>=14.18'} - '@sentry/node@8.45.1': - resolution: {integrity: sha512-xvlXifM/FSOQdLAqQBuo04SiOh7RP8rRRr+c5G/YbBtgJA867Pve0X8JZK2BJpDZ3OrGvzXV1Ubnt9ao4rBfYA==} - engines: {node: '>=14.18'} - '@sentry/node@8.47.0': resolution: {integrity: sha512-tMzeU3KkmDi2OVvSu+Ah5pwoi7srsSyc1DovBbRQU96RFf/lOFzGe9JERa1MyDUqqLH95NqnPTNsa4Amb8/Vxg==} engines: {node: '>=14.18'} - '@sentry/opentelemetry@8.45.1': - resolution: {integrity: sha512-khnR5TS21ksITTXmXnpniRN7brlZS5RNNQuMZ9n3MYi/L1/s9LT73skNh1gder28OV6ZxGUgrTZ+1dtKqn9tig==} - engines: {node: '>=14.18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core': ^1.29.0 - '@opentelemetry/instrumentation': ^0.56.0 - '@opentelemetry/sdk-trace-base': ^1.29.0 - '@opentelemetry/semantic-conventions': ^1.28.0 - '@sentry/opentelemetry@8.47.0': resolution: {integrity: sha512-wunyBIUPeY6Kx3SFhOQqOPs+hyRADO5bztpo8aZ3N3xfzhefSTOdrgUroKvHx1DvoQO6MAlykcuUFps3yfaqmg==} engines: {node: '>=14.18'} @@ -767,8 +1064,8 @@ packages: '@types/mysql@2.15.26': resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} - '@types/node@22.9.0': - resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} + '@types/node@22.10.10': + resolution: {integrity: sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -776,6 +1073,9 @@ packages: '@types/pg-pool@2.0.6': resolution: {integrity: sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==} + '@types/pg@8.11.11': + resolution: {integrity: sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==} + '@types/pg@8.6.1': resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} @@ -901,8 +1201,8 @@ packages: await-lock@2.2.2: resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} - axios@1.7.7: - resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + axios@1.7.9: + resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -938,6 +1238,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1030,8 +1333,8 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concurrently@9.1.0: - resolution: {integrity: sha512-VxkzwMAn4LP7WyMnJNbHN5mKV9L2IbyDjpzemKr99sXNR3GqRNMMHdm7prV1ws9wg7ETj6WUkNOigZVsptwbgg==} + concurrently@9.1.2: + resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==} engines: {node: '>=18'} hasBin: true @@ -1068,6 +1371,10 @@ packages: resolution: {integrity: sha512-Xd8lFX4LM9QEEwxQpF9J9NTUh8pmdJO0cyRJhFiDoLTk2eH8FXlRv2IFGYVadZpqI3j8fhNrSdKCeYPxiAhLXw==} engines: {node: '>=18'} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -1114,8 +1421,8 @@ packages: resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - daisyui@4.12.20: - resolution: {integrity: sha512-uHr3SQsd2yTjRdVuswTiqGFvZTxX0sGSBRa8JJdbKgmZCk/kRFh4B7Z2jg9vLIdwsHTHPyPgCkZadQo1ce0tAw==} + daisyui@4.12.23: + resolution: {integrity: sha512-EM38duvxutJ5PD65lO/AFMpcw+9qEy6XAZrTpzp7WyaPeO/l+F/Qiq0ECHHmFNcFXh5aVoALY4MGrrxtCiaQCQ==} engines: {node: '>=16.9.0'} dayjs@1.11.13: @@ -1150,6 +1457,10 @@ packages: resolution: {integrity: sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==} engines: {node: '>= 0.6.0'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -1185,6 +1496,106 @@ packages: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + + drizzle-kit@0.30.2: + resolution: {integrity: sha512-vhdLrxWA32WNVF77NabpSnX7pQBornx64VDQDmKddRonOB2Xe/yY4glQ7rECoa+ogqcQNo7VblLUbeBK6Zn9Ow==} + hasBin: true + + drizzle-orm@0.38.4: + resolution: {integrity: sha512-s7/5BpLKO+WJRHspvpqTydxFob8i1vo2rEx4pY6TGY7QSMuUfWUuzaY0DIpXCkgHOo37BaFC+SJQb99dDUXT3Q==} + peerDependencies: + '@aws-sdk/client-rds-data': '>=3' + '@cloudflare/workers-types': '>=4' + '@electric-sql/pglite': '>=0.2.0' + '@libsql/client': '>=0.10.0' + '@libsql/client-wasm': '>=0.10.0' + '@neondatabase/serverless': '>=0.10.0' + '@op-engineering/op-sqlite': '>=2' + '@opentelemetry/api': ^1.4.1 + '@planetscale/database': '>=1' + '@prisma/client': '*' + '@tidbcloud/serverless': '*' + '@types/better-sqlite3': '*' + '@types/pg': '*' + '@types/react': '>=18' + '@types/sql.js': '*' + '@vercel/postgres': '>=0.8.0' + '@xata.io/client': '*' + better-sqlite3: '>=7' + bun-types: '*' + expo-sqlite: '>=14.0.0' + knex: '*' + kysely: '*' + mysql2: '>=2' + pg: '>=8' + postgres: '>=3' + prisma: '*' + react: '>=18' + sql.js: '>=1' + sqlite3: '>=5' + peerDependenciesMeta: + '@aws-sdk/client-rds-data': + optional: true + '@cloudflare/workers-types': + optional: true + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + '@libsql/client-wasm': + optional: true + '@neondatabase/serverless': + optional: true + '@op-engineering/op-sqlite': + optional: true + '@opentelemetry/api': + optional: true + '@planetscale/database': + optional: true + '@prisma/client': + optional: true + '@tidbcloud/serverless': + optional: true + '@types/better-sqlite3': + optional: true + '@types/pg': + optional: true + '@types/react': + optional: true + '@types/sql.js': + optional: true + '@vercel/postgres': + optional: true + '@xata.io/client': + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + prisma: + optional: true + react: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} @@ -1228,9 +1639,20 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} - engines: {node: '>=6'} + esbuild-register@3.6.0: + resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} + peerDependencies: + esbuild: '>=0.12 <1' + + esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} + engines: {node: '>=12'} + hasBin: true escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} @@ -1273,8 +1695,8 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} - fast-json-stringify@6.0.0: - resolution: {integrity: sha512-FGMKZwniMTgZh7zQp9b6XnBVxUmKVahQLQeRQHqwYmPDqDhcEKZ3BaQsxelFFI5PY7nN71OEeiL47/zUWcYe1A==} + fast-json-stringify@6.0.1: + resolution: {integrity: sha512-s7SJE83QKBZwg54dIbD5rCtzOBVD43V1ReWXXYqBgwCwHLYAAT0RQc/FmrQglXqWPpz6omtryJQOau5jI4Nrvg==} fast-jwt@5.0.2: resolution: {integrity: sha512-b2z/32MTWyURskK8plXXkbLuZU3F+T79iFaVLYZEveF5lOwUj6g8wg2T7zIi6/xTbbv4BRQzm/lgH2jL3vSPgA==} @@ -1287,11 +1709,8 @@ packages: resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} engines: {node: '>=6'} - fast-uri@2.4.0: - resolution: {integrity: sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==} - - fast-uri@3.0.3: - resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} fastfall@1.5.1: resolution: {integrity: sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q==} @@ -1300,8 +1719,8 @@ packages: fastify-plugin@5.0.1: resolution: {integrity: sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==} - fastify@5.2.0: - resolution: {integrity: sha512-3s+Qt5S14Eq5dCpnE0FxTp3z4xKChI83ZnMv+k0FwX+VUoZrgCFoLAxpfdi/vT4y6Mk+g7aAMt9pgXDoZmkefQ==} + fastify@5.2.1: + resolution: {integrity: sha512-rslrNBF67eg8/Gyn7P2URV8/6pz8kSAscFL4EThZJ8JBMaXacVdVE4hmUcnPNKERl5o/xTiBSLfdowBRhVF1WA==} fastparallel@2.4.1: resolution: {integrity: sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==} @@ -1312,6 +1731,9 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + fastseries@1.7.2: resolution: {integrity: sha512-dTPFrPGS8SNSzAt7u/CbMKCJ3s01N04s4JFbORHcmyvVfVKmbhMD1VtRbh5enGHxkaQDqWyLefiKOGGmohGDDQ==} @@ -1363,10 +1785,6 @@ packages: forwarded-parse@2.1.2: resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -1417,6 +1835,9 @@ packages: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} + get-tsconfig@4.10.0: + resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} + git-log-parser@1.2.1: resolution: {integrity: sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==} @@ -1556,9 +1977,9 @@ packages: resolution: {integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==} engines: {node: '>=12'} - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} + ipaddr.js@2.2.0: + resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} + engines: {node: '>= 10'} is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -1660,8 +2081,8 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-ref-resolver@1.0.1: - resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} + json-schema-ref-resolver@2.0.1: + resolution: {integrity: sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q==} json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} @@ -1672,12 +2093,8 @@ packages: leac@0.6.0: resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} - light-my-request@6.3.0: - resolution: {integrity: sha512-bWTAPJmeWQH5suJNYwG0f5cs0p6ho9e6f1Ppoxv5qMosY+s9Ir2+ZLvvHcgA7VTDop4zl/NCHhOVVqU+kd++Ow==} - - lilconfig@3.1.2: - resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} - engines: {node: '>=14'} + light-my-request@6.5.1: + resolution: {integrity: sha512-0q82RyxIextuDtkA0UDofhPHIiQ2kmpa7fwElCSlm/8nQl36cDU1Cw+CAO90Es0lReH2HChClKL84I86Nc52hg==} lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} @@ -1686,8 +2103,8 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - liquidjs@10.19.0: - resolution: {integrity: sha512-dNINmbNJ/bp3B8n25BtZQV/GbrmFf0o2InGdMdfQXa+LxfzTFXOkUnBsOLZUb82sLzxaiWv5Jc381Kn4zHjTsQ==} + liquidjs@10.20.2: + resolution: {integrity: sha512-MbAueOtO8aH+GzC/kmhcJTiMrMu+MVel/3+yhFVmP3K89WP0ZuvVPi8ZRKCHAO6SLJvV0Y0Jz6tUEy6Hg8xO/g==} engines: {node: '>=14'} hasBin: true @@ -1747,8 +2164,8 @@ packages: engines: {node: '>= 18'} hasBin: true - megalodon@10.0.7: - resolution: {integrity: sha512-gz8mwfN3sp269fqpkd9znopK8U6rhuJKtlyI7sQyzk4d6VxpVIX730FBjACNz3Io4bWo9DJdQBH5XOO/FCHDzg==} + megalodon@10.1.1: + resolution: {integrity: sha512-mjgXVZ39/Uaw7OY4n/YbwqWv7hfTfY2Lcjtr2yypBfvuBe0wstmQquQDT7xgeFOl7oC2THmR5mWj1cVH1Cjc5Q==} engines: {node: '>=22.11.0'} meow@13.2.0: @@ -1847,14 +2264,14 @@ packages: resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} engines: {node: '>=18'} - node-html-parser@6.1.13: - resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} + node-html-parser@7.0.1: + resolution: {integrity: sha512-KGtmPY2kS0thCWGK0VuPyOS+pBKhhe8gXztzA2ilAOhbUbxa9homF1bOyKvhGzMLXUoRds9IOmr/v5lr/lqNmA==} node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} - nodemon@3.1.7: - resolution: {integrity: sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==} + nodemon@3.1.9: + resolution: {integrity: sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==} engines: {node: '>=10'} hasBin: true @@ -1978,6 +2395,9 @@ packages: obliterator@2.0.4: resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -2094,10 +2514,25 @@ packages: peberminta@0.9.0: resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} + pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + + pg-connection-string@2.7.0: + resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} + pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} + pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + + pg-pool@3.7.0: + resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==} + peerDependencies: + pg: '>=8.0' + pg-protocol@1.7.0: resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} @@ -2105,6 +2540,22 @@ packages: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} + pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + + pg@8.13.1: + resolution: {integrity: sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -2132,8 +2583,8 @@ packages: pino-std-serializers@7.0.0: resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} - pino@9.5.0: - resolution: {integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==} + pino@9.6.0: + resolution: {integrity: sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==} hasBin: true pirates@4.0.6: @@ -2218,18 +2669,37 @@ packages: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} + postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + postgres-bytea@1.0.0: resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} engines: {node: '>=0.10.0'} + postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + postgres-date@1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} + postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + postgres-interval@1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + + postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + pretty-hrtime@1.0.3: resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} engines: {node: '>= 0.8'} @@ -2246,16 +2716,12 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - process-warning@4.0.0: - resolution: {integrity: sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==} + process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -2321,6 +2787,9 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -2348,8 +2817,8 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex2@4.0.0: - resolution: {integrity: sha512-Hvjfv25jPDVr3U+4LDzBuZPPOymELG3PYcSk5hcevooo1yxxamQL/bHs/GrEPGmMoMEwRrHVGiCA1pXi97B8Ew==} + safe-regex2@4.0.1: + resolution: {integrity: sha512-goqsB+bSlOmVX+CiFX2PFc1OV88j5jvBqIM+DgqrucHnUguAUNtiNOs+aTadq2NqsLQ+TQ3UEVG3gtSFcdlkCg==} safe-stable-stringify@2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} @@ -2358,8 +2827,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - secure-json-parse@3.0.1: - resolution: {integrity: sha512-9QR7G96th4QJ2+dJwvZB+JoXyt8PN+DbEjOr6kL2/JU4KH8Eb2sFdU+gt8EDdzWDWoWH0uocDdfCoFzdVSixUA==} + secure-json-parse@3.0.2: + resolution: {integrity: sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==} selderee@0.11.0: resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} @@ -2439,6 +2908,9 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -2543,8 +3015,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - tailwindcss@3.4.16: - resolution: {integrity: sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==} + tailwindcss@3.4.17: + resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} engines: {node: '>=14.0.0'} hasBin: true @@ -2627,6 +3099,10 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + type-fest@1.4.0: resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} engines: {node: '>=10'} @@ -2655,8 +3131,12 @@ packages: undefsafe@2.0.5: resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + undici@5.28.4: + resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} + engines: {node: '>=14.0'} unicode-emoji-modifier-base@1.0.0: resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} @@ -2694,8 +3174,8 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@11.0.2: - resolution: {integrity: sha512-14FfcOJmqdjbBPdDjFQyk/SdT4NySW4eM0zcG+HqbHP5jzuH56xO3J1DGhgs/cEMCfwYi3HQI1gnTO62iaG+tQ==} + uuid@11.0.4: + resolution: {integrity: sha512-IzL6VtTTYcAhA/oghbFJ1Dkmqev+FpQWnCBaKq/gUluLxliWvO8DPFWfIviRmYbtaavtSQe4WBL++rFjdcGWEg==} hasBin: true v8-compile-cache-lib@3.0.1: @@ -2780,36 +3260,63 @@ packages: zod@3.23.8: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + snapshots: + '@actions/core@1.11.1': + dependencies: + '@actions/exec': 1.1.1 + '@actions/http-client': 2.2.3 + + '@actions/exec@1.1.1': + dependencies: + '@actions/io': 1.1.3 + + '@actions/http-client@2.2.3': + dependencies: + tunnel: 0.0.6 + undici: 5.28.4 + + '@actions/io@1.1.3': {} + '@alloc/quick-lru@5.2.0': {} - '@atproto/api@0.13.23': + '@atproto/api@0.13.31': dependencies: - '@atproto/common-web': 0.3.1 - '@atproto/lexicon': 0.4.4 + '@atproto/common-web': 0.3.2 + '@atproto/lexicon': 0.4.5 '@atproto/syntax': 0.3.1 - '@atproto/xrpc': 0.6.5 + '@atproto/xrpc': 0.6.6 await-lock: 2.2.2 multiformats: 9.9.0 tlds: 1.255.0 - zod: 3.23.8 + zod: 3.24.1 - '@atproto/common-web@0.3.1': + '@atproto/common-web@0.3.2': dependencies: graphemer: 1.4.0 multiformats: 9.9.0 uint8arrays: 3.0.0 - zod: 3.23.8 + zod: 3.24.1 '@atproto/lexicon@0.4.4': dependencies: - '@atproto/common-web': 0.3.1 + '@atproto/common-web': 0.3.2 '@atproto/syntax': 0.3.1 iso-datestring-validator: 2.2.2 multiformats: 9.9.0 zod: 3.23.8 + '@atproto/lexicon@0.4.5': + dependencies: + '@atproto/common-web': 0.3.2 + '@atproto/syntax': 0.3.1 + iso-datestring-validator: 2.2.2 + multiformats: 9.9.0 + zod: 3.24.1 + '@atproto/syntax@0.3.1': {} '@atproto/xrpc@0.6.5': @@ -2817,6 +3324,11 @@ snapshots: '@atproto/lexicon': 0.4.4 zod: 3.23.8 + '@atproto/xrpc@0.6.6': + dependencies: + '@atproto/lexicon': 0.4.5 + zod: 3.24.1 + '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -2827,8 +3339,9 @@ snapshots: '@badgateway/oauth2-client@2.4.2': {} - '@codedependant/semantic-release-docker@5.0.3': + '@codedependant/semantic-release-docker@5.1.0': dependencies: + '@actions/core': 1.11.1 '@semantic-release/error': 3.0.0 debug: 4.3.7(supports-color@5.5.0) execa: 4.1.0 @@ -2844,36 +3357,187 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@drizzle-team/brocli@0.10.2': {} + '@emnapi/runtime@1.2.0': dependencies: tslib: 2.8.1 optional: true + '@esbuild-kit/core-utils@3.3.2': + dependencies: + esbuild: 0.18.20 + source-map-support: 0.5.21 + + '@esbuild-kit/esm-loader@2.6.5': + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.10.0 + + '@esbuild/aix-ppc64@0.19.12': + optional: true + + '@esbuild/android-arm64@0.18.20': + optional: true + + '@esbuild/android-arm64@0.19.12': + optional: true + + '@esbuild/android-arm@0.18.20': + optional: true + + '@esbuild/android-arm@0.19.12': + optional: true + + '@esbuild/android-x64@0.18.20': + optional: true + + '@esbuild/android-x64@0.19.12': + optional: true + + '@esbuild/darwin-arm64@0.18.20': + optional: true + + '@esbuild/darwin-arm64@0.19.12': + optional: true + + '@esbuild/darwin-x64@0.18.20': + optional: true + + '@esbuild/darwin-x64@0.19.12': + optional: true + + '@esbuild/freebsd-arm64@0.18.20': + optional: true + + '@esbuild/freebsd-arm64@0.19.12': + optional: true + + '@esbuild/freebsd-x64@0.18.20': + optional: true + + '@esbuild/freebsd-x64@0.19.12': + optional: true + + '@esbuild/linux-arm64@0.18.20': + optional: true + + '@esbuild/linux-arm64@0.19.12': + optional: true + + '@esbuild/linux-arm@0.18.20': + optional: true + + '@esbuild/linux-arm@0.19.12': + optional: true + + '@esbuild/linux-ia32@0.18.20': + optional: true + + '@esbuild/linux-ia32@0.19.12': + optional: true + + '@esbuild/linux-loong64@0.18.20': + optional: true + + '@esbuild/linux-loong64@0.19.12': + optional: true + + '@esbuild/linux-mips64el@0.18.20': + optional: true + + '@esbuild/linux-mips64el@0.19.12': + optional: true + + '@esbuild/linux-ppc64@0.18.20': + optional: true + + '@esbuild/linux-ppc64@0.19.12': + optional: true + + '@esbuild/linux-riscv64@0.18.20': + optional: true + + '@esbuild/linux-riscv64@0.19.12': + optional: true + + '@esbuild/linux-s390x@0.18.20': + optional: true + + '@esbuild/linux-s390x@0.19.12': + optional: true + + '@esbuild/linux-x64@0.18.20': + optional: true + + '@esbuild/linux-x64@0.19.12': + optional: true + + '@esbuild/netbsd-x64@0.18.20': + optional: true + + '@esbuild/netbsd-x64@0.19.12': + optional: true + + '@esbuild/openbsd-x64@0.18.20': + optional: true + + '@esbuild/openbsd-x64@0.19.12': + optional: true + + '@esbuild/sunos-x64@0.18.20': + optional: true + + '@esbuild/sunos-x64@0.19.12': + optional: true + + '@esbuild/win32-arm64@0.18.20': + optional: true + + '@esbuild/win32-arm64@0.19.12': + optional: true + + '@esbuild/win32-ia32@0.18.20': + optional: true + + '@esbuild/win32-ia32@0.19.12': + optional: true + + '@esbuild/win32-x64@0.18.20': + optional: true + + '@esbuild/win32-x64@0.19.12': + optional: true + '@fastify/accept-negotiator@2.0.0': {} - '@fastify/ajv-compiler@4.0.1': + '@fastify/ajv-compiler@4.0.2': dependencies: ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) - fast-uri: 3.0.3 + fast-uri: 3.0.6 + + '@fastify/busboy@2.1.1': {} - '@fastify/cookie@11.0.1': + '@fastify/cookie@11.0.2': dependencies: cookie: 1.0.1 fastify-plugin: 5.0.1 '@fastify/error@4.0.0': {} - '@fastify/fast-json-stringify-compiler@5.0.1': + '@fastify/fast-json-stringify-compiler@5.0.2': dependencies: - fast-json-stringify: 6.0.0 + fast-json-stringify: 6.0.1 - '@fastify/formbody@8.0.1': + '@fastify/formbody@8.0.2': dependencies: fast-querystring: 1.1.2 fastify-plugin: 5.0.1 - '@fastify/jwt@9.0.2': + '@fastify/forwarded@3.0.0': {} + + '@fastify/jwt@9.0.3': dependencies: '@fastify/error': 4.0.0 '@lukeed/ms': 2.0.2 @@ -2881,9 +3545,14 @@ snapshots: fastify-plugin: 5.0.1 steed: 1.1.3 - '@fastify/merge-json-schemas@0.1.1': + '@fastify/merge-json-schemas@0.2.1': dependencies: - fast-deep-equal: 3.1.3 + dequal: 2.0.3 + + '@fastify/proxy-addr@5.0.0': + dependencies: + '@fastify/forwarded': 3.0.0 + ipaddr.js: 2.2.0 '@fastify/schedule@5.0.2(toad-scheduler@3.0.1)': dependencies: @@ -2912,7 +3581,7 @@ snapshots: fastq: 1.17.1 glob: 11.0.0 - '@fastify/view@10.0.1': + '@fastify/view@10.0.2': dependencies: fastify-plugin: 5.0.1 toad-cache: 3.7.0 @@ -3037,7 +3706,7 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.18.0 '@octokit/auth-token@5.1.1': {} @@ -3390,10 +4059,13 @@ snapshots: '@prisma/client@6.0.1(prisma@6.0.1)': optionalDependencies: prisma: 6.0.1 + optional: true - '@prisma/debug@6.0.1': {} + '@prisma/debug@6.0.1': + optional: true - '@prisma/engines-version@5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e': {} + '@prisma/engines-version@5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e': + optional: true '@prisma/engines@6.0.1': dependencies: @@ -3401,24 +4073,19 @@ snapshots: '@prisma/engines-version': 5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e '@prisma/fetch-engine': 6.0.1 '@prisma/get-platform': 6.0.1 + optional: true '@prisma/fetch-engine@6.0.1': dependencies: '@prisma/debug': 6.0.1 '@prisma/engines-version': 5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e '@prisma/get-platform': 6.0.1 + optional: true '@prisma/get-platform@6.0.1': dependencies: '@prisma/debug': 6.0.1 - - '@prisma/instrumentation@5.19.1': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.29.0(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + optional: true '@prisma/instrumentation@5.22.0': dependencies: @@ -3508,50 +4175,8 @@ snapshots: transitivePeerDependencies: - supports-color - '@sentry/core@8.45.1': {} - '@sentry/core@8.47.0': {} - '@sentry/node@8.45.1': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 1.29.0(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 1.29.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.56.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-amqplib': 0.45.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-connect': 0.42.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-dataloader': 0.15.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-express': 0.46.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-fastify': 0.43.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-fs': 0.18.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-generic-pool': 0.42.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-graphql': 0.46.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-hapi': 0.44.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-http': 0.56.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-ioredis': 0.46.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-kafkajs': 0.6.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-knex': 0.43.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-koa': 0.46.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-lru-memoizer': 0.43.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mongodb': 0.50.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mongoose': 0.45.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mysql': 0.44.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mysql2': 0.44.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-nestjs-core': 0.43.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-pg': 0.49.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-redis-4': 0.45.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-tedious': 0.17.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-undici': 0.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.29.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.29.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.28.0 - '@prisma/instrumentation': 5.19.1 - '@sentry/core': 8.45.1 - '@sentry/opentelemetry': 8.45.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.29.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.29.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.28.0) - import-in-the-middle: 1.11.2 - transitivePeerDependencies: - - supports-color - '@sentry/node@8.47.0': dependencies: '@opentelemetry/api': 1.9.0 @@ -3592,15 +4217,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@sentry/opentelemetry@8.45.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.29.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.29.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.28.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.29.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.56.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.29.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.28.0 - '@sentry/core': 8.45.1 - '@sentry/opentelemetry@8.47.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.29.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.29.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.28.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -3625,13 +4241,13 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} - '@tailwindcss/typography@0.5.15(tailwindcss@3.4.16(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.7.2)))': + '@tailwindcss/typography@0.5.15(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.10)(typescript@5.7.2)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.16(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.10.10)(typescript@5.7.2)) '@tsconfig/node10@1.0.11': {} @@ -3643,27 +4259,33 @@ snapshots: '@types/connect@3.4.36': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.10 '@types/html-to-text@9.0.4': {} '@types/mysql@2.15.26': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.10 - '@types/node@22.9.0': + '@types/node@22.10.10': dependencies: - undici-types: 6.19.8 + undici-types: 6.20.0 '@types/normalize-package-data@2.4.4': {} '@types/pg-pool@2.0.6': dependencies: - '@types/pg': 8.6.1 + '@types/pg': 8.11.11 + + '@types/pg@8.11.11': + dependencies: + '@types/node': 22.10.10 + pg-protocol: 1.7.0 + pg-types: 4.0.2 '@types/pg@8.6.1': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.10 pg-protocol: 1.7.0 pg-types: 2.2.0 @@ -3673,11 +4295,11 @@ snapshots: '@types/tedious@4.0.14': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.10 '@types/ws@8.5.13': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.10 abstract-logging@2.0.1: {} @@ -3709,7 +4331,7 @@ snapshots: ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.0.3 + fast-uri: 3.0.6 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -3772,11 +4394,11 @@ snapshots: avvio@9.1.0: dependencies: '@fastify/error': 4.0.0 - fastq: 1.17.1 + fastq: 1.18.0 await-lock@2.2.2: {} - axios@1.7.7: + axios@1.7.9: dependencies: follow-redirects: 1.15.9 form-data: 4.0.1 @@ -3816,6 +4438,8 @@ snapshots: node-releases: 2.0.18 update-browserslist-db: 1.1.0(browserslist@4.23.3) + buffer-from@1.1.2: {} + callsites@3.1.0: {} camelcase-css@2.0.1: {} @@ -3919,7 +4543,7 @@ snapshots: concat-map@0.0.1: {} - concurrently@9.1.0: + concurrently@9.1.2: dependencies: chalk: 4.1.2 lodash: 4.17.21 @@ -3960,6 +4584,8 @@ snapshots: cookie@1.0.1: {} + cookie@1.0.2: {} + core-util-is@1.0.3: {} cosmiconfig@9.0.0(typescript@5.7.2): @@ -4004,7 +4630,7 @@ snapshots: culori@3.3.0: {} - daisyui@4.12.20(postcss@8.4.49): + daisyui@4.12.23(postcss@8.4.49): dependencies: css-selector-tokenizer: 0.8.0 culori: 3.3.0 @@ -4031,6 +4657,8 @@ snapshots: dependency-graph@0.11.0: {} + dequal@2.0.3: {} + detect-libc@2.0.3: {} didyoumean@1.2.2: {} @@ -4065,6 +4693,25 @@ snapshots: dependencies: is-obj: 2.0.0 + dotenv@16.4.7: {} + + drizzle-kit@0.30.2: + dependencies: + '@drizzle-team/brocli': 0.10.2 + '@esbuild-kit/esm-loader': 2.6.5 + esbuild: 0.19.12 + esbuild-register: 3.6.0(esbuild@0.19.12) + transitivePeerDependencies: + - supports-color + + drizzle-orm@0.38.4(@opentelemetry/api@1.9.0)(@prisma/client@6.0.1(prisma@6.0.1))(@types/pg@8.11.11)(pg@8.13.1)(prisma@6.0.1): + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@prisma/client': 6.0.1(prisma@6.0.1) + '@types/pg': 8.11.11 + pg: 8.13.1 + prisma: 6.0.1 + duplexer2@0.1.4: dependencies: readable-stream: 2.3.8 @@ -4102,7 +4749,63 @@ snapshots: dependencies: is-arrayish: 0.2.1 - escalade@3.1.2: {} + esbuild-register@3.6.0(esbuild@0.19.12): + dependencies: + debug: 4.3.7(supports-color@5.5.0) + esbuild: 0.19.12 + transitivePeerDependencies: + - supports-color + + esbuild@0.18.20: + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + + esbuild@0.19.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 escalade@3.2.0: {} @@ -4165,14 +4868,13 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-json-stringify@6.0.0: + fast-json-stringify@6.0.1: dependencies: - '@fastify/merge-json-schemas': 0.1.1 + '@fastify/merge-json-schemas': 0.2.1 ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) - fast-deep-equal: 3.1.3 - fast-uri: 2.4.0 - json-schema-ref-resolver: 1.0.1 + fast-uri: 3.0.6 + json-schema-ref-resolver: 2.0.1 rfdc: 1.4.1 fast-jwt@5.0.2: @@ -4188,9 +4890,7 @@ snapshots: fast-redact@3.5.0: {} - fast-uri@2.4.0: {} - - fast-uri@3.0.3: {} + fast-uri@3.0.6: {} fastfall@1.5.1: dependencies: @@ -4198,21 +4898,21 @@ snapshots: fastify-plugin@5.0.1: {} - fastify@5.2.0: + fastify@5.2.1: dependencies: - '@fastify/ajv-compiler': 4.0.1 + '@fastify/ajv-compiler': 4.0.2 '@fastify/error': 4.0.0 - '@fastify/fast-json-stringify-compiler': 5.0.1 + '@fastify/fast-json-stringify-compiler': 5.0.2 + '@fastify/proxy-addr': 5.0.0 abstract-logging: 2.0.1 avvio: 9.1.0 - fast-json-stringify: 6.0.0 + fast-json-stringify: 6.0.1 find-my-way: 9.1.0 - light-my-request: 6.3.0 - pino: 9.5.0 - process-warning: 4.0.0 - proxy-addr: 2.0.7 + light-my-request: 6.5.1 + pino: 9.6.0 + process-warning: 4.0.1 rfdc: 1.4.1 - secure-json-parse: 3.0.1 + secure-json-parse: 3.0.2 semver: 7.6.3 toad-cache: 3.7.0 @@ -4227,6 +4927,10 @@ snapshots: dependencies: reusify: 1.0.4 + fastq@1.18.0: + dependencies: + reusify: 1.0.4 + fastseries@1.7.2: dependencies: reusify: 1.0.4 @@ -4248,7 +4952,7 @@ snapshots: dependencies: fast-deep-equal: 3.1.3 fast-querystring: 1.1.2 - safe-regex2: 4.0.0 + safe-regex2: 4.0.1 find-up-simple@1.0.0: {} @@ -4276,8 +4980,6 @@ snapshots: forwarded-parse@2.1.2: {} - forwarded@0.2.0: {} - fraction.js@4.3.7: {} from2@2.3.0: @@ -4317,6 +5019,10 @@ snapshots: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 + get-tsconfig@4.10.0: + dependencies: + resolve-pkg-maps: 1.0.0 + git-log-parser@1.2.1: dependencies: argv-formatter: 1.0.0 @@ -4479,7 +5185,7 @@ snapshots: from2: 2.3.0 p-is-promise: 3.0.0 - ipaddr.js@1.9.1: {} + ipaddr.js@2.2.0: {} is-arrayish@0.2.1: {} @@ -4557,9 +5263,9 @@ snapshots: json-parse-even-better-errors@2.3.1: {} - json-schema-ref-resolver@1.0.1: + json-schema-ref-resolver@2.0.1: dependencies: - fast-deep-equal: 3.1.3 + dequal: 2.0.3 json-schema-traverse@1.0.0: {} @@ -4571,19 +5277,17 @@ snapshots: leac@0.6.0: {} - light-my-request@6.3.0: + light-my-request@6.5.1: dependencies: - cookie: 1.0.1 - process-warning: 4.0.0 + cookie: 1.0.2 + process-warning: 4.0.1 set-cookie-parser: 2.7.1 - lilconfig@3.1.2: {} - lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} - liquidjs@10.19.0: + liquidjs@10.20.2: dependencies: commander: 10.0.1 @@ -4636,17 +5340,17 @@ snapshots: marked@12.0.2: {} - megalodon@10.0.7: + megalodon@10.1.1: dependencies: '@badgateway/oauth2-client': 2.4.2 '@types/ws': 8.5.13 - axios: 1.7.7 + axios: 1.7.9 dayjs: 1.11.13 events: 3.3.0 form-data: 4.0.1 isomorphic-ws: 5.0.0(ws@8.18.0) object-assign-deep: 0.4.0 - uuid: 11.0.2 + uuid: 11.0.4 ws: 8.18.0 transitivePeerDependencies: - bufferutil @@ -4729,14 +5433,14 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 - node-html-parser@6.1.13: + node-html-parser@7.0.1: dependencies: css-select: 5.1.0 he: 1.2.0 node-releases@2.0.18: {} - nodemon@3.1.7: + nodemon@3.1.9: dependencies: chokidar: 3.6.0 debug: 4.3.7(supports-color@5.5.0) @@ -4788,6 +5492,8 @@ snapshots: obliterator@2.0.4: {} + obuf@1.1.2: {} + on-exit-leak-free@2.1.2: {} once@1.4.0: @@ -4887,8 +5593,19 @@ snapshots: peberminta@0.9.0: {} + pg-cloudflare@1.1.1: + optional: true + + pg-connection-string@2.7.0: {} + pg-int8@1.0.1: {} + pg-numeric@1.0.2: {} + + pg-pool@3.7.0(pg@8.13.1): + dependencies: + pg: 8.13.1 + pg-protocol@1.7.0: {} pg-types@2.2.0: @@ -4899,6 +5616,30 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 + pg-types@4.0.2: + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + + pg@8.13.1: + dependencies: + pg-connection-string: 2.7.0 + pg-pool: 3.7.0(pg@8.13.1) + pg-protocol: 1.7.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picocolors@1.0.0: {} picocolors@1.1.0: {} @@ -4917,14 +5658,14 @@ snapshots: pino-std-serializers@7.0.0: {} - pino@9.5.0: + pino@9.6.0: dependencies: atomic-sleep: 1.0.0 fast-redact: 3.5.0 on-exit-leak-free: 2.1.2 pino-abstract-transport: 2.0.0 pino-std-serializers: 7.0.0 - process-warning: 4.0.0 + process-warning: 4.0.1 quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.5.0 @@ -4968,17 +5709,17 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.49 - postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.7.2)): + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.10)(typescript@5.7.2)): dependencies: lilconfig: 3.1.3 yaml: 2.6.0 optionalDependencies: postcss: 8.4.49 - ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.7.2) + ts-node: 10.9.2(@types/node@22.10.10)(typescript@5.7.2) postcss-load-config@5.0.3(jiti@1.21.6)(postcss@8.4.49): dependencies: - lilconfig: 3.1.2 + lilconfig: 3.1.3 yaml: 2.4.1 optionalDependencies: jiti: 1.21.6 @@ -5015,14 +5756,26 @@ snapshots: postgres-array@2.0.0: {} + postgres-array@3.0.2: {} + postgres-bytea@1.0.0: {} + postgres-bytea@3.0.0: + dependencies: + obuf: 1.1.2 + postgres-date@1.0.7: {} + postgres-date@2.1.0: {} + postgres-interval@1.2.0: dependencies: xtend: 4.0.2 + postgres-interval@3.0.0: {} + + postgres-range@1.1.4: {} + pretty-hrtime@1.0.3: {} pretty-ms@9.2.0: @@ -5034,18 +5787,14 @@ snapshots: '@prisma/engines': 6.0.1 optionalDependencies: fsevents: 2.3.3 + optional: true process-nextick-args@2.0.1: {} - process-warning@4.0.0: {} + process-warning@4.0.1: {} proto-list@1.2.4: {} - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - proxy-from-env@1.1.0: {} pstree.remy@1.1.8: {} @@ -5120,6 +5869,8 @@ snapshots: resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve@1.22.8: dependencies: is-core-module: 2.15.1 @@ -5144,7 +5895,7 @@ snapshots: safe-buffer@5.2.1: {} - safe-regex2@4.0.0: + safe-regex2@4.0.1: dependencies: ret: 0.5.0 @@ -5152,7 +5903,7 @@ snapshots: safer-buffer@2.1.2: {} - secure-json-parse@3.0.1: {} + secure-json-parse@3.0.2: {} selderee@0.11.0: dependencies: @@ -5271,6 +6022,11 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map@0.6.1: {} spawn-error-forwarder@1.0.0: {} @@ -5378,7 +6134,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - tailwindcss@3.4.16(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.7.2)): + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.10.10)(typescript@5.7.2)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -5397,7 +6153,7 @@ snapshots: postcss: 8.4.49 postcss-import: 15.1.0(postcss@8.4.49) postcss-js: 4.0.1(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.7.2)) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.10)(typescript@5.7.2)) postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -5459,14 +6215,14 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@types/node@22.9.0)(typescript@5.7.2): + ts-node@10.9.2(@types/node@22.10.10)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.9.0 + '@types/node': 22.10.10 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 @@ -5479,6 +6235,8 @@ snapshots: tslib@2.8.1: {} + tunnel@0.0.6: {} + type-fest@1.4.0: {} type-fest@2.19.0: {} @@ -5496,7 +6254,11 @@ snapshots: undefsafe@2.0.5: {} - undici-types@6.19.8: {} + undici-types@6.20.0: {} + + undici@5.28.4: + dependencies: + '@fastify/busboy': 2.1.1 unicode-emoji-modifier-base@1.0.0: {} @@ -5515,14 +6277,14 @@ snapshots: update-browserslist-db@1.1.0(browserslist@4.23.3): dependencies: browserslist: 4.23.3 - escalade: 3.1.2 + escalade: 3.2.0 picocolors: 1.1.1 url-join@5.0.0: {} util-deprecate@1.0.2: {} - uuid@11.0.2: {} + uuid@11.0.4: {} v8-compile-cache-lib@3.0.1: {} @@ -5590,3 +6352,5 @@ snapshots: yoctocolors@2.1.1: {} zod@3.23.8: {} + + zod@3.24.1: {} diff --git a/prisma/migrations/20231124224511_init/migration.sql b/prisma/migrations/20231124224511_init/migration.sql deleted file mode 100644 index 00666f6..0000000 --- a/prisma/migrations/20231124224511_init/migration.sql +++ /dev/null @@ -1,56 +0,0 @@ --- CreateEnum -CREATE TYPE "StatusVisibility" AS ENUM ('public', 'unlisted', 'private', 'direct'); - --- CreateTable -CREATE TABLE "MastodonInstance" ( - "id" TEXT NOT NULL, - "urlEncoded" TEXT NOT NULL, - "url" TEXT NOT NULL, - "applicationId" TEXT NOT NULL, - "applicationSecret" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "MastodonInstance_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "User" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "lastTootTime" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "name" TEXT NOT NULL, - "mastodonUid" TEXT NOT NULL, - "mastodonToken" TEXT NOT NULL, - "blueskyToken" TEXT, - "blueskyHandle" TEXT, - "mastodonInstanceId" TEXT NOT NULL, - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "UserSettings" ( - "id" TEXT NOT NULL, - "statusVisibility" "StatusVisibility" NOT NULL DEFAULT 'public', - "excludeReplies" BOOLEAN NOT NULL DEFAULT false, - "excludeReblogs" BOOLEAN NOT NULL DEFAULT false, - "excludeMentions" BOOLEAN NOT NULL DEFAULT false, - "excludeSensitive" BOOLEAN NOT NULL DEFAULT false, - "userId" TEXT NOT NULL, - - CONSTRAINT "UserSettings_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "MastodonInstance_urlEncoded_key" ON "MastodonInstance"("urlEncoded"); - --- CreateIndex -CREATE UNIQUE INDEX "MastodonInstance_url_key" ON "MastodonInstance"("url"); - --- AddForeignKey -ALTER TABLE "User" ADD CONSTRAINT "User_mastodonInstanceId_fkey" FOREIGN KEY ("mastodonInstanceId") REFERENCES "MastodonInstance"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "UserSettings" ADD CONSTRAINT "UserSettings_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20241024220214_user_bluesky_sessions/migration.sql b/prisma/migrations/20241024220214_user_bluesky_sessions/migration.sql deleted file mode 100644 index 8f05c45..0000000 --- a/prisma/migrations/20241024220214_user_bluesky_sessions/migration.sql +++ /dev/null @@ -1,3 +0,0 @@ --- AlterTable -ALTER TABLE "User" ADD COLUMN "blueskySession" JSONB, -ADD COLUMN "blueskySessionEvent" TEXT; diff --git a/prisma/migrations/20241025232212_reposts/migration.sql b/prisma/migrations/20241025232212_reposts/migration.sql deleted file mode 100644 index 0ac61ed..0000000 --- a/prisma/migrations/20241025232212_reposts/migration.sql +++ /dev/null @@ -1,16 +0,0 @@ --- CreateTable -CREATE TABLE "Repost" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "userId" TEXT NOT NULL, - "tootId" TEXT NOT NULL, - "bsRootUri" TEXT NOT NULL, - "bsRootCid" TEXT NOT NULL, - "bsParentUri" TEXT NOT NULL, - "bsParentCid" TEXT NOT NULL, - - CONSTRAINT "Repost_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "Repost" ADD CONSTRAINT "Repost_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20241031134028_user_delete_cascade/migration.sql b/prisma/migrations/20241031134028_user_delete_cascade/migration.sql deleted file mode 100644 index 9a0f067..0000000 --- a/prisma/migrations/20241031134028_user_delete_cascade/migration.sql +++ /dev/null @@ -1,11 +0,0 @@ --- DropForeignKey -ALTER TABLE "Repost" DROP CONSTRAINT "Repost_userId_fkey"; - --- DropForeignKey -ALTER TABLE "UserSettings" DROP CONSTRAINT "UserSettings_userId_fkey"; - --- AddForeignKey -ALTER TABLE "Repost" ADD CONSTRAINT "Repost_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "UserSettings" ADD CONSTRAINT "UserSettings_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20241118184906_add_pds_field_to_user/migration.sql b/prisma/migrations/20241118184906_add_pds_field_to_user/migration.sql deleted file mode 100644 index e80b86f..0000000 --- a/prisma/migrations/20241118184906_add_pds_field_to_user/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "User" ADD COLUMN "blueskyPDS" TEXT DEFAULT 'https://bsky.social'; diff --git a/prisma/migrations/20241215073828_add_relay_criteria/migration.sql b/prisma/migrations/20241215073828_add_relay_criteria/migration.sql deleted file mode 100644 index eb9a79e..0000000 --- a/prisma/migrations/20241215073828_add_relay_criteria/migration.sql +++ /dev/null @@ -1,6 +0,0 @@ --- CreateEnum -CREATE TYPE "RelayCriteria" AS ENUM ('all', 'favedBySelf', 'containsMarker', 'notContainsMarker'); - --- AlterTable -ALTER TABLE "User" ADD COLUMN "relayCriteria" "RelayCriteria" NOT NULL DEFAULT 'all', -ADD COLUMN "relayMarker" TEXT NOT NULL DEFAULT ''; diff --git a/prisma/migrations/20241223001124_orphan_user_settings/migration.sql b/prisma/migrations/20241223001124_orphan_user_settings/migration.sql deleted file mode 100644 index c0ed2a5..0000000 --- a/prisma/migrations/20241223001124_orphan_user_settings/migration.sql +++ /dev/null @@ -1,14 +0,0 @@ -/* - Warnings: - - - You are about to drop the `UserSettings` table. If the table is not empty, all the data it contains will be lost. - -*/ --- DropForeignKey -ALTER TABLE "UserSettings" DROP CONSTRAINT "UserSettings_userId_fkey"; - --- AlterTable -ALTER TABLE "User" ADD COLUMN "relayVisibility" "StatusVisibility"[] DEFAULT ARRAY['public']::"StatusVisibility"[]; - --- DropTable -DROP TABLE "UserSettings"; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml deleted file mode 100644 index fbffa92..0000000 --- a/prisma/migrations/migration_lock.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) -provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index 03aee32..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,69 +0,0 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "postgresql" - url = env("POSTGRES_URL") -} - -enum StatusVisibility { - public - unlisted - private - direct -} - -enum RelayCriteria { - all - favedBySelf - containsMarker - notContainsMarker -} - -model MastodonInstance { - id String @id @default(uuid()) - urlEncoded String @unique - url String @unique - applicationId String - applicationSecret String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - users User[] -} - -model User { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - lastTootTime DateTime @default(now()) - name String - mastodonInstance MastodonInstance @relation(fields: [mastodonInstanceId], references: [id]) - mastodonUid String - mastodonToken String - blueskyToken String? - blueskyHandle String? - blueskyPDS String? @default("https://bsky.social") - blueskySession Json? - blueskySessionEvent String? - mastodonInstanceId String - relayCriteria RelayCriteria @default(all) - relayMarker String @default("") - relayVisibility StatusVisibility[] @default([public]) - Repost Repost[] -} - -model Repost { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - userId String - tootId String - bsRootUri String - bsRootCid String - bsParentUri String - bsParentCid String -} diff --git a/routes/root.ts b/routes/root.ts index 8da2092..56d7cf4 100644 --- a/routes/root.ts +++ b/routes/root.ts @@ -1,12 +1,11 @@ import { intiBlueskyAgent, validateBlueskyAppPassword, validateBlueskyCredentials, validateBlueskyHandle } from './../lib/bluesky' import { authenticateJWT, checkValidHttpsUrl } from './../lib/utils' -import { db } from './../lib/db' +import { db, findUserById, persistBlueskyCreds, updateRelaySettings } from './../lib/db' import { FastifyInstance } from 'fastify' -import { StatusVisibility } from '@prisma/client' export const routesRoot = async (app: FastifyInstance, options: Object) => { app.get('/', { onRequest: [authenticateJWT] }, async (req, res) => { - const user = await db.user.findFirst({ where: { id: req.user.id } }) + const user = await findUserById(req.user.id); return res.view("index", { userName: req.user.mastodonHandle, @@ -28,7 +27,7 @@ export const routesRoot = async (app: FastifyInstance, options: Object) => { blueskyPDS: string } }>('/settings/blueskyCreds', { onRequest: [authenticateJWT] }, async (req, res) => { - const user = await db.user.findFirst({ where: { id: req.user.id }, include: { mastodonInstance: true } }) + const user = await findUserById(req.user.id, true); let response_data: any = { err: undefined, @@ -60,16 +59,7 @@ export const routesRoot = async (app: FastifyInstance, options: Object) => { err: 'Invalid Bluesky Credentials, could not authenticate' }) - await db.user.update({ - where: { - id: req.user.id - }, - data: { - blueskyHandle: req.body.blueskyHandle, - blueskyToken: req.body.blueskyToken, - blueskyPDS: req.body.blueskyPDS, - } - }) + await persistBlueskyCreds(req.user.id, req.body.blueskyHandle, req.body.blueskyToken, req.body.blueskyPDS) return res.redirect('/') }) @@ -78,10 +68,10 @@ export const routesRoot = async (app: FastifyInstance, options: Object) => { Body: { relayCriteria: any, relayMarker: string, - relayVisibility: StatusVisibility[] + relayVisibility: string[] } }>('/settings/repost', { onRequest: [authenticateJWT] }, async (req, res) => { - const user = await db.user.findFirst({ where: { id: req.user.id }, include: { mastodonInstance: true } }) + const user = await findUserById(req.user.id, true); let response_data: any = { err: undefined, @@ -102,16 +92,7 @@ export const routesRoot = async (app: FastifyInstance, options: Object) => { console.log(relayVisibility) - await db.user.update({ - where: { - id: req.user.id - }, - data: { - relayCriteria: req.body.relayCriteria, - relayMarker: req.body.relayMarker, - relayVisibility: relayVisibility - } - }) + await updateRelaySettings(req.user.id, req.body.relayCriteria, req.body.relayMarker, relayVisibility) return res.redirect('/') }) @@ -119,4 +100,8 @@ export const routesRoot = async (app: FastifyInstance, options: Object) => { app.get('/privacy', async (req, res) => { return res.view("privacy", {}) }) + + app.get('/health', async (req, res) => { + return res.send({ status: "ok" }) + }) } \ No newline at end of file diff --git a/routes/user.ts b/routes/user.ts index fc2a830..6746dae 100644 --- a/routes/user.ts +++ b/routes/user.ts @@ -1,7 +1,7 @@ import { FastifyInstance } from "fastify"; import { Mastodon } from 'megalodon' import { authenticateJWT, domainToUrl, genCallBackUrl, validateDomain } from './../lib/utils' -import { db, getInstanceByDomain, getUserByMastodonUid } from './../lib/db' +import { createMastodonInstance, createUser, db, deleteUser, getAllUserInformation, getInstanceByDomain, getUserByMastodonUid, updateUser } from './../lib/db' import { AtpSessionData } from "@atproto/api"; export const routesUser = async (app: FastifyInstance, options: Object) => { @@ -14,37 +14,13 @@ export const routesUser = async (app: FastifyInstance, options: Object) => { }) app.post('/account/delete', { onRequest: [authenticateJWT] }, async (req, res) => { - await db.user.delete({ - where: { - id: req.user.id - } - }) + deleteUser(req.user) return res.clearCookie('token').redirect('/login') }) app.get('/account/downloadData', { onRequest: [authenticateJWT] }, async (req, res) => { - let user = await db.user.findFirst( - { - where: { id: req.user.id }, - select: { - mastodonInstance: { - select: { - url: true, - } - }, - createdAt: true, - updatedAt: true, - mastodonUid: true, - mastodonToken: false, - name: true, - lastTootTime: true, - blueskyHandle: true, - blueskyToken: false, - blueskySession: true, - blueskyPDS: true, - } - }) - + let user = await getAllUserInformation(req.user.id); + if (user) { if(user.blueskySession) { const blueskySession = user?.blueskySession as unknown as AtpSessionData @@ -58,10 +34,11 @@ export const routesUser = async (app: FastifyInstance, options: Object) => { status: blueskySession?.status, } } - - - res.header('Content-Disposition', `attachment; filename=skymoth-userdata-${user?.name}.json`) - res.send(user).type('application/json').code(200).redirect('/') + res.header('Content-Disposition', `attachment; filename=skymoth-userdata-${user?.name}.json`) + res.send(user).type('application/json').code(200).redirect('/') + } else { + return res.status(404).send('User not found') + } }) app.get<{ @@ -92,14 +69,7 @@ export const routesUser = async (app: FastifyInstance, options: Object) => { redirect_uris: genCallBackUrl(instanceDomain) }) - knownInstance = await db.mastodonInstance.create({ - data: { - url: instanceDomain, - urlEncoded: btoa(instanceDomain), - applicationId: appData.client_id, - applicationSecret: appData.client_secret - } - }) + knownInstance = (await createMastodonInstance(instanceDomain, appData))[0] } const authUrl = await client.generateAuthUrl(knownInstance.applicationId, knownInstance.applicationSecret, { @@ -134,34 +104,12 @@ export const routesUser = async (app: FastifyInstance, options: Object) => { const userClient = new Mastodon(domainToUrl(instance.url), token.access_token) const verifiedCredentials = await userClient.verifyAccountCredentials(); - let user = await getUserByMastodonUid(verifiedCredentials.data.id, instance.id) + let user: any = await getUserByMastodonUid(verifiedCredentials.data.id, instance.id) if (!user) { - user = await db.user.create({ - data: { - mastodonInstance: { - connect: { - id: instance.id - } - }, - mastodonUid: verifiedCredentials.data.id, - mastodonToken: token.access_token, - name: verifiedCredentials.data.username, - lastTootTime: new Date() - } - }) + user = (await createUser(instance.id, verifiedCredentials, token))[0] } else { - console.log('updating user') - - user = await db.user.update({ - where: { - id: user.id - }, - data: { - mastodonToken: token.access_token, - name: verifiedCredentials.data.username, - } - }) + user = (await updateUser(user.id, token, verifiedCredentials.data.username))[0] } const jwt = app.jwt.sign({ diff --git a/tsconfig.json b/tsconfig.json index b5a5492..c1d6898 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "esModuleInterop": true, - "outDir": "./dist" + "outDir": "./dist", + "strict": true } } \ No newline at end of file