From 25c1806fe76f73ca75b651d96cdedcba1ed8ca83 Mon Sep 17 00:00:00 2001 From: Florian <45694132+flo-bit@users.noreply.github.com> Date: Sun, 07 Jun 2026 16:29:43 +0000 Subject: [PATCH] bump --- pnpm-lock.yaml | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- pnpm-workspace.yaml | 6 ++++++ apps/web/package.json | 2 +- apps/web/src/lib/contrail.config.ts | 2 +- apps/web/src/lib/spaces/config.ts | 12 ++++++++++-- apps/web/src/routes/(app)/+page.server.ts | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------- 6 file(s) changed, 188 insertion(s)(+), 64 deletion(s)(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,8 +30,8 @@ specifier: ^1.1.2 version: 1.1.2 '@atmo-dev/contrail': - specifier: ^0.5.0 - version: 0.5.0(wrangler@4.77.0(@cloudflare/workers-types@4.20260317.1)) + specifier: ^0.9.0 + version: 0.9.0(wrangler@4.77.0(@cloudflare/workers-types@4.20260317.1)) '@atmo-dev/events-ui': specifier: workspace:* version: link:../../packages/ui @@ -388,12 +388,41 @@ '@atcute/xrpc-server@0.1.12': resolution: {integrity: sha512-70KIerQlljp5+s6t0u6YNN9klEboQUZa2hhoi/hmXIO1cIKEORettTMctnyjfcCJaSfAuj42dxPu51GTZBlm8w==} + '@atmo-dev/contrail-appview@0.9.0': + resolution: {integrity: sha512-nb/l820ex4h41Eh1AMKxu2vLuBZ9kAlhr7RiGi1Q9ynA2I9R4Gjy4guEzGXADKs4mLfiHvGbVINn/IGixNtFtQ==} + + '@atmo-dev/contrail-authority@0.9.0': + resolution: {integrity: sha512-Vriw3ICqJCkALE3euc2U5lZ5mAIyRij3A7kyPNeQ2+WSuxSrIoyc97C3hol73nZQzAyC8SskfFcve2dN8CGR/A==} + + '@atmo-dev/contrail-base@0.9.0': + resolution: {integrity: sha512-BTTRaOG4amCJvZwMbN2AbYcnfdUn5k0UGezBtKL5RUueDvIVVcNNk9cvS8Ol08y1FYqT8fn1KsyW2vb46e5Ctw==} + peerDependencies: + pg: ^8.0.0 + peerDependenciesMeta: + pg: + optional: true + '@atmo-dev/contrail-lexicons@0.4.4': resolution: {integrity: sha512-rb22K1H0NYp9Y7Okui/ny42T3X4xfj795p+pPrtWeBsio2ZsK9uuFtn3E+XnB314sGSUQQSe0FtkgVCUjLT+uQ==} hasBin: true + '@atmo-dev/contrail-record-host@0.9.0': + resolution: {integrity: sha512-32Re59u8BJFWHhfqRo7kBC2Iv5eLFFFjowVvriz1xqwAJIZSD74Ch7rJHj8542GgNPr45LGIOYeRw7ACzNKYbA==} + '@atmo-dev/contrail@0.5.0': resolution: {integrity: sha512-PeeA3Q6NDwaho2dgaW4QANPRvhjKBml17MMxjcq6DwQG7p0MTUqoa2RM1G7DpA8CAIPrRXTVcosb6ybqshlWtQ==} + hasBin: true + peerDependencies: + pg: ^8.0.0 + wrangler: ^4.0.0 + peerDependenciesMeta: + pg: + optional: true + wrangler: + optional: true + + '@atmo-dev/contrail@0.9.0': + resolution: {integrity: sha512-6L6+cNWyCel79Hjwk/G3P/vq9m2ENjMCf0J6RGf2nk+rJl3uZ/Ai7JvzU/HDNAMRf36fPjNME05zqL6AzVelhg==} hasBin: true peerDependencies: pg: ^8.0.0 @@ -3662,6 +3691,45 @@ '@badrap/valita': 0.4.6 nanoid: 5.1.7 + '@atmo-dev/contrail-appview@0.9.0': + dependencies: + '@atcute/atproto': 3.1.10 + '@atcute/cbor': 2.3.2 + '@atcute/cid': 2.4.1 + '@atcute/client': 4.2.1 + '@atcute/identity': 1.1.4 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.4) + '@atcute/jetstream': 1.1.2 + '@atcute/lexicons': 1.2.9 + '@atcute/xrpc-server': 0.1.12 + '@atmo-dev/contrail-authority': 0.9.0 + '@atmo-dev/contrail-base': 0.9.0 + '@atmo-dev/contrail-record-host': 0.9.0 + hono: 4.12.14 + transitivePeerDependencies: + - pg + - react + + '@atmo-dev/contrail-authority@0.9.0': + dependencies: + '@atcute/cid': 2.4.1 + '@atcute/lexicons': 1.2.9 + '@atmo-dev/contrail-base': 0.9.0 + hono: 4.12.14 + transitivePeerDependencies: + - pg + + '@atmo-dev/contrail-base@0.9.0': + dependencies: + '@atcute/atproto': 3.1.10 + '@atcute/cid': 2.4.1 + '@atcute/client': 4.2.1 + '@atcute/identity': 1.1.4 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.4) + '@atcute/lexicons': 1.2.9 + '@atcute/xrpc-server': 0.1.12 + hono: 4.12.14 + '@atmo-dev/contrail-lexicons@0.4.4(wrangler@4.77.0(@cloudflare/workers-types@4.20260317.1))': dependencies: '@atcute/lex-cli': 2.5.3 @@ -3670,6 +3738,14 @@ - pg - react - wrangler + + '@atmo-dev/contrail-record-host@0.9.0': + dependencies: + '@atcute/cid': 2.4.1 + '@atmo-dev/contrail-base': 0.9.0 + hono: 4.12.14 + transitivePeerDependencies: + - pg '@atmo-dev/contrail@0.5.0(wrangler@4.77.0(@cloudflare/workers-types@4.20260317.1))': dependencies: @@ -3682,6 +3758,29 @@ '@atcute/jetstream': 1.1.2 '@atcute/lexicons': 1.2.9 '@atcute/xrpc-server': 0.1.12 + cac: 7.0.0 + hono: 4.12.14 + jiti: 2.6.1 + optionalDependencies: + wrangler: 4.77.0(@cloudflare/workers-types@4.20260317.1) + transitivePeerDependencies: + - react + + '@atmo-dev/contrail@0.9.0(wrangler@4.77.0(@cloudflare/workers-types@4.20260317.1))': + dependencies: + '@atcute/atproto': 3.1.10 + '@atcute/cbor': 2.3.2 + '@atcute/cid': 2.4.1 + '@atcute/client': 4.2.1 + '@atcute/identity': 1.1.4 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.4) + '@atcute/jetstream': 1.1.2 + '@atcute/lexicons': 1.2.9 + '@atcute/xrpc-server': 0.1.12 + '@atmo-dev/contrail-appview': 0.9.0 + '@atmo-dev/contrail-authority': 0.9.0 + '@atmo-dev/contrail-base': 0.9.0 + '@atmo-dev/contrail-record-host': 0.9.0 cac: 7.0.0 hono: 4.12.14 jiti: 2.6.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,3 +6,9 @@ esbuild: true sharp: true workerd: true +minimumReleaseAgeExclude: + - '@atmo-dev/contrail-appview@0.9.0' + - '@atmo-dev/contrail-authority@0.9.0' + - '@atmo-dev/contrail-base@0.9.0' + - '@atmo-dev/contrail-record-host@0.9.0' + - '@atmo-dev/contrail@0.9.0' diff --git a/apps/web/package.json b/apps/web/package.json --- a/apps/web/package.json +++ b/apps/web/package.json @@ -63,7 +63,7 @@ "dependencies": { "@atcute/bluesky-richtext-parser": "^2.1.1", "@atcute/jetstream": "^1.1.2", - "@atmo-dev/contrail": "^0.5.0", + "@atmo-dev/contrail": "^0.9.0", "@atmo-dev/events-ui": "workspace:*", "@ethercorps/sveltekit-og": "^4.2.1", "@foxui/colors": "^0.8.5", diff --git a/apps/web/src/lib/contrail.config.ts b/apps/web/src/lib/contrail.config.ts --- a/apps/web/src/lib/contrail.config.ts +++ b/apps/web/src/lib/contrail.config.ts @@ -10,7 +10,7 @@ // `spaces` is declared statically so `pnpm generate` emits the `rsvp.atmo.space.*` // lexicons. The real serviceDid is injected at runtime in `$lib/contrail/index.ts` // via `getSpacesConfig()` — generate doesn't serialize it. - spaces: { type: SPACE_TYPE, serviceDid: 'did:web:placeholder' }, + spaces: { authority: { type: SPACE_TYPE, serviceDid: 'did:web:placeholder' }, recordHost: {} }, permissionSet: { title: 'Atmo Events', description: 'Manage your private events and rsvps.' diff --git a/apps/web/src/lib/spaces/config.ts b/apps/web/src/lib/spaces/config.ts --- a/apps/web/src/lib/spaces/config.ts +++ b/apps/web/src/lib/spaces/config.ts @@ -10,9 +10,17 @@ if (!SERVICE_DID) { return null; } + // contrail 0.9 split SpacesConfig into authority (member list / credentials / + // space management) and recordHost (record + blob storage). type+serviceDid + // moved under `authority`. `recordHost` must be present for record-host XRPC + // routes to register — without it space records can't be read/written. We + // store blobs on the PDS (scope.blob in atproto/settings), so no blob adapter. return { - type: SPACE_TYPE, - serviceDid: SERVICE_DID + authority: { + type: SPACE_TYPE, + serviceDid: SERVICE_DID + }, + recordHost: {} }; } diff --git a/apps/web/src/routes/(app)/+page.server.ts b/apps/web/src/routes/(app)/+page.server.ts --- a/apps/web/src/routes/(app)/+page.server.ts +++ b/apps/web/src/routes/(app)/+page.server.ts @@ -6,6 +6,7 @@ getServerClient, listDiscoverableEventsFromContrail, listEventRecordsFromContrail, + withD1Retry, type ActivityCluster, type HostProfile } from '$lib/contrail'; @@ -27,6 +28,7 @@ const myEventsPromise = (async () => { if (!locals.did) return { upcoming: [], past: [] }; + const did = locals.did; const client = locals.client && spacesAvailable() @@ -36,18 +38,20 @@ const cutoff = new Date(Date.now() - SEVEN_DAYS_MS); const cutoffIso = cutoff.toISOString(); - const [rsvpResponse, hostingResponse] = await Promise.all([ - client.get('rsvp.atmo.rsvp.listRecords', { - params: { actor: locals.did, hydrateEvent: true, limit: 100 } - }), - listEventRecordsFromContrail(client, { - actor: locals.did, - startsAtMin: cutoffIso, - sort: 'startsAt', - order: 'asc', - limit: 100 - }) - ]); + const [rsvpResponse, hostingResponse] = await withD1Retry(() => + Promise.all([ + client.get('rsvp.atmo.rsvp.listRecords', { + params: { actor: did, hydrateEvent: true, limit: 100 } + }), + listEventRecordsFromContrail(client, { + actor: did, + startsAtMin: cutoffIso, + sort: 'startsAt', + order: 'asc', + limit: 100 + }) + ]) + ); const rsvpEvents = (rsvpResponse.ok ? (rsvpResponse.data.records ?? []) : []) .filter((r) => { @@ -81,14 +85,16 @@ return { upcoming, past }; })(); - const globalPromise = listDiscoverableEventsFromContrail(publicClient, { - startsAtMin: nowIso, - rsvpsCountMin: 2, - hydrateRsvps: 5, - sort: 'startsAt', - order: 'asc', - limit: 20 - }); + const globalPromise = withD1Retry(() => + listDiscoverableEventsFromContrail(publicClient, { + startsAtMin: nowIso, + rsvpsCountMin: 2, + hydrateRsvps: 5, + sort: 'startsAt', + order: 'asc', + limit: 20 + }) + ); // listRecords and getFeed return structurally identical rsvp records, but TS // sees them as nominally-distinct lex types. Cast inputs to the structural @@ -180,15 +186,17 @@ } async function fetchGlobalActivity(): Promise { - const response = await publicClient.get('rsvp.atmo.rsvp.listRecords', { - params: { - hydrateEvent: true, - profiles: true, - sort: 'createdAt', - order: 'desc', - limit: ACTIVITY_FETCH_LIMIT - } - }); + const response = await withD1Retry(() => + publicClient.get('rsvp.atmo.rsvp.listRecords', { + params: { + hydrateEvent: true, + profiles: true, + sort: 'createdAt', + order: 'desc', + limit: ACTIVITY_FETCH_LIMIT + } + }) + ); if (!response.ok) return []; const clusters = new Map(); addRsvpsToClusters( @@ -209,35 +217,38 @@ // just gets layered on. If the merged set is empty (cold start), fall // back to the global recent-RSVP feed. if (locals.did) { - const [rsvpResp, eventResp] = await Promise.all([ - publicClient.get('rsvp.atmo.getFeed', { - params: { - feed: 'network', - actor: locals.did, - collection: 'rsvp', - hydrateEvent: true, - profiles: true, - sort: 'createdAt', - order: 'desc', - limit: ACTIVITY_FETCH_LIMIT - } - }), - publicClient.get('rsvp.atmo.getFeed', { - params: { - feed: 'network', - actor: locals.did, - collection: 'event', - profiles: true, - sort: 'startsAt', - order: 'asc', - // Only events still upcoming or recent. Server-side filter is - // possible here because startsAt IS in the event collection's - // queryable (unlike rsvp records, which carry no event date). - startsAtMin: new Date(Date.now() - ACTIVITY_RECENT_EVENT_WINDOW_MS).toISOString(), - limit: ACTIVITY_FETCH_LIMIT - } - }) - ]); + const did = locals.did; + const [rsvpResp, eventResp] = await withD1Retry(() => + Promise.all([ + publicClient.get('rsvp.atmo.getFeed', { + params: { + feed: 'network', + actor: did, + collection: 'rsvp', + hydrateEvent: true, + profiles: true, + sort: 'createdAt', + order: 'desc', + limit: ACTIVITY_FETCH_LIMIT + } + }), + publicClient.get('rsvp.atmo.getFeed', { + params: { + feed: 'network', + actor: did, + collection: 'event', + profiles: true, + sort: 'startsAt', + order: 'asc', + // Only events still upcoming or recent. Server-side filter is + // possible here because startsAt IS in the event collection's + // queryable (unlike rsvp records, which carry no event date). + startsAtMin: new Date(Date.now() - ACTIVITY_RECENT_EVENT_WINDOW_MS).toISOString(), + limit: ACTIVITY_FETCH_LIMIT + } + }) + ]) + ); const clusters = new Map(); if (rsvpResp.ok) { -- tangled.sh