-76
Caddyfile
-76
Caddyfile
···
1
-
{
2
-
storage file_system /data/
3
-
debug
4
-
pki {
5
-
ca hayden {
6
-
name "Hayden"
7
-
}
8
-
}
9
-
}
10
-
11
-
api.dev.hayden.moe {
12
-
tls {
13
-
issuer internal {
14
-
ca hayden
15
-
}
16
-
}
17
-
18
-
reverse_proxy http://host.docker.internal:8080
19
-
}
20
-
21
-
cookware.dev.hayden.moe {
22
-
tls {
23
-
issuer internal {
24
-
ca hayden
25
-
}
26
-
}
27
-
28
-
reverse_proxy http://host.docker.internal:5173
29
-
30
-
handle_path /xrpc/* {
31
-
rewrite * /xrpc{uri}
32
-
reverse_proxy http://host.docker.internal:8080
33
-
}
34
-
handle_path /api/* {
35
-
rewrite * /api{uri}
36
-
reverse_proxy http://host.docker.internal:8080
37
-
}
38
-
}
39
-
40
-
http://*.trycloudflare.com {
41
-
reverse_proxy http://host.docker.internal:5173
42
-
43
-
handle_path /xrpc/* {
44
-
rewrite * /xrpc{uri}
45
-
reverse_proxy http://host.docker.internal:8080
46
-
}
47
-
handle_path /oauth/* {
48
-
rewrite * /oauth{uri}
49
-
reverse_proxy http://host.docker.internal:8080
50
-
}
51
-
handle_path /api/* {
52
-
rewrite * /api{uri}
53
-
reverse_proxy http://host.docker.internal:8080
54
-
}
55
-
}
56
-
57
-
acme.dev.hayden.moe {
58
-
tls {
59
-
issuer internal {
60
-
ca hayden
61
-
}
62
-
}
63
-
acme_server {
64
-
ca hayden
65
-
}
66
-
}
67
-
68
-
turso.dev.hayden.moe {
69
-
tls {
70
-
issuer internal {
71
-
ca hayden
72
-
}
73
-
}
74
-
75
-
reverse_proxy http://libsql:8080
76
-
}
+1
apps/api/migrations
+1
apps/api/migrations
···
1
+
../../libs/database/migrations
+8
-5
apps/api/package.json
+8
-5
apps/api/package.json
···
2
2
"name": "@cookware/api",
3
3
"type": "module",
4
4
"private": true,
5
-
"main": "dist/index.js",
5
+
"main": "src/index.ts",
6
6
"publishConfig": {
7
7
"access": "public"
8
8
},
9
9
"scripts": {
10
-
"dev": "NODE_OPTIONS=--use-openssl-ca tsx watch --clear-screen=false src/index.ts | pino-pretty",
10
+
"dev": "wrangler dev",
11
11
"build": "tsup",
12
12
"start": "NODE_OPTIONS=--use-openssl-ca node dist/index.cjs",
13
13
"clean": "rimraf dist"
14
14
},
15
15
"dependencies": {
16
-
"@atcute/client": "^2.0.6",
16
+
"@atcute/atproto": "^3.1.9",
17
+
"@atcute/client": "^4.0.5",
18
+
"@atcute/lexicons": "^1.2.3",
17
19
"@atcute/xrpc-server": "^0.1.3",
18
20
"@atcute/xrpc-server-cloudflare": "^0.1.0",
19
21
"@atproto/api": "^0.13.19",
···
38
40
"zod": "^3.23.8"
39
41
},
40
42
"devDependencies": {
41
-
"@atcute/bluesky": "^1.0.9",
43
+
"@atcute/bluesky": "^3.2.10",
42
44
"@cookware/tsconfig": "workspace:*",
43
45
"@swc/core": "^1.9.3",
44
46
"@types/ws": "^8.5.13",
···
48
50
"ts-node": "^10.9.2",
49
51
"tsup": "^8.3.5",
50
52
"tsx": "^4.19.2",
51
-
"typescript": "^5.7.2"
53
+
"typescript": "^5.7.2",
54
+
"wrangler": "^4.50.0"
52
55
},
53
56
"tsup": {
54
57
"entry": [
-34
apps/api/src/config/env.ts
-34
apps/api/src/config/env.ts
···
1
-
import { z } from "zod";
2
-
3
-
const envSchema = z.object({
4
-
PORT: z.coerce.number().lte(65535).default(8080),
5
-
HOST: z.string().ip().default('0.0.0.0'),
6
-
7
-
PUBLIC_DIR: z.string().default('../web/dist'),
8
-
9
-
CORS_ORIGINS: z
10
-
.string()
11
-
.transform((arg) => arg.split(','))
12
-
.default('http://127.0.0.1:5173,https://cookware.local.recipes.blue'),
13
-
14
-
PLC_DIRECTORY_URL: z.string().url().default('https://plc.directory'),
15
-
16
-
JWKS_PRIVATE_KEY: z.string().default('{"kty":"EC","x":"pew2xWIyBQ4XSY4gcCuTJBI-oC5rQqQlcDxIN8nN834","y":"aiJFNEFWyKKWGiFKPRvLAU4wdhsfgysfTfTuzTC4LNQ","crv":"P-256","d":"QS-q9RzH1u2Oj8gDiUzLk1qpGxZjKSf-3Z1oKCRL_jQ"}'),
17
-
18
-
SESSION_KEY: z.string().default('bJVS+Dx03A3QWWfW3A5Om5DGx1GKptx+1IGAXzOTpw8='),
19
-
SESSION_TTL: z.number().default(((60 * 60) * 24) * 5), // expire in 5 days
20
-
21
-
SENTRY_DSN: z.string().or(z.undefined()),
22
-
23
-
ENV: z
24
-
.union([
25
-
z.literal('development'),
26
-
z.literal('production'),
27
-
])
28
-
.default('development'),
29
-
});
30
-
31
-
const env = envSchema.parse(process.env);
32
-
33
-
export default env;
34
-
export type Env = z.infer<typeof envSchema>;
+10
apps/api/src/env.d.ts
+10
apps/api/src/env.d.ts
···
1
1
/// <reference types="@atcute/bluesky/lexicons" />
2
2
/// <reference types="@cookware/lexicons" />
3
+
4
+
import { DrizzleD1Database } from "drizzle-orm/d1";
5
+
6
+
declare global {
7
+
interface RouterContext {
8
+
env: Env;
9
+
ctx: ExecutionContext;
10
+
db: DrizzleD1Database;
11
+
}
12
+
}
+22
-75
apps/api/src/index.ts
+22
-75
apps/api/src/index.ts
···
1
-
import { json, XRPCRouter } from '@atcute/xrpc-server';
1
+
import { XRPCRouter } from '@atcute/xrpc-server';
2
2
import { cors } from '@atcute/xrpc-server/middlewares/cors';
3
3
import { createCloudflareWebSocket } from '@atcute/xrpc-server-cloudflare';
4
-
import { BlueRecipesFeedDefs, BlueRecipesFeedGetRecipes } from '@cookware/lexicons';
5
-
import { DID, getDidFromHandleOrDid } from '@cookware/lexicons/did';
6
-
import { db, recipeTable } from '@cookware/database';
7
-
import { desc, eq, sql } from 'drizzle-orm';
8
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
9
-
import { getAuthorInfo } from './util/api.js';
4
+
import { registerGetRecipes } from './xrpc/blue.recipes.feed.getRecipes.js';
5
+
import { drizzle } from 'drizzle-orm/d1';
6
+
import { registerGetRecipe } from './xrpc/blue.recipes.feed.getRecipe.js';
10
7
11
-
const adapter = createCloudflareWebSocket();
12
-
const router = new XRPCRouter({
13
-
websocket: adapter,
14
-
middlewares: [
15
-
cors({
16
-
allowedHeaders: ['Content-Type', 'Accept'],
17
-
exposedHeaders: ['Content-Length'],
18
-
}),
19
-
],
20
-
});
21
-
22
-
router.addQuery(BlueRecipesFeedGetRecipes.mainSchema, {
23
-
async handler({ params: { did: didQuery } }) {
24
-
let did: DID | null = null;
25
-
if (didQuery)
26
-
did = await getDidFromHandleOrDid(didQuery);
27
-
28
-
const recipes = await db
29
-
.select({
30
-
rkey: recipeTable.rkey,
31
-
title: recipeTable.title,
32
-
description: recipeTable.description,
33
-
time: recipeTable.time,
34
-
serves: recipeTable.serves,
35
-
ingredientsCount: sql`json_array_length(${recipeTable.ingredients})`,
36
-
stepsCount: sql`json_array_length(${recipeTable.steps})`,
37
-
createdAt: recipeTable.createdAt,
38
-
authorDid: recipeTable.authorDid,
39
-
imageRef: recipeTable.imageRef,
40
-
uri: sql`concat(${recipeTable.authorDid}, "/", ${recipeTable.rkey})`.as('uri'),
41
-
})
42
-
.from(recipeTable)
43
-
.where(did ? eq(recipeTable.authorDid, did) : undefined)
44
-
.orderBy(desc(recipeTable.createdAt));
45
-
46
-
const rpc = new XRPC({
47
-
handler: simpleFetchHandler({
48
-
service: 'https://public.api.bsky.app',
8
+
const createRouter = (env: Env, ctx: ExecutionContext) => {
9
+
const adapter = createCloudflareWebSocket();
10
+
const router = new XRPCRouter({
11
+
websocket: adapter,
12
+
middlewares: [
13
+
cors({
14
+
allowedHeaders: ['Content-Type', 'Accept'],
15
+
exposedHeaders: ['Content-Length'],
49
16
}),
50
-
});
51
-
52
-
let authorInfo: BlueRecipesFeedDefs.AuthorInfo | null = null;
53
-
if (did) {
54
-
authorInfo = await getAuthorInfo(did, rpc);
55
-
};
17
+
],
18
+
});
56
19
57
-
const results = [];
58
-
const eachRecipe = async (r: typeof recipes[0]) => ({
59
-
author: authorInfo || await getAuthorInfo(r.authorDid, rpc),
60
-
rkey: r.rkey,
61
-
title: r.title,
62
-
time: r.time,
63
-
serves: r.serves ?? 1,
64
-
description: r.description || undefined,
65
-
ingredients: r.ingredientsCount as number,
66
-
steps: r.stepsCount as number,
67
-
imageUrl: r.imageRef
68
-
? `https://cdn.bsky.app/img/feed_thumbnail/plain/${r.authorDid}/${r.imageRef}@jpeg`
69
-
: undefined,
70
-
});
20
+
const db = drizzle(env.DB, { logger: true });
71
21
72
-
for (const result of recipes) {
73
-
results.push(await eachRecipe(result));
74
-
}
22
+
registerGetRecipes(router, { env, ctx, db });
23
+
registerGetRecipe(router, { env, ctx, db });
75
24
76
-
return json({
77
-
author: authorInfo || undefined,
78
-
recipes: results,
79
-
});
80
-
}
81
-
});
25
+
return router;
26
+
}
82
27
83
-
export default router satisfies ExportedHandler;
28
+
export default {
29
+
fetch: (req, env, ctx) => createRouter(env, ctx).fetch(req),
30
+
} satisfies ExportedHandler<Env>;
-5
apps/api/src/logger.ts
-5
apps/api/src/logger.ts
-5
apps/api/src/recipes/index.ts
-5
apps/api/src/recipes/index.ts
+22
-10
apps/api/src/util/api.ts
+22
-10
apps/api/src/util/api.ts
···
1
-
import { XRPC } from '@atcute/client';
2
-
import { AppBskyActorProfile } from '@atcute/client/lexicons';
1
+
import { Client } from '@atcute/client';
2
+
import { AppBskyActorProfile } from '@atcute/bluesky';
3
3
import type { BlueRecipesFeedDefs } from '@cookware/lexicons';
4
-
import { DID, getDidDoc } from '@cookware/lexicons/did';
4
+
import { getDidDoc } from '@cookware/lexicons/did';
5
+
import { Did } from '@atcute/lexicons';
6
+
7
+
import type {} from '@atcute/atproto';
8
+
import { isBlob, isLegacyBlob } from '@atcute/lexicons/interfaces';
5
9
6
10
export const getAuthorInfo = async (
7
-
did: DID,
8
-
rpc: XRPC,
11
+
did: Did,
12
+
rpc: Client,
9
13
): Promise<BlueRecipesFeedDefs.AuthorInfo> => {
10
14
const author = await getDidDoc(did);
11
-
const profile = await rpc.get('com.atproto.repo.getRecord', {
15
+
const { ok, data } = await rpc.get('com.atproto.repo.getRecord', {
12
16
params: {
13
17
repo: did,
14
18
collection: 'app.bsky.actor.profile',
15
19
rkey: 'self',
16
20
},
17
21
});
18
-
const data = profile.data.value as AppBskyActorProfile.Record;
22
+
23
+
if (!ok) throw new Error(`Failed to query Bluesky profile: ${data.error}`);
24
+
25
+
const profile = data.value as AppBskyActorProfile.Main;
19
26
20
27
let info: BlueRecipesFeedDefs.AuthorInfo = {
21
28
did: did,
22
29
handle: author.alsoKnownAs[0]?.substring(5) as string,
23
-
displayName: data.displayName,
30
+
displayName: profile.displayName,
24
31
};
25
32
26
-
if (data.avatar)
27
-
info['avatarUrl'] = `https://cdn.bsky.app/img/avatar_thumbnail/plain/${did}/${data.avatar.ref.$link}@jpeg`;
33
+
if (profile.avatar) {
34
+
if (isBlob(profile.avatar)) {
35
+
info['avatarUrl'] = `https://cdn.bsky.app/img/avatar_thumbnail/plain/${did}/${profile.avatar.ref.$link}@jpeg`;
36
+
} else if (isLegacyBlob(profile.avatar)) {
37
+
info.avatarUrl = `https://cdn.bsky.app/img/avatar_thumbnail/plain/${did}/${profile.avatar.cid}@jpeg`
38
+
}
39
+
}
28
40
29
41
return info;
30
42
};
+67
apps/api/src/xrpc/blue.recipes.feed.getRecipe.ts
+67
apps/api/src/xrpc/blue.recipes.feed.getRecipe.ts
···
1
+
import { json, XRPCRouter, XRPCError } from '@atcute/xrpc-server';
2
+
import { BlueRecipesFeedGetRecipe } from '@cookware/lexicons';
3
+
import { getDidFromHandleOrDid } from '@cookware/lexicons/did';
4
+
import { recipeTable } from '@cookware/database';
5
+
import { and, eq } from 'drizzle-orm';
6
+
import { Client, simpleFetchHandler } from '@atcute/client';
7
+
import { getAuthorInfo } from '../util/api.js';
8
+
9
+
export const registerGetRecipe = (router: XRPCRouter, { db }: RouterContext) => {
10
+
router.addQuery(BlueRecipesFeedGetRecipe.mainSchema, {
11
+
async handler({ params: { did, rkey } }) {
12
+
if (!did) throw new Error('Invalid DID');
13
+
if (!rkey) throw new Error('Invalid rkey');
14
+
15
+
let parsedDid = await getDidFromHandleOrDid(did);
16
+
if (!parsedDid) {
17
+
throw new XRPCError({
18
+
status: 404,
19
+
error: 'InvalidDid',
20
+
description: 'No such author was found by that identifier.',
21
+
});
22
+
}
23
+
24
+
const recipe = await db
25
+
.select()
26
+
.from(recipeTable)
27
+
.where(
28
+
and(
29
+
eq(recipeTable.authorDid, parsedDid),
30
+
eq(recipeTable.rkey, rkey),
31
+
),
32
+
)
33
+
.limit(1)
34
+
.get();
35
+
36
+
if (!recipe) {
37
+
throw new XRPCError({
38
+
status: 404,
39
+
error: 'RecipeNotFound',
40
+
description: 'No such recipe was found in the index.',
41
+
});
42
+
}
43
+
44
+
const rpc = new Client({
45
+
handler: simpleFetchHandler({
46
+
service: 'https://public.api.bsky.app',
47
+
}),
48
+
});
49
+
50
+
const authorInfo = await getAuthorInfo(recipe.authorDid, rpc);
51
+
52
+
return json({
53
+
recipe: {
54
+
author: authorInfo,
55
+
title: recipe.title,
56
+
time: recipe.time,
57
+
serves: recipe.serves || undefined,
58
+
description: recipe.description || undefined,
59
+
ingredients: recipe.ingredients,
60
+
steps: recipe.steps,
61
+
imageUrl: recipe.imageRef
62
+
? `https://cdn.bsky.app/img/feed_thumbnail/plain/${recipe.authorDid}/${recipe.imageRef}@jpeg`
63
+
: undefined,
64
+
},
65
+
}); }
66
+
});
67
+
};
+70
apps/api/src/xrpc/blue.recipes.feed.getRecipes.ts
+70
apps/api/src/xrpc/blue.recipes.feed.getRecipes.ts
···
1
+
import { json, XRPCRouter } from '@atcute/xrpc-server';
2
+
import { BlueRecipesFeedDefs, BlueRecipesFeedGetRecipes } from '@cookware/lexicons';
3
+
import { DID, getDidFromHandleOrDid } from '@cookware/lexicons/did';
4
+
import { recipeTable } from '@cookware/database';
5
+
import { desc, eq, sql } from 'drizzle-orm';
6
+
import { simpleFetchHandler, XRPC } from '@atcute/client';
7
+
import { getAuthorInfo } from '../util/api.js';
8
+
9
+
export const registerGetRecipes = (router: XRPCRouter, { db }: RouterContext) => {
10
+
router.addQuery(BlueRecipesFeedGetRecipes.mainSchema, {
11
+
async handler({ params: { did: didQuery } }) {
12
+
let did: DID | null = null;
13
+
if (didQuery)
14
+
did = await getDidFromHandleOrDid(didQuery);
15
+
16
+
const recipes = await db
17
+
.select({
18
+
rkey: recipeTable.rkey,
19
+
title: recipeTable.title,
20
+
description: recipeTable.description,
21
+
time: recipeTable.time,
22
+
serves: recipeTable.serves,
23
+
ingredientsCount: sql`json_array_length(${recipeTable.ingredients})`,
24
+
stepsCount: sql`json_array_length(${recipeTable.steps})`,
25
+
createdAt: recipeTable.createdAt,
26
+
authorDid: recipeTable.authorDid,
27
+
imageRef: recipeTable.imageRef,
28
+
uri: sql`concat(${recipeTable.authorDid}, "/", ${recipeTable.rkey})`.as('uri'),
29
+
})
30
+
.from(recipeTable)
31
+
.where(did ? eq(recipeTable.authorDid, did) : undefined)
32
+
.orderBy(desc(recipeTable.createdAt));
33
+
34
+
const rpc = new XRPC({
35
+
handler: simpleFetchHandler({
36
+
service: 'https://public.api.bsky.app',
37
+
}),
38
+
});
39
+
40
+
let authorInfo: BlueRecipesFeedDefs.AuthorInfo | null = null;
41
+
if (did) {
42
+
authorInfo = await getAuthorInfo(did, rpc);
43
+
};
44
+
45
+
const results = [];
46
+
const eachRecipe = async (r: typeof recipes[0]) => ({
47
+
author: authorInfo || await getAuthorInfo(r.authorDid, rpc),
48
+
rkey: r.rkey,
49
+
title: r.title,
50
+
time: r.time,
51
+
serves: r.serves ?? 1,
52
+
description: r.description || undefined,
53
+
ingredients: r.ingredientsCount as number,
54
+
steps: r.stepsCount as number,
55
+
imageUrl: r.imageRef
56
+
? `https://cdn.bsky.app/img/feed_thumbnail/plain/${r.authorDid}/${r.imageRef}@jpeg`
57
+
: undefined,
58
+
});
59
+
60
+
for (const result of recipes) {
61
+
results.push(await eachRecipe(result));
62
+
}
63
+
64
+
return json({
65
+
author: authorInfo || undefined,
66
+
recipes: results,
67
+
});
68
+
}
69
+
});
70
+
};
-125
apps/api/src/xrpc/index.ts
-125
apps/api/src/xrpc/index.ts
···
1
-
import { Hono } from 'hono';
2
-
import { db, recipeTable } from '@cookware/database';
3
-
import { and, desc, eq, sql } from 'drizzle-orm';
4
-
import { DID, getDidFromHandleOrDid } from '@cookware/lexicons';
5
-
import { simpleFetchHandler, XRPC } from '@atcute/client';
6
-
import { BlueRecipesFeedDefs, BlueRecipesFeedGetRecipes } from '@atcute/client/lexicons';
7
-
import { getAuthorInfo } from '../util/api.js';
8
-
9
-
export const xrpcApp = new Hono();
10
-
11
-
xrpcApp.get('/blue.recipes.feed.getRecipes', async ctx => {
12
-
const { did: didQuery } = ctx.req.query();
13
-
14
-
let did: DID | null = null;
15
-
if (didQuery)
16
-
did = await getDidFromHandleOrDid(didQuery);
17
-
18
-
const recipes = await db
19
-
.select({
20
-
rkey: recipeTable.rkey,
21
-
title: recipeTable.title,
22
-
description: recipeTable.description,
23
-
time: recipeTable.time,
24
-
serves: recipeTable.serves,
25
-
ingredientsCount: sql`json_array_length(${recipeTable.ingredients})`,
26
-
stepsCount: sql`json_array_length(${recipeTable.steps})`,
27
-
createdAt: recipeTable.createdAt,
28
-
authorDid: recipeTable.authorDid,
29
-
imageRef: recipeTable.imageRef,
30
-
uri: sql`concat(${recipeTable.authorDid}, "/", ${recipeTable.rkey})`.as('uri'),
31
-
})
32
-
.from(recipeTable)
33
-
.where(did ? eq(recipeTable.authorDid, did) : undefined)
34
-
.orderBy(desc(recipeTable.createdAt));
35
-
36
-
const rpc = new XRPC({
37
-
handler: simpleFetchHandler({
38
-
service: 'https://public.api.bsky.app',
39
-
}),
40
-
});
41
-
42
-
let authorInfo: BlueRecipesFeedDefs.AuthorInfo | null = null;
43
-
if (did) {
44
-
authorInfo = await getAuthorInfo(did, rpc);
45
-
};
46
-
47
-
const results = [];
48
-
const eachRecipe = async (r: typeof recipes[0]) => ({
49
-
author: authorInfo || await getAuthorInfo(r.authorDid, rpc),
50
-
rkey: r.rkey,
51
-
title: r.title,
52
-
time: r.time,
53
-
serves: r.serves ?? 1,
54
-
description: r.description || undefined,
55
-
ingredients: r.ingredientsCount as number,
56
-
steps: r.stepsCount as number,
57
-
imageUrl: r.imageRef
58
-
? `https://cdn.bsky.app/img/feed_thumbnail/plain/${r.authorDid}/${r.imageRef}@jpeg`
59
-
: undefined,
60
-
});
61
-
62
-
for (const result of recipes) {
63
-
results.push(await eachRecipe(result));
64
-
}
65
-
66
-
let result: BlueRecipesFeedGetRecipes.Output = {
67
-
author: authorInfo || undefined,
68
-
recipes: results,
69
-
};
70
-
71
-
return ctx.json(result);
72
-
});
73
-
74
-
xrpcApp.get('/blue.recipes.feed.getRecipe', async ctx => {
75
-
const { did, rkey } = ctx.req.query();
76
-
if (!did) throw new Error('Invalid DID');
77
-
if (!rkey) throw new Error('Invalid rkey');
78
-
79
-
let parsedDid = await getDidFromHandleOrDid(did);
80
-
if (!parsedDid) {
81
-
ctx.status(404);
82
-
return ctx.json({
83
-
error: 'invalid_did',
84
-
message: 'No such author was found by that identifier.',
85
-
});
86
-
}
87
-
88
-
const recipe = await db.query.recipeTable.findFirst({
89
-
where: and(
90
-
eq(recipeTable.authorDid, parsedDid),
91
-
eq(recipeTable.rkey, rkey),
92
-
),
93
-
});
94
-
95
-
if (!recipe) {
96
-
ctx.status(404);
97
-
return ctx.json({
98
-
error: 'not_found',
99
-
message: 'No such recipe was found in the index.',
100
-
});
101
-
}
102
-
103
-
const rpc = new XRPC({
104
-
handler: simpleFetchHandler({
105
-
service: 'https://public.api.bsky.app',
106
-
}),
107
-
});
108
-
109
-
const authorInfo = await getAuthorInfo(recipe.authorDid, rpc);
110
-
111
-
return ctx.json({
112
-
recipe: {
113
-
author: authorInfo,
114
-
title: recipe.title,
115
-
time: recipe.time,
116
-
serves: recipe.serves,
117
-
description: recipe.description,
118
-
ingredients: recipe.ingredients,
119
-
steps: recipe.steps,
120
-
imageUrl: recipe.imageRef
121
-
? `https://cdn.bsky.app/img/feed_thumbnail/plain/${recipe.authorDid}/${recipe.imageRef}@jpeg`
122
-
: null,
123
-
},
124
-
});
125
-
});
+2
-1
apps/api/worker-configuration.d.ts
+2
-1
apps/api/worker-configuration.d.ts
···
1
1
/* eslint-disable */
2
-
// Generated by Wrangler by running `wrangler types` (hash: b739a9c19cff1463949c4db47674ed86)
2
+
// Generated by Wrangler by running `wrangler types` (hash: 973863b87c5f17b377119a1dc8be79cf)
3
3
// Runtime types generated with workerd@1.20251118.0 2025-11-23
4
4
declare namespace Cloudflare {
5
5
interface GlobalProps {
6
6
mainModule: typeof import("./src/index");
7
7
}
8
8
interface Env {
9
+
DB: D1Database;
9
10
}
10
11
}
11
12
interface Env extends Cloudflare.Env {}
+14
apps/api/wrangler.json
+14
apps/api/wrangler.json
···
1
+
{
2
+
"$schema": "./node_modules/wrangler/config-schema.json",
3
+
"name": "recipes-blue-api",
4
+
"main": "src/index.ts",
5
+
"compatibility_date": "2025-11-23",
6
+
"observability": { "enabled": true },
7
+
"d1_databases": [
8
+
{
9
+
"binding": "DB",
10
+
"database_name": "recipesblue",
11
+
"migrations_dir": "../../libs/database/migrations"
12
+
}
13
+
]
14
+
}
-4
apps/api/wrangler.toml
-4
apps/api/wrangler.toml
+1
-1
apps/ingester/package.json
+1
-1
apps/ingester/package.json
+3
-1
apps/web/package.json
+3
-1
apps/web/package.json
···
10
10
"preview": "vite preview"
11
11
},
12
12
"dependencies": {
13
-
"@atcute/client": "^2.0.6",
13
+
"@atcute/atproto": "^3.1.9",
14
+
"@atcute/client": "^4.0.5",
15
+
"@atcute/lexicons": "^1.2.3",
14
16
"@atcute/oauth-browser-client": "^1.0.7",
15
17
"@atproto/common": "^0.4.5",
16
18
"@atproto/common-web": "^0.3.1",
+6
-6
apps/web/src/hooks/use-xrpc.tsx
+6
-6
apps/web/src/hooks/use-xrpc.tsx
···
1
1
import { SERVER_URL } from "@/lib/utils";
2
2
import { useAuth } from "@/state/auth";
3
-
import { CredentialManager, XRPC } from "@atcute/client"
3
+
import { Client, simpleFetchHandler } from "@atcute/client";
4
4
5
5
export function useXrpc() {
6
6
const { agent } = useAuth();
7
7
8
8
if (agent) {
9
-
return new XRPC({
9
+
return new Client({
10
10
handler: agent,
11
11
proxy: {
12
-
type: 'api',
13
-
service: `did:web:${SERVER_URL}`,
12
+
did: `did:web:${SERVER_URL}`,
13
+
serviceId: '#recipes_blue',
14
14
},
15
15
});
16
16
}
17
17
18
-
const creds = new CredentialManager({ service: `https://${SERVER_URL}` });
19
-
return new XRPC({ handler: creds });
18
+
const handler = simpleFetchHandler({ service: `https://${SERVER_URL}` });
19
+
return new Client({ handler });
20
20
}
+37
-21
apps/web/src/queries/recipe.ts
+37
-21
apps/web/src/queries/recipe.ts
···
1
1
import { useXrpc } from "@/hooks/use-xrpc";
2
2
import { useAuth } from "@/state/auth";
3
-
import { XRPC, XRPCError } from "@atcute/client";
4
-
import { RecipeCollection } from "@cookware/lexicons";
5
3
import { queryOptions, useMutation, useQuery } from "@tanstack/react-query";
4
+
import { Client } from "@atcute/client";
6
5
import { notFound } from "@tanstack/react-router";
7
6
import { UseFormReturn } from "react-hook-form";
8
7
import { TID } from '@atproto/common-web';
9
8
import { recipeSchema } from "@/forms/recipe";
10
9
import { z } from "zod";
10
+
import { ActorIdentifier, Did } from "@atcute/lexicons";
11
+
12
+
import type {} from '@atcute/atproto';
13
+
import type {} from '@cookware/lexicons';
11
14
12
15
const RQKEY_ROOT = 'posts';
13
16
export const RQKEY = (cursor: string, did: string, rkey: string) => [RQKEY_ROOT, cursor, did, rkey];
14
17
15
-
export const useRecipesQuery = (cursor: string, did?: string) => {
18
+
export const useRecipesQuery = (cursor: string, did?: Did) => {
16
19
const rpc = useXrpc();
17
20
return useQuery({
18
21
queryKey: RQKEY(cursor, did ?? '', ''),
···
25
28
});
26
29
};
27
30
28
-
export const recipeQueryOptions = (rpc: XRPC, did: string, rkey: string) => {
31
+
export const recipeQueryOptions = (rpc: Client, did: Did, rkey: string) => {
29
32
return queryOptions({
30
33
queryKey: RQKEY('', did, rkey),
31
34
queryFn: async () => {
32
-
try {
33
-
const res = await rpc.get('blue.recipes.feed.getRecipe', {
35
+
const { ok, data } = await rpc.get('blue.recipes.feed.getRecipe', {
34
36
params: { did, rkey },
35
37
});
36
-
return res.data;
37
-
} catch (err) {
38
-
if (err instanceof XRPCError && err.kind && err.kind == 'not_found') {
39
-
throw notFound({ routeId: '/_' });
38
+
39
+
if (!ok) {
40
+
switch (data.error) {
41
+
case 'RecipeNotFound':
42
+
throw notFound({ routeId: '/_' });
43
+
default:
44
+
throw new Error(`Error fetching recipe: ${data.error}`);
40
45
}
41
-
throw err;
42
46
}
47
+
48
+
return data;
43
49
},
44
50
});
45
51
};
46
52
47
-
export const useRecipeQuery = (did: string, rkey: string) => {
53
+
export const useRecipeQuery = (did: Did, rkey: string) => {
48
54
const rpc = useXrpc();
49
55
return useQuery(recipeQueryOptions(rpc, did, rkey));
50
56
};
···
58
64
let recipeImg = null;
59
65
if (image) {
60
66
const imageFile = image.item(0) as File;
61
-
const res = await rpc.call('com.atproto.repo.uploadBlob', {
62
-
data: imageFile,
67
+
const { ok, data } = await rpc.post('com.atproto.repo.uploadBlob', {
68
+
input: imageFile,
63
69
});
64
-
recipeImg = res.data.blob
70
+
71
+
if (!ok) {
72
+
throw new Error(`Image upload failed: ${data.error}`);
73
+
}
74
+
75
+
recipeImg = data.blob;
65
76
}
66
77
67
78
const rkey = TID.nextStr();
68
-
const res = await rpc.call(`com.atproto.repo.createRecord`, {
69
-
data: {
70
-
repo: agent?.session.info.sub as `did:${string}`,
79
+
const { ok, data } = await rpc.post(`com.atproto.repo.createRecord`, {
80
+
input: {
81
+
repo: agent?.session.info.sub as ActorIdentifier,
71
82
record: {
72
83
...recipe,
73
84
image: recipeImg,
74
85
},
75
-
collection: RecipeCollection,
86
+
collection: 'blue.recipes.feed.recipe',
76
87
rkey: rkey,
77
-
},
88
+
}
78
89
});
90
+
91
+
if (!ok) {
92
+
throw new Error(`Recipe creation failed: ${data.error}`);
93
+
}
94
+
79
95
return {
80
96
rkey: rkey,
81
-
resp: res.data
97
+
resp: data,
82
98
};
83
99
},
84
100
onError: (error) => {
+2
-2
apps/web/src/state/auth.tsx
+2
-2
apps/web/src/state/auth.tsx
···
1
-
import { At } from "@atcute/client/lexicons";
1
+
import { Did } from "@atcute/lexicons";
2
2
import { finalizeAuthorization, getSession, OAuthUserAgent } from "@atcute/oauth-browser-client";
3
3
import { createContext, PropsWithChildren, useContext, useEffect, useState } from "react";
4
4
···
36
36
37
37
if (lastSignedIn) {
38
38
try {
39
-
return await getSession(lastSignedIn as At.DID);
39
+
return await getSession(lastSignedIn as Did);
40
40
} catch (err) {
41
41
localStorage.removeItem("lastSignedIn");
42
42
throw err;
+184
-11
bun.lock
+184
-11
bun.lock
···
10
10
"apps/api": {
11
11
"name": "@cookware/api",
12
12
"dependencies": {
13
-
"@atcute/client": "^2.0.6",
13
+
"@atcute/atproto": "^3.1.9",
14
+
"@atcute/client": "^4.0.5",
15
+
"@atcute/lexicons": "^1.2.3",
14
16
"@atcute/xrpc-server": "^0.1.3",
15
17
"@atcute/xrpc-server-cloudflare": "^0.1.0",
16
18
"@atproto/api": "^0.13.19",
···
35
37
"zod": "^3.23.8",
36
38
},
37
39
"devDependencies": {
38
-
"@atcute/bluesky": "^1.0.9",
40
+
"@atcute/bluesky": "^3.2.10",
39
41
"@cookware/tsconfig": "workspace:*",
40
42
"@swc/core": "^1.9.3",
41
43
"@types/ws": "^8.5.13",
···
46
48
"tsup": "^8.3.5",
47
49
"tsx": "^4.19.2",
48
50
"typescript": "^5.7.2",
51
+
"wrangler": "^4.50.0",
49
52
},
50
53
},
51
54
"apps/ingester": {
52
55
"name": "@cookware/ingester",
53
56
"dependencies": {
54
-
"@atcute/client": "^2.0.6",
57
+
"@atcute/client": "^4.0.5",
55
58
"@cookware/database": "workspace:^",
56
59
"@sentry/node": "^8.42.0",
57
60
"@skyware/jetstream": "^0.2.1",
···
78
81
"name": "@cookware/web",
79
82
"version": "0.0.0",
80
83
"dependencies": {
81
-
"@atcute/client": "^2.0.6",
84
+
"@atcute/atproto": "^3.1.9",
85
+
"@atcute/client": "^4.0.5",
86
+
"@atcute/lexicons": "^1.2.3",
82
87
"@atcute/oauth-browser-client": "^1.0.7",
83
88
"@atproto/common": "^0.4.5",
84
89
"@atproto/common-web": "^0.3.1",
···
179
184
180
185
"@atcute/atproto": ["@atcute/atproto@3.1.9", "", { "dependencies": { "@atcute/lexicons": "^1.2.2" } }, "sha512-DyWwHCTdR4hY2BPNbLXgVmm7lI+fceOwWbE4LXbGvbvVtSn+ejSVFaAv01Ra3kWDha0whsOmbJL8JP0QPpf1+w=="],
181
186
182
-
"@atcute/bluesky": ["@atcute/bluesky@1.0.15", "", { "peerDependencies": { "@atcute/client": "^1.0.0 || ^2.0.0" } }, "sha512-+EFiybmKQ97aBAgtaD+cKRJER5AMn3cZMkEwEg/pDdWyzxYJ9m1UgemmLdTgI8VrxPufKqdXS2nl7uO7TY6BPA=="],
187
+
"@atcute/bluesky": ["@atcute/bluesky@3.2.10", "", { "dependencies": { "@atcute/atproto": "^3.1.9", "@atcute/lexicons": "^1.2.2" } }, "sha512-qwQWTzRf3umnh2u41gdU+xWYkbzGlKDupc3zeOB+YjmuP1N9wEaUhwS8H7vgrqr0xC9SGNDjeUVcjC4m5BPLBg=="],
183
188
184
189
"@atcute/cbor": ["@atcute/cbor@2.2.7", "", { "dependencies": { "@atcute/cid": "^2.2.5", "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5" } }, "sha512-/mwAF0gnokOphceZqFq3uzMGdd8sbw5y6bxF8CRutRkCCUcpjjpJc5fkLwhxyGgOveF3mZuHE6p7t/+IAqb7Aw=="],
185
190
186
191
"@atcute/cid": ["@atcute/cid@2.2.6", "", { "dependencies": { "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5" } }, "sha512-bTAHHbJ24p+E//V4KCS4xdmd39o211jJswvqQOevj7vk+5IYcgDLx1ryZWZ1sEPOo9x875li/kj5gpKL14RDwQ=="],
187
192
188
-
"@atcute/client": ["@atcute/client@2.0.9", "", {}, "sha512-QNDm9gMP6x9LY77ArwY+urQOBtQW74/onEAz42c40JxRm6Rl9K9cU4ROvNKJ+5cpVmEm1sthEWVRmDr5CSZENA=="],
193
+
"@atcute/client": ["@atcute/client@4.0.5", "", { "dependencies": { "@atcute/identity": "^1.1.1", "@atcute/lexicons": "^1.2.2" } }, "sha512-R8Qen8goGmEkynYGg2m6XFlVmz0GTDvQ+9w+4QqOob+XMk8/WDpF4aImev7WKEde/rV2gjcqW7zM8E6W9NShDA=="],
189
194
190
195
"@atcute/crypto": ["@atcute/crypto@2.2.6", "", { "dependencies": { "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5", "@noble/secp256k1": "^3.0.0" } }, "sha512-vkuexF+kmrKE1/Uqzub99Qi4QpnxA2jbu60E6PTgL4XypELQ6rb59MB/J1VbY2gs0kd3ET7+L3+NWpKD5nXyfA=="],
191
196
···
327
332
328
333
"@cbor-extract/cbor-extract-win32-x64": ["@cbor-extract/cbor-extract-win32-x64@2.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w=="],
329
334
335
+
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
336
+
337
+
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.7.11", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20251106.1" }, "optionalPeers": ["workerd"] }, "sha512-se23f1D4PxKrMKOq+Stz+Yn7AJ9ITHcEecXo2Yjb+UgbUDCEBch1FXQC6hx6uT5fNA3kmX3mfzeZiUmpK1W9IQ=="],
338
+
339
+
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20251118.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-UmWmYEYS/LkK/4HFKN6xf3Hk8cw70PviR+ftr3hUvs9HYZS92IseZEp16pkL6ZBETrPRpZC7OrzoYF7ky6kHsg=="],
340
+
341
+
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20251118.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RockU7Qzf4rxNfY1lx3j4rvwutNLjTIX7rr2hogbQ4mzLo8Ea40/oZTzXVxl+on75joLBrt0YpenGW8o/r44QA=="],
342
+
343
+
"@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20251118.0", "", { "os": "linux", "cpu": "x64" }, "sha512-aT97GnOAbJDuuOG0zPVhgRk0xFtB1dzBMrxMZ09eubDLoU4djH4BuORaqvxNRMmHgKfa4T6drthckT0NjUvBdw=="],
344
+
345
+
"@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20251118.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-bXZPJcwlq00MPOXqP7DMWjr+goYj0+Fqyw6zgEC2M3FR1+SWla4yjghnZ4IdpN+H1t7VbUrsi5np2LzMUFs0NA=="],
346
+
347
+
"@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20251118.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2LV99AHSlpr8WcCb/BYbU2QsYkXLUL1izN6YKWkN9Eibv80JKX0RtgmD3dfmajE5sNvClavxZejgzVvHD9N9Ag=="],
348
+
330
349
"@cookware/api": ["@cookware/api@workspace:apps/api"],
331
350
332
351
"@cookware/database": ["@cookware/database@workspace:libs/database"],
···
352
371
"@dnd-kit/utilities": ["@dnd-kit/utilities@3.2.2", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg=="],
353
372
354
373
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
374
+
375
+
"@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],
355
376
356
377
"@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
357
378
···
447
468
448
469
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
449
470
471
+
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
472
+
473
+
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="],
474
+
475
+
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="],
476
+
477
+
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="],
478
+
479
+
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="],
480
+
481
+
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="],
482
+
483
+
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.0.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="],
484
+
485
+
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="],
486
+
487
+
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="],
488
+
489
+
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="],
490
+
491
+
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="],
492
+
493
+
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="],
494
+
495
+
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="],
496
+
497
+
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="],
498
+
499
+
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="],
500
+
501
+
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="],
502
+
503
+
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.33.5", "", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="],
504
+
505
+
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.33.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="],
506
+
507
+
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
508
+
450
509
"@ipld/dag-cbor": ["@ipld/dag-cbor@7.0.3", "", { "dependencies": { "cborg": "^1.6.0", "multiformats": "^9.5.4" } }, "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA=="],
451
510
452
511
"@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="],
···
575
634
576
635
"@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="],
577
636
637
+
"@poppinss/colors": ["@poppinss/colors@4.1.5", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw=="],
638
+
639
+
"@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="],
640
+
641
+
"@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="],
642
+
578
643
"@prisma/instrumentation": ["@prisma/instrumentation@5.22.0", "", { "dependencies": { "@opentelemetry/api": "^1.8", "@opentelemetry/instrumentation": "^0.49 || ^0.50 || ^0.51 || ^0.52.0 || ^0.53.0", "@opentelemetry/sdk-trace-base": "^1.22" } }, "sha512-LxccF392NN37ISGxIurUljZSh1YWnphO34V5a0+T7FVQG2u9bhAXRTJpgmQ3483woVhkraQZFF7cbRrpbw/F4Q=="],
579
644
580
645
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
···
699
764
700
765
"@sentry/opentelemetry": ["@sentry/opentelemetry@8.55.0", "", { "dependencies": { "@sentry/core": "8.55.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1", "@opentelemetry/core": "^1.30.1", "@opentelemetry/instrumentation": "^0.57.1", "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/semantic-conventions": "^1.28.0" } }, "sha512-UvatdmSr3Xf+4PLBzJNLZ2JjG1yAPWGe/VrJlJAqyTJ2gKeTzgXJJw8rp4pbvNZO8NaTGEYhhO+scLUj0UtLAQ=="],
701
766
767
+
"@sindresorhus/is": ["@sindresorhus/is@7.1.1", "", {}, "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ=="],
768
+
702
769
"@skyware/jetstream": ["@skyware/jetstream@0.2.5", "", { "dependencies": { "@atcute/atproto": "^3.1.0", "@atcute/bluesky": "^3.1.4", "@atcute/lexicons": "^1.1.0", "partysocket": "^1.1.3", "tiny-emitter": "^2.1.0" } }, "sha512-fM/zs03DLwqRyzZZJFWN20e76KrdqIp97Tlm8Cek+vxn96+tu5d/fx79V6H85L0QN6HvGiX2l9A8hWFqHvYlOA=="],
703
770
771
+
"@speed-highlight/core": ["@speed-highlight/core@1.2.12", "", {}, "sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA=="],
772
+
704
773
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
705
774
706
775
"@swc/core": ["@swc/core@1.15.3", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.3", "@swc/core-darwin-x64": "1.15.3", "@swc/core-linux-arm-gnueabihf": "1.15.3", "@swc/core-linux-arm64-gnu": "1.15.3", "@swc/core-linux-arm64-musl": "1.15.3", "@swc/core-linux-x64-gnu": "1.15.3", "@swc/core-linux-x64-musl": "1.15.3", "@swc/core-win32-arm64-msvc": "1.15.3", "@swc/core-win32-ia32-msvc": "1.15.3", "@swc/core-win32-x64-msvc": "1.15.3" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q=="],
···
865
934
866
935
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
867
936
937
+
"blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="],
938
+
868
939
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
869
940
870
941
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
···
909
980
910
981
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
911
982
983
+
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
984
+
912
985
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
913
986
914
987
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
915
988
989
+
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
990
+
916
991
"colord": ["colord@2.9.3", "", {}, "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="],
917
992
918
993
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
···
928
1003
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
929
1004
930
1005
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
1006
+
1007
+
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
931
1008
932
1009
"cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="],
933
1010
···
995
1072
996
1073
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
997
1074
1075
+
"error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="],
1076
+
998
1077
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
999
1078
1000
1079
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
···
1041
1120
1042
1121
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
1043
1122
1123
+
"exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="],
1124
+
1044
1125
"fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="],
1045
1126
1046
1127
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
···
1100
1181
"glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="],
1101
1182
1102
1183
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
1184
+
1185
+
"glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
1103
1186
1104
1187
"globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="],
1105
1188
···
1137
1220
1138
1221
"iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
1139
1222
1223
+
"is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="],
1224
+
1140
1225
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
1141
1226
1142
1227
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
···
1177
1262
1178
1263
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
1179
1264
1265
+
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
1266
+
1180
1267
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
1181
1268
1182
1269
"libsql": ["libsql@0.4.7", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.4.7", "@libsql/darwin-x64": "0.4.7", "@libsql/linux-arm64-gnu": "0.4.7", "@libsql/linux-arm64-musl": "0.4.7", "@libsql/linux-x64-gnu": "0.4.7", "@libsql/linux-x64-musl": "0.4.7", "@libsql/win32-x64-msvc": "0.4.7" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ] }, "sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw=="],
···
1211
1298
1212
1299
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
1213
1300
1301
+
"mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
1302
+
1214
1303
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
1215
1304
1216
1305
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
1306
+
1307
+
"miniflare": ["miniflare@4.20251118.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251118.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-uLSAE/DvOm392fiaig4LOaatxLjM7xzIniFRG5Y3yF9IduOYLLK/pkCPQNCgKQH3ou0YJRHnTN+09LPfqYNTQQ=="],
1217
1308
1218
1309
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
1219
1310
···
1278
1369
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
1279
1370
1280
1371
"path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="],
1372
+
1373
+
"path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="],
1281
1374
1282
1375
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
1283
1376
···
1455
1548
1456
1549
"seroval-plugins": ["seroval-plugins@1.4.0", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ=="],
1457
1550
1551
+
"sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
1552
+
1458
1553
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
1459
1554
1460
1555
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
1461
1556
1462
1557
"shimmer": ["shimmer@1.2.1", "", {}, "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="],
1558
+
1559
+
"simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="],
1463
1560
1464
1561
"solid-js": ["solid-js@1.9.10", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew=="],
1465
1562
···
1472
1569
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
1473
1570
1474
1571
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
1572
+
1573
+
"stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="],
1475
1574
1476
1575
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
1477
1576
···
1551
1650
1552
1651
"uint8arrays": ["uint8arrays@5.1.0", "", { "dependencies": { "multiformats": "^13.0.0" } }, "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww=="],
1553
1652
1554
-
"undici": ["undici@6.22.0", "", {}, "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw=="],
1653
+
"undici": ["undici@7.14.0", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="],
1555
1654
1556
1655
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
1656
+
1657
+
"unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="],
1557
1658
1558
1659
"unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
1559
1660
···
1581
1682
1582
1683
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
1583
1684
1685
+
"workerd": ["workerd@1.20251118.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251118.0", "@cloudflare/workerd-darwin-arm64": "1.20251118.0", "@cloudflare/workerd-linux-64": "1.20251118.0", "@cloudflare/workerd-linux-arm64": "1.20251118.0", "@cloudflare/workerd-windows-64": "1.20251118.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-Om5ns0Lyx/LKtYI04IV0bjIrkBgoFNg0p6urzr2asekJlfP18RqFzyqMFZKf0i9Gnjtz/JfAS/Ol6tjCe5JJsQ=="],
1686
+
1687
+
"wrangler": ["wrangler@4.50.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.11", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20251118.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20251118.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251118.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-+nuZuHZxDdKmAyXOSrHlciGshCoAPiy5dM+t6mEohWm7HpXvTHmWQGUf/na9jjWlWJHCJYOWzkA1P5HBJqrIEA=="],
1688
+
1584
1689
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
1585
1690
1586
1691
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
···
1592
1697
"yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="],
1593
1698
1594
1699
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
1700
+
1701
+
"youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="],
1702
+
1703
+
"youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="],
1595
1704
1596
1705
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
1597
1706
1598
-
"@atcute/oauth-browser-client/@atcute/client": ["@atcute/client@4.0.5", "", { "dependencies": { "@atcute/identity": "^1.1.1", "@atcute/lexicons": "^1.2.2" } }, "sha512-R8Qen8goGmEkynYGg2m6XFlVmz0GTDvQ+9w+4QqOob+XMk8/WDpF4aImev7WKEde/rV2gjcqW7zM8E6W9NShDA=="],
1707
+
"@atproto-labs/fetch-node/undici": ["undici@6.22.0", "", {}, "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw=="],
1599
1708
1600
1709
"@atproto-labs/identity-resolver/@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="],
1601
1710
···
1639
1748
1640
1749
"@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
1641
1750
1642
-
"@cookware/lexicons/@atcute/client": ["@atcute/client@4.0.5", "", { "dependencies": { "@atcute/identity": "^1.1.1", "@atcute/lexicons": "^1.2.2" } }, "sha512-R8Qen8goGmEkynYGg2m6XFlVmz0GTDvQ+9w+4QqOob+XMk8/WDpF4aImev7WKEde/rV2gjcqW7zM8E6W9NShDA=="],
1751
+
"@cookware/web/@atcute/bluesky": ["@atcute/bluesky@1.0.15", "", { "peerDependencies": { "@atcute/client": "^1.0.0 || ^2.0.0" } }, "sha512-+EFiybmKQ97aBAgtaD+cKRJER5AMn3cZMkEwEg/pDdWyzxYJ9m1UgemmLdTgI8VrxPufKqdXS2nl7uO7TY6BPA=="],
1643
1752
1644
1753
"@cookware/web/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
1645
1754
···
1666
1775
"@opentelemetry/resources/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
1667
1776
1668
1777
"@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
1778
+
1779
+
"@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="],
1669
1780
1670
1781
"@prisma/instrumentation/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.53.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.53.0", "@types/shimmer": "^1.2.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1", "semver": "^7.5.2", "shimmer": "^1.2.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A=="],
1671
1782
···
1719
1830
1720
1831
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
1721
1832
1722
-
"@skyware/jetstream/@atcute/bluesky": ["@atcute/bluesky@3.2.10", "", { "dependencies": { "@atcute/atproto": "^3.1.9", "@atcute/lexicons": "^1.2.2" } }, "sha512-qwQWTzRf3umnh2u41gdU+xWYkbzGlKDupc3zeOB+YjmuP1N9wEaUhwS8H7vgrqr0xC9SGNDjeUVcjC4m5BPLBg=="],
1723
-
1724
1833
"@tanstack/react-router-devtools/vite": ["vite@7.2.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w=="],
1725
1834
1726
1835
"@tanstack/router-devtools/vite": ["vite@7.2.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w=="],
···
1747
1856
1748
1857
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
1749
1858
1859
+
"miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
1860
+
1861
+
"miniflare/acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="],
1862
+
1863
+
"miniflare/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
1864
+
1865
+
"miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
1866
+
1750
1867
"postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
1751
1868
1752
1869
"postcss-calc/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
···
1761
1878
1762
1879
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
1763
1880
1881
+
"sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
1882
+
1764
1883
"solid-js/seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="],
1765
1884
1766
1885
"solid-js/seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="],
···
1783
1902
1784
1903
"vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
1785
1904
1905
+
"wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
1906
+
1786
1907
"@atproto/api/@atproto/common-web/uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="],
1787
1908
1788
1909
"@atproto/common/@atproto/common-web/uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="],
···
1798
1919
"@atproto/common/pino/thread-stream": ["thread-stream@2.7.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw=="],
1799
1920
1800
1921
"@atproto/lexicon/@atproto/common-web/uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="],
1922
+
1923
+
"@cookware/web/@atcute/bluesky/@atcute/client": ["@atcute/client@2.0.9", "", {}, "sha512-QNDm9gMP6x9LY77ArwY+urQOBtQW74/onEAz42c40JxRm6Rl9K9cU4ROvNKJ+5cpVmEm1sthEWVRmDr5CSZENA=="],
1801
1924
1802
1925
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
1803
1926
···
2032
2155
"vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
2033
2156
2034
2157
"vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
2158
+
2159
+
"wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
2160
+
2161
+
"wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="],
2162
+
2163
+
"wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="],
2164
+
2165
+
"wrangler/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="],
2166
+
2167
+
"wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="],
2168
+
2169
+
"wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="],
2170
+
2171
+
"wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="],
2172
+
2173
+
"wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="],
2174
+
2175
+
"wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="],
2176
+
2177
+
"wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="],
2178
+
2179
+
"wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="],
2180
+
2181
+
"wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="],
2182
+
2183
+
"wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="],
2184
+
2185
+
"wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="],
2186
+
2187
+
"wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="],
2188
+
2189
+
"wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="],
2190
+
2191
+
"wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="],
2192
+
2193
+
"wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="],
2194
+
2195
+
"wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="],
2196
+
2197
+
"wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="],
2198
+
2199
+
"wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="],
2200
+
2201
+
"wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="],
2202
+
2203
+
"wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="],
2204
+
2205
+
"wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="],
2206
+
2207
+
"wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="],
2035
2208
2036
2209
"@tanstack/react-router-devtools/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
2037
2210
+3
-3
config/dev/caddy/Caddyfile
+3
-3
config/dev/caddy/Caddyfile
···
11
11
12
12
api.local.recipes.blue {
13
13
import tls_config
14
-
reverse_proxy http://host.docker.internal:8080
14
+
reverse_proxy http://host.docker.internal:8787
15
15
}
16
16
17
17
local.recipes.blue {
···
20
20
21
21
handle_path /xrpc/* {
22
22
rewrite * /xrpc{uri}
23
-
reverse_proxy http://host.docker.internal:8080
23
+
reverse_proxy http://host.docker.internal:8787
24
24
}
25
25
handle_path /api/* {
26
26
rewrite * /api{uri}
27
-
reverse_proxy http://host.docker.internal:8080
27
+
reverse_proxy http://host.docker.internal:8787
28
28
}
29
29
}
30
30
+1
-3
libs/database/drizzle.config.ts
+1
-3
libs/database/drizzle.config.ts
+3
libs/database/migrations/0000_boring_tenebrous.sql
libs/database/migrations/0000_fantastic_magma.sql
+3
libs/database/migrations/0000_boring_tenebrous.sql
libs/database/migrations/0000_fantastic_magma.sql
-1
libs/database/migrations/0001_icy_killmonger.sql
-1
libs/database/migrations/0001_icy_killmonger.sql
···
1
-
ALTER TABLE `recipes` ADD `time` integer DEFAULT 0 NOT NULL;
-5
libs/database/migrations/0002_redundant_wither.sql
-5
libs/database/migrations/0002_redundant_wither.sql
···
1
-
DROP INDEX IF EXISTS "recipes_id_unique";--> statement-breakpoint
2
-
DROP INDEX IF EXISTS "recipes_rkey_author_did_unique";--> statement-breakpoint
3
-
ALTER TABLE `recipes` ALTER COLUMN "title" TO "title" text;--> statement-breakpoint
4
-
CREATE UNIQUE INDEX `recipes_id_unique` ON `recipes` (`id`);--> statement-breakpoint
5
-
CREATE UNIQUE INDEX `recipes_rkey_author_did_unique` ON `recipes` (`rkey`,`author_did`);
-6
libs/database/migrations/0003_fixed_peter_parker.sql
-6
libs/database/migrations/0003_fixed_peter_parker.sql
···
1
-
DROP INDEX IF EXISTS "recipes_id_unique";--> statement-breakpoint
2
-
DROP INDEX IF EXISTS "recipes_rkey_author_did_unique";--> statement-breakpoint
3
-
ALTER TABLE `recipes` ALTER COLUMN "title" TO "title" text NOT NULL;--> statement-breakpoint
4
-
CREATE UNIQUE INDEX `recipes_id_unique` ON `recipes` (`id`);--> statement-breakpoint
5
-
CREATE UNIQUE INDEX `recipes_rkey_author_did_unique` ON `recipes` (`rkey`,`author_did`);--> statement-breakpoint
6
-
ALTER TABLE `recipes` ADD `image_ref` text;
-1
libs/database/migrations/0004_left_sersi.sql
-1
libs/database/migrations/0004_left_sersi.sql
···
1
-
ALTER TABLE `recipes` ADD `serves` integer;
+23
-1
libs/database/migrations/meta/0000_snapshot.json
+23
-1
libs/database/migrations/meta/0000_snapshot.json
···
1
1
{
2
2
"version": "6",
3
3
"dialect": "sqlite",
4
-
"id": "1c01d686-877c-426c-ac8a-31f47df9385d",
4
+
"id": "2d4a90ff-be48-461c-8876-50c11cb2b91d",
5
5
"prevId": "00000000-0000-0000-0000-000000000000",
6
6
"tables": {
7
7
"auth_session": {
···
74
74
"type": "text",
75
75
"primaryKey": false,
76
76
"notNull": true,
77
+
"autoincrement": false
78
+
},
79
+
"image_ref": {
80
+
"name": "image_ref",
81
+
"type": "text",
82
+
"primaryKey": false,
83
+
"notNull": false,
84
+
"autoincrement": false
85
+
},
86
+
"time": {
87
+
"name": "time",
88
+
"type": "integer",
89
+
"primaryKey": false,
90
+
"notNull": true,
91
+
"autoincrement": false,
92
+
"default": 0
93
+
},
94
+
"serves": {
95
+
"name": "serves",
96
+
"type": "integer",
97
+
"primaryKey": false,
98
+
"notNull": false,
77
99
"autoincrement": false
78
100
},
79
101
"description": {
-156
libs/database/migrations/meta/0001_snapshot.json
-156
libs/database/migrations/meta/0001_snapshot.json
···
1
-
{
2
-
"version": "6",
3
-
"dialect": "sqlite",
4
-
"id": "2c6fca6c-38c3-4482-b189-6defabb5f8c8",
5
-
"prevId": "1c01d686-877c-426c-ac8a-31f47df9385d",
6
-
"tables": {
7
-
"auth_session": {
8
-
"name": "auth_session",
9
-
"columns": {
10
-
"key": {
11
-
"name": "key",
12
-
"type": "text",
13
-
"primaryKey": true,
14
-
"notNull": true,
15
-
"autoincrement": false
16
-
},
17
-
"session": {
18
-
"name": "session",
19
-
"type": "text",
20
-
"primaryKey": false,
21
-
"notNull": true,
22
-
"autoincrement": false
23
-
}
24
-
},
25
-
"indexes": {},
26
-
"foreignKeys": {},
27
-
"compositePrimaryKeys": {},
28
-
"uniqueConstraints": {},
29
-
"checkConstraints": {}
30
-
},
31
-
"auth_state": {
32
-
"name": "auth_state",
33
-
"columns": {
34
-
"key": {
35
-
"name": "key",
36
-
"type": "text",
37
-
"primaryKey": true,
38
-
"notNull": true,
39
-
"autoincrement": false
40
-
},
41
-
"state": {
42
-
"name": "state",
43
-
"type": "text",
44
-
"primaryKey": false,
45
-
"notNull": true,
46
-
"autoincrement": false
47
-
}
48
-
},
49
-
"indexes": {},
50
-
"foreignKeys": {},
51
-
"compositePrimaryKeys": {},
52
-
"uniqueConstraints": {},
53
-
"checkConstraints": {}
54
-
},
55
-
"recipes": {
56
-
"name": "recipes",
57
-
"columns": {
58
-
"id": {
59
-
"name": "id",
60
-
"type": "integer",
61
-
"primaryKey": true,
62
-
"notNull": true,
63
-
"autoincrement": false
64
-
},
65
-
"rkey": {
66
-
"name": "rkey",
67
-
"type": "text",
68
-
"primaryKey": false,
69
-
"notNull": true,
70
-
"autoincrement": false
71
-
},
72
-
"title": {
73
-
"name": "title",
74
-
"type": "text",
75
-
"primaryKey": false,
76
-
"notNull": true,
77
-
"autoincrement": false
78
-
},
79
-
"time": {
80
-
"name": "time",
81
-
"type": "integer",
82
-
"primaryKey": false,
83
-
"notNull": true,
84
-
"autoincrement": false,
85
-
"default": 0
86
-
},
87
-
"description": {
88
-
"name": "description",
89
-
"type": "text",
90
-
"primaryKey": false,
91
-
"notNull": false,
92
-
"autoincrement": false
93
-
},
94
-
"ingredients": {
95
-
"name": "ingredients",
96
-
"type": "text",
97
-
"primaryKey": false,
98
-
"notNull": true,
99
-
"autoincrement": false
100
-
},
101
-
"steps": {
102
-
"name": "steps",
103
-
"type": "text",
104
-
"primaryKey": false,
105
-
"notNull": true,
106
-
"autoincrement": false
107
-
},
108
-
"created_at": {
109
-
"name": "created_at",
110
-
"type": "text",
111
-
"primaryKey": false,
112
-
"notNull": true,
113
-
"autoincrement": false
114
-
},
115
-
"author_did": {
116
-
"name": "author_did",
117
-
"type": "text",
118
-
"primaryKey": false,
119
-
"notNull": true,
120
-
"autoincrement": false
121
-
}
122
-
},
123
-
"indexes": {
124
-
"recipes_id_unique": {
125
-
"name": "recipes_id_unique",
126
-
"columns": [
127
-
"id"
128
-
],
129
-
"isUnique": true
130
-
},
131
-
"recipes_rkey_author_did_unique": {
132
-
"name": "recipes_rkey_author_did_unique",
133
-
"columns": [
134
-
"rkey",
135
-
"author_did"
136
-
],
137
-
"isUnique": true
138
-
}
139
-
},
140
-
"foreignKeys": {},
141
-
"compositePrimaryKeys": {},
142
-
"uniqueConstraints": {},
143
-
"checkConstraints": {}
144
-
}
145
-
},
146
-
"views": {},
147
-
"enums": {},
148
-
"_meta": {
149
-
"schemas": {},
150
-
"tables": {},
151
-
"columns": {}
152
-
},
153
-
"internal": {
154
-
"indexes": {}
155
-
}
156
-
}
-156
libs/database/migrations/meta/0002_snapshot.json
-156
libs/database/migrations/meta/0002_snapshot.json
···
1
-
{
2
-
"version": "6",
3
-
"dialect": "sqlite",
4
-
"id": "5e0d9054-f192-4db9-8afe-afcabe08e661",
5
-
"prevId": "2c6fca6c-38c3-4482-b189-6defabb5f8c8",
6
-
"tables": {
7
-
"auth_session": {
8
-
"name": "auth_session",
9
-
"columns": {
10
-
"key": {
11
-
"name": "key",
12
-
"type": "text",
13
-
"primaryKey": true,
14
-
"notNull": true,
15
-
"autoincrement": false
16
-
},
17
-
"session": {
18
-
"name": "session",
19
-
"type": "text",
20
-
"primaryKey": false,
21
-
"notNull": true,
22
-
"autoincrement": false
23
-
}
24
-
},
25
-
"indexes": {},
26
-
"foreignKeys": {},
27
-
"compositePrimaryKeys": {},
28
-
"uniqueConstraints": {},
29
-
"checkConstraints": {}
30
-
},
31
-
"auth_state": {
32
-
"name": "auth_state",
33
-
"columns": {
34
-
"key": {
35
-
"name": "key",
36
-
"type": "text",
37
-
"primaryKey": true,
38
-
"notNull": true,
39
-
"autoincrement": false
40
-
},
41
-
"state": {
42
-
"name": "state",
43
-
"type": "text",
44
-
"primaryKey": false,
45
-
"notNull": true,
46
-
"autoincrement": false
47
-
}
48
-
},
49
-
"indexes": {},
50
-
"foreignKeys": {},
51
-
"compositePrimaryKeys": {},
52
-
"uniqueConstraints": {},
53
-
"checkConstraints": {}
54
-
},
55
-
"recipes": {
56
-
"name": "recipes",
57
-
"columns": {
58
-
"id": {
59
-
"name": "id",
60
-
"type": "integer",
61
-
"primaryKey": true,
62
-
"notNull": true,
63
-
"autoincrement": false
64
-
},
65
-
"rkey": {
66
-
"name": "rkey",
67
-
"type": "text",
68
-
"primaryKey": false,
69
-
"notNull": true,
70
-
"autoincrement": false
71
-
},
72
-
"title": {
73
-
"name": "title",
74
-
"type": "text",
75
-
"primaryKey": false,
76
-
"notNull": false,
77
-
"autoincrement": false
78
-
},
79
-
"time": {
80
-
"name": "time",
81
-
"type": "integer",
82
-
"primaryKey": false,
83
-
"notNull": true,
84
-
"autoincrement": false,
85
-
"default": 0
86
-
},
87
-
"description": {
88
-
"name": "description",
89
-
"type": "text",
90
-
"primaryKey": false,
91
-
"notNull": false,
92
-
"autoincrement": false
93
-
},
94
-
"ingredients": {
95
-
"name": "ingredients",
96
-
"type": "text",
97
-
"primaryKey": false,
98
-
"notNull": true,
99
-
"autoincrement": false
100
-
},
101
-
"steps": {
102
-
"name": "steps",
103
-
"type": "text",
104
-
"primaryKey": false,
105
-
"notNull": true,
106
-
"autoincrement": false
107
-
},
108
-
"created_at": {
109
-
"name": "created_at",
110
-
"type": "text",
111
-
"primaryKey": false,
112
-
"notNull": true,
113
-
"autoincrement": false
114
-
},
115
-
"author_did": {
116
-
"name": "author_did",
117
-
"type": "text",
118
-
"primaryKey": false,
119
-
"notNull": true,
120
-
"autoincrement": false
121
-
}
122
-
},
123
-
"indexes": {
124
-
"recipes_id_unique": {
125
-
"name": "recipes_id_unique",
126
-
"columns": [
127
-
"id"
128
-
],
129
-
"isUnique": true
130
-
},
131
-
"recipes_rkey_author_did_unique": {
132
-
"name": "recipes_rkey_author_did_unique",
133
-
"columns": [
134
-
"rkey",
135
-
"author_did"
136
-
],
137
-
"isUnique": true
138
-
}
139
-
},
140
-
"foreignKeys": {},
141
-
"compositePrimaryKeys": {},
142
-
"uniqueConstraints": {},
143
-
"checkConstraints": {}
144
-
}
145
-
},
146
-
"views": {},
147
-
"enums": {},
148
-
"_meta": {
149
-
"schemas": {},
150
-
"tables": {},
151
-
"columns": {}
152
-
},
153
-
"internal": {
154
-
"indexes": {}
155
-
}
156
-
}
-163
libs/database/migrations/meta/0003_snapshot.json
-163
libs/database/migrations/meta/0003_snapshot.json
···
1
-
{
2
-
"version": "6",
3
-
"dialect": "sqlite",
4
-
"id": "fa77a98d-2ae1-49d5-ab93-81492dcbdebd",
5
-
"prevId": "5e0d9054-f192-4db9-8afe-afcabe08e661",
6
-
"tables": {
7
-
"auth_session": {
8
-
"name": "auth_session",
9
-
"columns": {
10
-
"key": {
11
-
"name": "key",
12
-
"type": "text",
13
-
"primaryKey": true,
14
-
"notNull": true,
15
-
"autoincrement": false
16
-
},
17
-
"session": {
18
-
"name": "session",
19
-
"type": "text",
20
-
"primaryKey": false,
21
-
"notNull": true,
22
-
"autoincrement": false
23
-
}
24
-
},
25
-
"indexes": {},
26
-
"foreignKeys": {},
27
-
"compositePrimaryKeys": {},
28
-
"uniqueConstraints": {},
29
-
"checkConstraints": {}
30
-
},
31
-
"auth_state": {
32
-
"name": "auth_state",
33
-
"columns": {
34
-
"key": {
35
-
"name": "key",
36
-
"type": "text",
37
-
"primaryKey": true,
38
-
"notNull": true,
39
-
"autoincrement": false
40
-
},
41
-
"state": {
42
-
"name": "state",
43
-
"type": "text",
44
-
"primaryKey": false,
45
-
"notNull": true,
46
-
"autoincrement": false
47
-
}
48
-
},
49
-
"indexes": {},
50
-
"foreignKeys": {},
51
-
"compositePrimaryKeys": {},
52
-
"uniqueConstraints": {},
53
-
"checkConstraints": {}
54
-
},
55
-
"recipes": {
56
-
"name": "recipes",
57
-
"columns": {
58
-
"id": {
59
-
"name": "id",
60
-
"type": "integer",
61
-
"primaryKey": true,
62
-
"notNull": true,
63
-
"autoincrement": false
64
-
},
65
-
"rkey": {
66
-
"name": "rkey",
67
-
"type": "text",
68
-
"primaryKey": false,
69
-
"notNull": true,
70
-
"autoincrement": false
71
-
},
72
-
"title": {
73
-
"name": "title",
74
-
"type": "text",
75
-
"primaryKey": false,
76
-
"notNull": true,
77
-
"autoincrement": false
78
-
},
79
-
"image_ref": {
80
-
"name": "image_ref",
81
-
"type": "text",
82
-
"primaryKey": false,
83
-
"notNull": false,
84
-
"autoincrement": false
85
-
},
86
-
"time": {
87
-
"name": "time",
88
-
"type": "integer",
89
-
"primaryKey": false,
90
-
"notNull": true,
91
-
"autoincrement": false,
92
-
"default": 0
93
-
},
94
-
"description": {
95
-
"name": "description",
96
-
"type": "text",
97
-
"primaryKey": false,
98
-
"notNull": false,
99
-
"autoincrement": false
100
-
},
101
-
"ingredients": {
102
-
"name": "ingredients",
103
-
"type": "text",
104
-
"primaryKey": false,
105
-
"notNull": true,
106
-
"autoincrement": false
107
-
},
108
-
"steps": {
109
-
"name": "steps",
110
-
"type": "text",
111
-
"primaryKey": false,
112
-
"notNull": true,
113
-
"autoincrement": false
114
-
},
115
-
"created_at": {
116
-
"name": "created_at",
117
-
"type": "text",
118
-
"primaryKey": false,
119
-
"notNull": true,
120
-
"autoincrement": false
121
-
},
122
-
"author_did": {
123
-
"name": "author_did",
124
-
"type": "text",
125
-
"primaryKey": false,
126
-
"notNull": true,
127
-
"autoincrement": false
128
-
}
129
-
},
130
-
"indexes": {
131
-
"recipes_id_unique": {
132
-
"name": "recipes_id_unique",
133
-
"columns": [
134
-
"id"
135
-
],
136
-
"isUnique": true
137
-
},
138
-
"recipes_rkey_author_did_unique": {
139
-
"name": "recipes_rkey_author_did_unique",
140
-
"columns": [
141
-
"rkey",
142
-
"author_did"
143
-
],
144
-
"isUnique": true
145
-
}
146
-
},
147
-
"foreignKeys": {},
148
-
"compositePrimaryKeys": {},
149
-
"uniqueConstraints": {},
150
-
"checkConstraints": {}
151
-
}
152
-
},
153
-
"views": {},
154
-
"enums": {},
155
-
"_meta": {
156
-
"schemas": {},
157
-
"tables": {},
158
-
"columns": {}
159
-
},
160
-
"internal": {
161
-
"indexes": {}
162
-
}
163
-
}
-170
libs/database/migrations/meta/0004_snapshot.json
-170
libs/database/migrations/meta/0004_snapshot.json
···
1
-
{
2
-
"version": "6",
3
-
"dialect": "sqlite",
4
-
"id": "d6e34451-dba5-4458-8471-ac988decffec",
5
-
"prevId": "fa77a98d-2ae1-49d5-ab93-81492dcbdebd",
6
-
"tables": {
7
-
"auth_session": {
8
-
"name": "auth_session",
9
-
"columns": {
10
-
"key": {
11
-
"name": "key",
12
-
"type": "text",
13
-
"primaryKey": true,
14
-
"notNull": true,
15
-
"autoincrement": false
16
-
},
17
-
"session": {
18
-
"name": "session",
19
-
"type": "text",
20
-
"primaryKey": false,
21
-
"notNull": true,
22
-
"autoincrement": false
23
-
}
24
-
},
25
-
"indexes": {},
26
-
"foreignKeys": {},
27
-
"compositePrimaryKeys": {},
28
-
"uniqueConstraints": {},
29
-
"checkConstraints": {}
30
-
},
31
-
"auth_state": {
32
-
"name": "auth_state",
33
-
"columns": {
34
-
"key": {
35
-
"name": "key",
36
-
"type": "text",
37
-
"primaryKey": true,
38
-
"notNull": true,
39
-
"autoincrement": false
40
-
},
41
-
"state": {
42
-
"name": "state",
43
-
"type": "text",
44
-
"primaryKey": false,
45
-
"notNull": true,
46
-
"autoincrement": false
47
-
}
48
-
},
49
-
"indexes": {},
50
-
"foreignKeys": {},
51
-
"compositePrimaryKeys": {},
52
-
"uniqueConstraints": {},
53
-
"checkConstraints": {}
54
-
},
55
-
"recipes": {
56
-
"name": "recipes",
57
-
"columns": {
58
-
"id": {
59
-
"name": "id",
60
-
"type": "integer",
61
-
"primaryKey": true,
62
-
"notNull": true,
63
-
"autoincrement": false
64
-
},
65
-
"rkey": {
66
-
"name": "rkey",
67
-
"type": "text",
68
-
"primaryKey": false,
69
-
"notNull": true,
70
-
"autoincrement": false
71
-
},
72
-
"title": {
73
-
"name": "title",
74
-
"type": "text",
75
-
"primaryKey": false,
76
-
"notNull": true,
77
-
"autoincrement": false
78
-
},
79
-
"image_ref": {
80
-
"name": "image_ref",
81
-
"type": "text",
82
-
"primaryKey": false,
83
-
"notNull": false,
84
-
"autoincrement": false
85
-
},
86
-
"time": {
87
-
"name": "time",
88
-
"type": "integer",
89
-
"primaryKey": false,
90
-
"notNull": true,
91
-
"autoincrement": false,
92
-
"default": 0
93
-
},
94
-
"serves": {
95
-
"name": "serves",
96
-
"type": "integer",
97
-
"primaryKey": false,
98
-
"notNull": false,
99
-
"autoincrement": false
100
-
},
101
-
"description": {
102
-
"name": "description",
103
-
"type": "text",
104
-
"primaryKey": false,
105
-
"notNull": false,
106
-
"autoincrement": false
107
-
},
108
-
"ingredients": {
109
-
"name": "ingredients",
110
-
"type": "text",
111
-
"primaryKey": false,
112
-
"notNull": true,
113
-
"autoincrement": false
114
-
},
115
-
"steps": {
116
-
"name": "steps",
117
-
"type": "text",
118
-
"primaryKey": false,
119
-
"notNull": true,
120
-
"autoincrement": false
121
-
},
122
-
"created_at": {
123
-
"name": "created_at",
124
-
"type": "text",
125
-
"primaryKey": false,
126
-
"notNull": true,
127
-
"autoincrement": false
128
-
},
129
-
"author_did": {
130
-
"name": "author_did",
131
-
"type": "text",
132
-
"primaryKey": false,
133
-
"notNull": true,
134
-
"autoincrement": false
135
-
}
136
-
},
137
-
"indexes": {
138
-
"recipes_id_unique": {
139
-
"name": "recipes_id_unique",
140
-
"columns": [
141
-
"id"
142
-
],
143
-
"isUnique": true
144
-
},
145
-
"recipes_rkey_author_did_unique": {
146
-
"name": "recipes_rkey_author_did_unique",
147
-
"columns": [
148
-
"rkey",
149
-
"author_did"
150
-
],
151
-
"isUnique": true
152
-
}
153
-
},
154
-
"foreignKeys": {},
155
-
"compositePrimaryKeys": {},
156
-
"uniqueConstraints": {},
157
-
"checkConstraints": {}
158
-
}
159
-
},
160
-
"views": {},
161
-
"enums": {},
162
-
"_meta": {
163
-
"schemas": {},
164
-
"tables": {},
165
-
"columns": {}
166
-
},
167
-
"internal": {
168
-
"indexes": {}
169
-
}
170
-
}
+2
-30
libs/database/migrations/meta/_journal.json
+2
-30
libs/database/migrations/meta/_journal.json
···
5
5
{
6
6
"idx": 0,
7
7
"version": "6",
8
-
"when": 1733683012154,
9
-
"tag": "0000_boring_tenebrous",
10
-
"breakpoints": true
11
-
},
12
-
{
13
-
"idx": 1,
14
-
"version": "6",
15
-
"when": 1734630004978,
16
-
"tag": "0001_icy_killmonger",
17
-
"breakpoints": true
18
-
},
19
-
{
20
-
"idx": 2,
21
-
"version": "6",
22
-
"when": 1734642833768,
23
-
"tag": "0002_redundant_wither",
24
-
"breakpoints": true
25
-
},
26
-
{
27
-
"idx": 3,
28
-
"version": "6",
29
-
"when": 1734643156502,
30
-
"tag": "0003_fixed_peter_parker",
31
-
"breakpoints": true
32
-
},
33
-
{
34
-
"idx": 4,
35
-
"version": "6",
36
-
"when": 1735493787990,
37
-
"tag": "0004_left_sersi",
8
+
"when": 1763864322315,
9
+
"tag": "0000_fantastic_magma",
38
10
"breakpoints": true
39
11
}
40
12
]
-15
libs/database/src/config.ts
-15
libs/database/src/config.ts
···
1
-
import { z } from "zod";
2
-
3
-
const envSchema = z.object({
4
-
ENV: z
5
-
.union([
6
-
z.literal('development'),
7
-
z.literal('production'),
8
-
])
9
-
.default('development'),
10
-
});
11
-
12
-
const env = envSchema.parse(process.env);
13
-
14
-
export default env;
15
-
export type Env = z.infer<typeof envSchema>;
-4
libs/database/src/database.ts
-4
libs/database/src/database.ts
-1
libs/database/src/index.ts
-1
libs/database/src/index.ts
+5
-6
libs/database/src/schema.ts
+5
-6
libs/database/src/schema.ts
···
1
1
import { customType, int, sqliteTable, text, unique } from "drizzle-orm/sqlite-core";
2
-
import { DID } from "@cookware/lexicons";
3
-
import { Ingredient, Step } from "@cookware/lexicons";
4
-
import { NodeSavedSession, NodeSavedState } from "@atproto/oauth-client-node";
2
+
import { BlueRecipesFeedRecipe } from "@cookware/lexicons";
3
+
import { Did, NodeSavedSession, NodeSavedState } from "@atproto/oauth-client-node";
5
4
6
-
const did = customType<{ data: DID }>({
5
+
const did = customType<{ data: Did }>({
7
6
dataType() {
8
7
return "text";
9
8
},
···
25
24
time: int('time').notNull().default(0),
26
25
serves: int('serves'),
27
26
description: text('description'),
28
-
ingredients: text('ingredients', { mode: 'json' }).$type<Partial<Ingredient>[]>().notNull(),
29
-
steps: text('steps', { mode: 'json' }).$type<Partial<Step>[]>().notNull(),
27
+
ingredients: text('ingredients', { mode: 'json' }).$type<BlueRecipesFeedRecipe.Main['ingredients']>().notNull(),
28
+
steps: text('steps', { mode: 'json' }).$type<BlueRecipesFeedRecipe.Main['steps']>().notNull(),
30
29
createdAt: dateIsoText("created_at").notNull(),
31
30
authorDid: did("author_did").notNull(),
32
31
}, t => ({
+8
-7
libs/lexicons/src/did.ts
+8
-7
libs/lexicons/src/did.ts
···
1
+
import { Did } from "@atcute/lexicons";
1
2
import { z } from "zod";
2
3
3
4
type Brand<K, T> = K & { __brand: T };
4
5
export type DID = Brand<string, "DID">;
5
6
6
-
export function isDid(s: string): s is DID {
7
+
export function isDid(s: string): s is Did {
7
8
return s.startsWith("did:");
8
9
}
9
10
10
-
export function parseDid(s: string): DID | null {
11
+
export function parseDid(s: string): Did | null {
11
12
if (!isDid(s)) {
12
13
return null;
13
14
}
14
15
return s;
15
16
}
16
17
17
-
export const getDidDoc = async (did: DID) => {
18
+
export const getDidDoc = async (did: Did) => {
18
19
let url = `https://plc.directory/${did}`;
19
20
if (did.startsWith('did:web')) {
20
21
url = `https://${did.split(':')[2]}/.well-known/did.json`;
···
25
26
return PlcDocument.parse(await response.json());
26
27
};
27
28
28
-
export const getPdsUrl = async (did: DID) => {
29
+
export const getPdsUrl = async (did: Did) => {
29
30
const plc = await getDidDoc(did);
30
31
31
32
return (
···
57
58
),
58
59
});
59
60
60
-
async function getAtprotoDidFromDns(handle: string) {
61
+
async function getAtprotoDidFromDns(handle: string): Promise<Did | null> {
61
62
const url = new URL("https://cloudflare-dns.com/dns-query");
62
63
url.searchParams.set("type", "TXT");
63
64
url.searchParams.set("name", `_atproto.${handle}`);
···
74
75
? JSON.parse(Answer[0]?.data).split("did=")[1]
75
76
: null;
76
77
77
-
return val ? parseDid(val) : null;
78
+
return parseDid(val);
78
79
}
79
80
80
81
const getAtprotoFromHttps = async (handle: string) => {
···
124
125
return plcHandle.toLowerCase() === handle.toLowerCase() ? did : null;
125
126
};
126
127
127
-
export const getDidFromHandleOrDid = async (handleOrDid: string) => {
128
+
export const getDidFromHandleOrDid = async (handleOrDid: string): Promise<Did | null> => {
128
129
const decodedHandleOrDid = decodeURIComponent(handleOrDid);
129
130
if (isDid(decodedHandleOrDid)) {
130
131
return decodedHandleOrDid;