ue/github/frontpage/readme.md
2024-10-30 07:19:23 +09:00

6.5 KiB

frontpage

$ git clone https://github.com/likeandscribe/frontpage
$ dir=${0:a:h}/frontpage
$ cd $dir

first setting

$ cd $dir
$ nvm use 20
$ pnpm i
$ cat turbo.json
$ pnpm exec turbo run --affected type-check
$ cd $dir/packages/frontpage
$ pnpm exec tsx ./scripts/generate-jwk.mts
# pnpm run db:generate 
# pnpm run db:migrate
$ cat .env.local
# frontpage/.env.local
PRIVATE_JWK=`pnpm exec tsx ./scripts/generate-jwk.mts`
PUBLIC_JWK=`pnpm exec tsx ./scripts/generate-jwk.mts`

TURSO_CONNECTION_URL=libsql://xxx.turso.io
#TURSO_CONNECTION_URL=`turso db shell xxx-xxx`
TURSO_AUTH_TOKEN=`turso db tokens create xxx-xxx`

DRAINPIPE_CONSUMER_SECRET=`openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32`
VERCEL_PROJECT_PRODUCTION_URL=example.com
VERCEL_BRANCH_URL=example.com

#DRAINPIPE_CONSUMER_SECRET=secret
#TURSO_CONNECTION_URL=libsql://turso.dev.unravel.fyi
#PLC_DIRECTORY_URL=https://plc.dev.unravel.fyi
$ cd $dir/packages-rs/drainpipe
$ cargo install diesel_cli --no-default-features --features sqlite
$ diesel setup
$ diesel migration run
$ ls drainpipe.db
$ cat .env.local
# drainpipe/.env.local
DATABASE_URL="drainpipe.db"
FRONTPAGE_CONSUMER_URL="http://${cloudflared}/api/receive_hook"
FRONTPAGE_CONSUMER_SECRET=`openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32`
#RELAY_URL=wss://bsky.network
#FRONTPAGE_CONSUMER_SECRET=secret

rewrite

$ cd $dir/packages/frontpage
$ PUBLIC_URL=example.com
$ grep -R frontpage.fyi ./app ./lib |cut -d : -f 1|sed -i "s/frontpage.fyi/$PUBLIC_URL/g"

$ HOST_REVERT=com.unravel.example
$ grep -R unravel.frontpage ./app ./lib |cut -d : -f 1|xargs sed -i "s/fyi.unravel.frontpage/${HOST_REVERT}/g"
$ cd $dir/packages-rs/drainpipe
$ HOST_REVERT=com.unravel.example
$ grep -R fyi.unravel.frontpage ./src |cut -d : -f 1|xargs sed -i "s/fyi.unravel.frontpage/${HOST_REVERT}/g"

deploy

$ cd $dir/packages-rs/drainpipe
$ docker compose up
---
$ cd $dir/packages/frontpage
$ docker compose up

explanation

client-metadata.json

the client_id is different between pnpm run start and pnpm run dev. see https://localhost:3000/oauth/client-metadata.json for this.

local-infra

i think this is the server configuration required for self-hosting.

https://github.com/likeandscribe/frontpage/tree/main/packages/frontpage/local-infra

since plc gives an error, do the following. probably a postgres database is required. there is no need to open ports.

  plc:
    image: ghcr.io/bluesky-social/did-method-plc:plc-f2ab7516bac5bc0f3f86842fa94e996bd1b3815b
    container_name: plc
    restart: unless-stopped
    ports:
      - '4000:8080'
    depends_on:
      - plc_db
    env_file:
      - ./plc.env

  plc_db:
    image: postgres:16-alpine
    restart: always
    env_file:
      - ./postgres.env
    volumes:
      - ./configs/postgres/init/:/docker-entrypoint-initdb.d/
      - ./data/postgres/:/var/lib/postgresql/data/
    healthcheck:
      test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
      interval: 5s
      retries: 20
# plc.env
DEBUG_MODE=1
LOG_ENABLED=true
LOG_LEVEL=debug
LOG_DESTINATION=1
PORT=8080
DATABASE_URL=postgres://postgres:postgres@plc_db/plc
DB_CREDS_JSON='{"username":"postgres","password":"postgres","host":"plc_db","port":"5432","database":"plc"}'
ENABLE_MIGRATIONS=true
DB_MIGRATE_CREDS_JSON='{"username":"postgres","password":"postgres","host":"plc_db","port":"5432","database":"plc"}'
# configs/postgres/init/init.sql
-- PLC
CREATE DATABASE plc;
GRANT ALL PRIVILEGES ON DATABASE plc TO postgres;

pds

first, i think you need to get the pdsurl with oauth(session). if you have a session, you can perform operations such as posting.

$ cd $dir/packages/frontpage
./lib/data/user.ts:  const pdsUrl = await getPdsUrl(session.user.did);

it seems that drainpipe searches for fyi.unravel.frontpage(collection) in pds and commits it to firehose subscriberepos. if you change these two parts, it will not work with frontpage.fyi.

// https://github.com/likeandscribe/frontpage/blob/e7444ec6c19f0ccef3776f04702c3bb033ed3bfc/packages-rs/drainpipe/src/main.rs#L66-L97
// RELAY_URL=wss://bsky.network
let mut ws_request = format!(
        "{}/xrpc/com.atproto.sync.subscribeRepos{}",
        relay_url, query_string
)

/// Process a message from the firehose. Returns the sequence number of the message or an error.
async fn process(message: Vec<u8>, ctx: &mut Context) -> Result<i64, ProcessError> {
    let (_header, data) = firehose::read(&message).map_err(|e| ProcessError {
        inner: e.into(),
        seq: -1,
        source: message.clone().into(),
        kind: ProcessErrorKind::DecodeError,
    })?;
    let sequence = match data {
        firehose::SubscribeRepos::Commit(commit) => {
            let frontpage_ops = commit
                .operations
                .iter()
                .filter(|op| op.path.starts_with("com.unravel.example."))
                //.filter(|op| op.path.starts_with("fyi.unravel.frontpage."))
                .collect::<Vec<_>>();
            if !frontpage_ops.is_empty() {
                process_frontpage_ops(&frontpage_ops, &commit, &ctx)
                    .map_err(|e| ProcessError {
                        seq: commit.sequence,
                        inner: e,
                        source: message.clone().into(),
                        kind: ProcessErrorKind::ProcessError,
                    })
                    .await?;
            }
            commit.sequence
        }
        msg => msg.sequence(),
    };

    Ok(sequence)
}

other

license view

// https://github.com/likeandscribe/frontpage/blob/de31aedf73c4e80e7376cf73c7c054437563f2ab/packages/frontpage/app/layout.tsx#L28-L52
+ <div dangerouslySetInnerHTML={{__html: '<!-- frontpage | MIT | https://github.com/likeandscribe/frontpage/blob/main/LICENSE -->'}} />

admin view

# https://github.com/likeandscribe/frontpage/blob/7fccf20fa800ba25fd57db279033ddf2cc92e9ce/packages/frontpage/lib/constants.ts
./lib/constants.ts:export const FRONTPAGE_ATPROTO_HANDLE = "admin.example.com";

# https://github.com/likeandscribe/frontpage/blob/cf8a4cb8bc7bab54407972964f8d39bf5e7c9182/packages/frontpage/app/(app)/layout.tsx#L55-L66
./app/\(app\)/layout.tsx:@admin.example.com <OpenInNewWindowIcon className="inline" />