Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,3 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts
.env
pnpm-lock.yaml
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore artifacts:
build
coverage
components/ui
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
93 changes: 93 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# AGENTS.md

These instructions apply to the entire repository.

## Workflow

- Follow `docs/session-workflow.md` for substantial work.
- Use `docs/model-effort-workflow.md` when recommending effort for broad,
ambiguous, or risky tasks.
- Use `docs/pr-review-workflow.md` before inspecting, addressing, or replying
to pull-request feedback.
- For tiny mechanical edits, keep the process lightweight, but still check the
worktree, preserve user changes, and verify appropriately.

## Project Shape

- This is a Next.js 16 App Router app using React 19.
- Package manager is pnpm. Use `pnpm install`, `pnpm lint`, and `pnpm build`.
- `pnpm-workspace.yaml` is used for pnpm settings even though the repo has one
root package. Keep `packages: ["."]` if the file remains present.
- UI is built with Chakra UI plus RainbowKit, Wagmi, Viem, TanStack Query, and
React Icons.
- The main page gates access by connected wallet, Gnosis-chain token balance,
and a signed message.
- API routes under `app/api/` verify the signed message server-side, fetch
membership data from an external subgraph, and create S3 signed URLs.

## Repository Map

- `app/page.tsx`: client flow for wallet connection, balance check, message
signing, file list fetching, and file link requests.
- `app/layout.tsx`: global providers, RainbowKit/Wagmi setup, Google font, and
page frame.
- `app/api/files/route.ts`: verifies membership and returns available S3
objects.
- `app/api/channel/route.ts`: verifies membership and returns a short-lived
signed URL for one S3 object.
- `app/api/shared/memberAuth.ts`: shared request validation, message constant,
member query, and membership error text.
- `app/config.ts`: server-side S3 client configuration from environment
variables.
- `app/utils/requests.ts`: client request helpers and API error normalization.
- `components/ui/`: Chakra UI helper snippets.

## Security And Privacy

- Never commit `.env` files, credentials, private URLs, local machine paths, or
real user data.
- Keep `S3_KEY`, `S3_SECRET`, `S3_ENDPOINT`, and related storage configuration
server-side only.
- Do not move signed URL creation to the client.
- Treat wallet UI checks as experience improvements only; server routes must
remain the authorization boundary.
- Preserve request-body validation before using signatures or S3 object keys.
- Avoid logging secrets, signatures, signed URLs, or sensitive response bodies.
- Discuss any change to the membership source, sign message, token threshold,
chain, bucket, or external API before implementing it.

## Environment Variables

Known environment variable names:

- `NEXT_PUBLIC_PROJECT_ID`
- `S3_ENDPOINT`
- `S3_REGION`
- `S3_KEY`
- `S3_SECRET`
- `THE_GRAPH_API_KEY`
- `JWT_SECRET`

Document variable names when needed, but never document secret values.

## Verification

Run focused checks for the files you touch. Preferred repo-level checks:

- `pnpm lint`
- `pnpm build`

Build notes:

- `pnpm build` may need network access for `next/font/google`.
- If pnpm can start but package binaries fail with `node: not found`, fix the
shell's Node runtime before diagnosing the repo.

## Style

- Follow existing Next App Router, React, TypeScript, and Chakra patterns.
- Keep changes small and reviewable.
- Prefer typed request validation at API boundaries.
- Use conventional commit messages.
- Do not introduce new dependencies, services, storage, or authentication
patterns without explaining the tradeoff first.
73 changes: 0 additions & 73 deletions app/api/channel/route.js

This file was deleted.

68 changes: 68 additions & 0 deletions app/api/channel/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { verifyMessage } from "ethers";
import { NextResponse } from "next/server";

import { s3Client } from "../../config";
import {
MEMBER_SIGN_MESSAGE,
NOT_MEMBER_ERROR,
type ChannelRequestBody,
fetchMemberAddresses,
isChannelRequestBody,
logServerError,
} from "../shared/memberAuth";

export async function POST(req: Request) {
let requestBody: ChannelRequestBody;

try {
const parsed = (await req.json()) as unknown;
if (!isChannelRequestBody(parsed)) {
return NextResponse.json(
{ error: "Invalid request body" },
{ status: 400 },
);
}
requestBody = parsed;
} catch {
return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
}

let address: string;

try {
address = verifyMessage(MEMBER_SIGN_MESSAGE, requestBody.signature);
} catch {
return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
}

try {
const members = await fetchMemberAddresses();

if (members.includes(address.toLowerCase())) {
const bucketParams = {
Bucket: "raid-guild-valhalla",
Key: requestBody.key,
};

const url = await getSignedUrl(
s3Client,
new GetObjectCommand(bucketParams),
{
expiresIn: 15 * 60,
},
);

return NextResponse.json({ channel: url });
} else {
return NextResponse.json({ error: NOT_MEMBER_ERROR }, { status: 403 });
}
} catch (error: unknown) {
logServerError("Error fetching channel", error);
return NextResponse.json(
{ error: "Failed to fetch data" },
{ status: 500 },
);
}
}
53 changes: 0 additions & 53 deletions app/api/files/route.js

This file was deleted.

Loading