diff --git a/app/lib/account.ts b/app/lib/account.ts deleted file mode 100644 index 8a0572a..0000000 --- a/app/lib/account.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { - getV0AccountsIdentifier, - getV0TimelineAccountsId, -} from "@pulsate-dev/exp-api-types"; - -import type { TimelineResponse } from "~/lib/api/timeline"; - -import { apiOptions, parseApiErrorMessage } from "./api/client"; - -export interface AccountResponse { - id: string; - name: string; - nickname: string; - bio: string; - avatar: string; - header: string; - followed_count: number; - following_count: number; - note_count: number; -} - -export const account = async ( - identifier: string, - token: string | undefined, - basePath: string -): Promise => { - try { - const { data, error } = await getV0AccountsIdentifier({ - ...apiOptions( - basePath, - token, - `/v0/accounts/${encodeURIComponent(identifier)}` - ), - path: { identifier }, - }); - if (error || !data) { - return { error: error ? parseApiErrorMessage(error) : "failed to fetch" }; - } - return { - id: data.id, - name: data.name, - nickname: data.nickname, - bio: data.bio, - avatar: data.avatar, - header: data.header, - followed_count: data.followed_count, - following_count: data.following_count, - note_count: data.note_count, - }; - } catch { - return { error: "unknown error" }; - } -}; - -export const accountTimeline = async ( - id: string, - token: string | undefined, - basePath: string, - beforeID?: string, - afterID?: string -): Promise => { - try { - const { data, error } = await getV0TimelineAccountsId({ - ...apiOptions( - basePath, - token, - `/v0/timeline/accounts/${encodeURIComponent(id)}` - ), - path: { id }, - query: beforeID - ? { before_id: beforeID } - : afterID - ? { after_id: afterID } - : undefined, - }); - if (error || !data) { - return { error: parseApiErrorMessage(error) }; - } - const timelineNotes = data.map( - (note) => - ({ - ...note, - created_at: new Date(note.created_at), - visibility: note.visibility as TimelineResponse["visibility"], - }) satisfies TimelineResponse - ); - return afterID - ? timelineNotes.filter((note) => note.id !== afterID).reverse() - : timelineNotes; - } catch { - return { error: "unknown error" }; - } -}; diff --git a/app/lib/api/account.ts b/app/lib/api/account.ts index 40cf167..96f8496 100644 --- a/app/lib/api/account.ts +++ b/app/lib/api/account.ts @@ -74,7 +74,8 @@ export const accountTimeline = async ( id: string, token: string | undefined, basePath: string, - beforeID?: string + beforeID?: string, + afterID?: string ): Promise => { try { const { data: response, error } = await getV0TimelineAccountsId({ @@ -84,38 +85,27 @@ export const accountTimeline = async ( `/v0/timeline/accounts/${encodeURIComponent(id)}` ), path: { id }, - query: beforeID ? { before_id: beforeID } : undefined, + query: beforeID + ? { before_id: beforeID } + : afterID + ? { after_id: afterID } + : undefined, }); if (error || !response) { return { error: parseApiErrorMessage(error) }; } - return response.map( - (item) => + const timelineNotes = response.map( + (note) => ({ - id: item.id, - content: item.content, - contents_warning_comment: item.contents_warning_comment, - visibility: item.visibility as "PUBLIC" | "HOME" | "FOLLOWERS", - created_at: new Date(item.created_at), - author: { - id: item.author.id, - name: item.author.name, - display_name: item.author.display_name, - bio: item.author.bio, - avatar: item.author.avatar, - header: item.author.header, - followed_count: item.author.followed_count, - following_count: item.author.following_count, - }, - reactions: item.reactions.map( - (reaction): TimelineResponse["reactions"][number] => ({ - emoji: reaction.emoji, - reacted_by: reaction.reacted_by, - }) - ), + ...note, + created_at: new Date(note.created_at), + visibility: note.visibility as TimelineResponse["visibility"], }) satisfies TimelineResponse ); + return afterID + ? timelineNotes.filter((note) => note.id !== afterID).reverse() + : timelineNotes; } catch { return { error: "unknown error" }; } diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 57acaae..49a1895 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -1,7 +1,7 @@ import type { LoaderFunctionArgs } from "react-router"; import { Link, useLoaderData } from "react-router"; -import { account } from "~/lib/account"; +import { account } from "~/lib/api/account"; import { getToken } from "~/lib/api/getToken"; import { cloudflareContext } from "~/lib/cloudflareContext"; import { parseToken } from "~/lib/parseToken"; diff --git a/app/routes/accounts.$id._index.tsx b/app/routes/accounts.$id._index.tsx index 216be15..5db83b0 100644 --- a/app/routes/accounts.$id._index.tsx +++ b/app/routes/accounts.$id._index.tsx @@ -6,8 +6,8 @@ import { FollowButton } from "~/components/followButton"; import { LoadMoreNoteButton } from "~/components/loadMoreNote"; import type { NoteProps } from "~/components/note"; import { Note } from "~/components/note"; -import type { AccountResponse } from "~/lib/account"; -import { account, accountTimeline } from "~/lib/account"; +import type { AccountResponse } from "~/lib/api/account"; +import { account, accountTimeline } from "~/lib/api/account"; import { getToken } from "~/lib/api/getToken"; import { loggedInAccount } from "~/lib/api/loggedInAccount"; import { fetchNote } from "~/lib/api/note"; diff --git a/app/routes/accounts.$id.follower.tsx b/app/routes/accounts.$id.follower.tsx index 4d7d392..18860b0 100644 --- a/app/routes/accounts.$id.follower.tsx +++ b/app/routes/accounts.$id.follower.tsx @@ -1,7 +1,7 @@ import { redirect, useLoaderData, type LoaderFunctionArgs } from "react-router"; import { FollowAccount } from "~/components/followAccount"; -import { account } from "~/lib/account"; +import { account } from "~/lib/api/account"; import { getFollowersList, type FollowerResponse } from "~/lib/api/followlist"; import { getToken } from "~/lib/api/getToken"; import { cloudflareContext } from "~/lib/cloudflareContext"; diff --git a/app/routes/accounts.$id.following.tsx b/app/routes/accounts.$id.following.tsx index 265bba7..ad12969 100644 --- a/app/routes/accounts.$id.following.tsx +++ b/app/routes/accounts.$id.following.tsx @@ -1,7 +1,7 @@ import { redirect, useLoaderData, type LoaderFunctionArgs } from "react-router"; import { FollowAccount } from "~/components/followAccount"; -import { account } from "~/lib/account"; +import { account } from "~/lib/api/account"; import { getFollowingList, type FollowingResponse } from "~/lib/api/followlist"; import { getToken } from "~/lib/api/getToken"; import { cloudflareContext } from "~/lib/cloudflareContext"; diff --git a/app/routes/signup._index.tsx b/app/routes/signup._index.tsx index 6c61739..bffcebc 100644 --- a/app/routes/signup._index.tsx +++ b/app/routes/signup._index.tsx @@ -21,11 +21,6 @@ export const action = async ({ try { const env = context.get(cloudflareContext).env; - if (env.API_BASE_URL == null) { - logger.error("API_BASE_URL env was not configured"); - return { error: "Something went wrong" }; - } - const { error } = await postV0Accounts({ ...apiOptions(env.API_BASE_URL), body: { diff --git a/wrangler.jsonc b/wrangler.jsonc index 9ba57ff..beb194d 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -3,56 +3,60 @@ * https://developers.cloudflare.com/workers/wrangler/configuration/ */ { - "$schema": "node_modules/wrangler/config-schema.json", - "name": "caramel", - "compatibility_date": "2025-04-04", - "main": "./workers/app.ts", - "observability": { - "enabled": true + "$schema": "node_modules/wrangler/config-schema.json", + "name": "caramel", + "compatibility_date": "2025-04-04", + "main": "./workers/app.ts", + "observability": { + "enabled": true, + }, + "vars": { + "API_BASE_URL": "http://localhost:3000", + "INSTANCE_FQDN": "example.com", + }, + "env": { + "demo": { + "vars": { + "API_BASE_URL": "https://demo.pulsate.dev", + "INSTANCE_FQDN": "demo.pulsate.dev", + }, }, - "env": { - "demo": { - "vars": { - "API_BASE_URL": "https://demo.pulsate.dev", - "INSTANCE_FQDN": "demo.pulsate.dev" - } - }, - "ci": { - "vars": { - "API_BASE_URL": "http://localhost:3000", - "INSTANCE_FQDN": "example.com", - "TURNSTILE_KEY": "1x00000000000000000000AA" - } - } - } - /** - * Smart Placement - * Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement - */ - // "placement": { "mode": "smart" }, - /** - * Bindings - * Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform, including - * databases, object storage, AI inference, real-time communication and more. - * https://developers.cloudflare.com/workers/runtime-apis/bindings/ - */ - /** - * Environment Variables - * https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables - */ - // "vars": { "MY_VARIABLE": "production_value" }, - /** - * Note: Use secrets to store sensitive data. - * https://developers.cloudflare.com/workers/configuration/secrets/ - */ - /** - * Static Assets - * https://developers.cloudflare.com/workers/static-assets/binding/ - */ - // "assets": { "directory": "./public/", "binding": "ASSETS" }, - /** - * Service Bindings (communicate between multiple Workers) - * https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings - */ - // "services": [{ "binding": "MY_SERVICE", "service": "my-service" }] + "ci": { + "vars": { + "API_BASE_URL": "http://localhost:3000", + "INSTANCE_FQDN": "example.com", + "TURNSTILE_KEY": "1x00000000000000000000AA", + }, + }, + }, + /** + * Smart Placement + * Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement + */ + // "placement": { "mode": "smart" }, + /** + * Bindings + * Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform, including + * databases, object storage, AI inference, real-time communication and more. + * https://developers.cloudflare.com/workers/runtime-apis/bindings/ + */ + /** + * Environment Variables + * https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables + */ + // "vars": { "MY_VARIABLE": "production_value" }, + /** + * Note: Use secrets to store sensitive data. + * https://developers.cloudflare.com/workers/configuration/secrets/ + */ + /** + * Static Assets + * https://developers.cloudflare.com/workers/static-assets/binding/ + */ + // "assets": { "directory": "./public/", "binding": "ASSETS" }, + /** + * Service Bindings (communicate between multiple Workers) + * https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings + */ + // "services": [{ "binding": "MY_SERVICE", "service": "my-service" }] }