update
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
repos
|
||||
.claude
|
||||
48
README.md
48
README.md
@@ -0,0 +1,48 @@
|
||||
# at
|
||||
|
||||
- https://github.com/bluesky-social/atproto
|
||||
- https://github.com/bluesky-social/atproto/discussions/2026
|
||||
|
||||
|word|name|example|
|
||||
|---|---|---|
|
||||
|at|uri|at://example.com|
|
||||
|@|user|@example.com|
|
||||
|[at]proto|repo|`git@github.com:bluesky-social/atproto`|
|
||||
|[at]mosphere|system|pds, bsky(appview), ozone, bgs, plc|
|
||||
|[a]uthenticated [t]ransfer|protocol|[did](https://www.w3.org/TR/did-core/)|
|
||||
|
||||
- https://atproto.com/ja/guides/glossary
|
||||
|
||||
## account
|
||||
|
||||
- [ai@syu.is](https://syu.is/profile/did:plc:6qyecktefllvenje24fcxnie)
|
||||
- [ai@bsky.app](https://bsky.app/profile/did:plc:6qyecktefllvenje24fcxnie)
|
||||
- https://plc.syu.is/did:plc:6qyecktefllvenje24fcxnie
|
||||
- https://plc.directory/did:plc:6qyecktefllvenje24fcxnie
|
||||
|
||||
```sh
|
||||
$ curl -sL syu.is/xrpc/_health
|
||||
|
||||
# latest
|
||||
# https://github.com/bluesky-social/atproto/blob/main/packages/pds/package.json
|
||||
$ curl -sL https://raw.githubusercontent.com/bluesky-social/atproto/refs/heads/main/packages/pds/package.json |jq -r .version
|
||||
```
|
||||
|
||||
```sh
|
||||
$ handle=ai.syui.ai
|
||||
$ curl -sL "syu.is/xrpc/com.atproto.repo.describeRepo?repo=${handle}" |jq -r .did
|
||||
did:plc:6qyecktefllvenje24fcxnie
|
||||
|
||||
$ curl -sL "syu.is/xrpc/com.atproto.repo.listRecords?repo=${handle}&collection=app.bsky.feed.post&reverse=true&limit=1"
|
||||
{"records":[{"uri":"at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.post/3l6s2riuouk2j","cid":"bafyreibjohl7va4upkibw5twaxdd4jg3l6rmfatu4dpjjfd5xkb2ijtlx4","value":{"text":"hello","$type":"app.bsky.feed.post","langs":["ja"],"createdAt":"2024-10-18T13:21:39.809Z"}}],"cursor":"3l6s2riuouk2j"}
|
||||
```
|
||||
|
||||
## feed
|
||||
|
||||
> at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/cmd
|
||||
|
||||
- https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd
|
||||
- https://feed.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd
|
||||
- https://desc.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:6qyecktefllvenje24fcxnie/app.bsky.feed.generator/cmd
|
||||
|
||||
|
||||
|
||||
139
compose.yml
Normal file
139
compose.yml
Normal file
@@ -0,0 +1,139 @@
|
||||
services:
|
||||
|
||||
database:
|
||||
image: postgres:16-alpine
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/postgres
|
||||
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
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- ./data/redis/:/data/
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping", "|", "grep", "PONG"]
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
plc:
|
||||
ports:
|
||||
- 2582:3000
|
||||
build:
|
||||
context: ./repos/did-method-plc/
|
||||
dockerfile: packages/server/Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/plc
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
pds:
|
||||
ports:
|
||||
- 2583:3000
|
||||
build:
|
||||
context: ./repos/atproto/
|
||||
dockerfile: services/pds/Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/pds
|
||||
volumes:
|
||||
- ./data/pds/:/data/
|
||||
command: node --enable-source-maps index.js
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
bsky:
|
||||
ports:
|
||||
- 2584:2584
|
||||
build:
|
||||
context: ./repos/atproto/
|
||||
dockerfile: services/bsky/Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/bsky
|
||||
user: root
|
||||
volumes:
|
||||
- ./data/bsky/:/data/
|
||||
command: node --enable-source-maps api.js
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
bgs:
|
||||
ports:
|
||||
- 2470:2470
|
||||
build:
|
||||
context: ./repos/indigo/
|
||||
dockerfile: cmd/bigsky/Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/bgs
|
||||
volumes:
|
||||
- ./data/bgs/:/data/
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
social-app:
|
||||
ports:
|
||||
- 8100:8100
|
||||
build:
|
||||
context: ./repos/social-app/
|
||||
dockerfile: Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/social-app
|
||||
command: "/usr/bin/bskyweb serve"
|
||||
|
||||
jetstream:
|
||||
build:
|
||||
context: ./repos/jetstream/
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 6008:6008
|
||||
volumes:
|
||||
- ./data/jetstream:/data
|
||||
restart: always
|
||||
env_file:
|
||||
- ./envs/jetstream
|
||||
|
||||
ozone-web:
|
||||
build:
|
||||
context: ./repos/ozone/
|
||||
ports:
|
||||
- 2586:3000
|
||||
restart: always
|
||||
volumes:
|
||||
- ./data/ozone/:/data/
|
||||
env_file:
|
||||
- ./envs/ozone
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
|
||||
ozone:
|
||||
build:
|
||||
context: ./repos/atproto/
|
||||
dockerfile: services/ozone/Dockerfile
|
||||
ports:
|
||||
- 2585:3000
|
||||
restart: always
|
||||
command: node --enable-source-maps api.js
|
||||
volumes:
|
||||
- ./data/ozone/:/data/
|
||||
env_file:
|
||||
- ./envs/ozone
|
||||
|
||||
35
configs/postgres/init/init.sql
Normal file
35
configs/postgres/init/init.sql
Normal file
@@ -0,0 +1,35 @@
|
||||
-- PLC
|
||||
CREATE DATABASE plc;
|
||||
GRANT ALL PRIVILEGES ON DATABASE plc TO postgres;
|
||||
|
||||
-- BGS
|
||||
CREATE DATABASE bgs;
|
||||
CREATE DATABASE carstore;
|
||||
GRANT ALL PRIVILEGES ON DATABASE bgs TO postgres;
|
||||
GRANT ALL PRIVILEGES ON DATABASE carstore TO postgres;
|
||||
|
||||
-- bsky(AppView)
|
||||
--CREATE DATABASE appview;
|
||||
--GRANT ALL PRIVILEGES ON DATABASE appview TO postgres;
|
||||
CREATE DATABASE bsky;
|
||||
GRANT ALL PRIVILEGES ON DATABASE bsky TO postgres;
|
||||
|
||||
-- ozone(Moderation)
|
||||
--CREATE DATABASE moderation;
|
||||
--GRANT ALL PRIVILEGES ON DATABASE moderation TO postgres;
|
||||
CREATE DATABASE ozone;
|
||||
GRANT ALL PRIVILEGES ON DATABASE ozone TO postgres;
|
||||
|
||||
-- search(palomar)
|
||||
CREATE DATABASE search;
|
||||
GRANT ALL PRIVILEGES ON DATABASE search TO postgres;
|
||||
--CREATE DATABASE palomar;
|
||||
--GRANT ALL PRIVILEGES ON DATABASE palomar TO postgres;
|
||||
|
||||
-- PDS
|
||||
CREATE DATABASE pds;
|
||||
GRANT ALL PRIVILEGES ON DATABASE pds TO postgres;
|
||||
|
||||
-- BSYNC
|
||||
CREATE DATABASE bsync;
|
||||
GRANT ALL PRIVILEGES ON DATABASE bsync TO postgres;
|
||||
6
envs/bgs
Normal file
6
envs/bgs
Normal file
@@ -0,0 +1,6 @@
|
||||
DATABASE_URL=postgres://postgres:postgres@database/bgs
|
||||
CARSTORE_DATABASE_URL=postgres://postgres:postgres@database/carstore
|
||||
DATA_DIR=/data
|
||||
ATP_PLC_HOST=https://plc.${host}
|
||||
BGS_NEW_PDS_PER_DAY_LIMIT=1000
|
||||
BGS_ADMIN_KEY=
|
||||
19
envs/bsky
Normal file
19
envs/bsky
Normal file
@@ -0,0 +1,19 @@
|
||||
BSKY_PORT=2584
|
||||
BSKY_BLOB_CACHE_LOC=/data/
|
||||
BSKY_BSYNC_HTTP_VERSION=1.1
|
||||
BSKY_BSYNC_PORT=3002
|
||||
BSKY_BSYNC_URL=http://bsky:3002
|
||||
BSKY_COURIER_URL=http://fake-courier.example.invalid/
|
||||
BSKY_DATAPLANE_HTTP_VERSION=1.1
|
||||
BSKY_DATAPLANE_PORT=3001
|
||||
BSKY_DATAPLANE_URLS=http://bsky:3001
|
||||
BSKY_DB_POSTGRES_URL=postgres://postgres:postgres@database/bsky
|
||||
BSKY_DID_PLC_URL=https://plc.${host}
|
||||
BSKY_PUBLIC_URL=https://bsky.${host}
|
||||
BSKY_REPO_PROVIDER=wss://bgs.${host}
|
||||
BSKY_SERVER_DID=did:web:bsky.${host}
|
||||
MOD_SERVICE_DID=did:web:ozone.${host}
|
||||
|
||||
#BSKY_IMG_URI_ENDPOINT=https://bsky.${host}/img
|
||||
BSKY_ADMIN_PASSWORDS
|
||||
BSKY_SERVICE_SIGNING_KEY
|
||||
5
envs/jetstream
Normal file
5
envs/jetstream
Normal file
@@ -0,0 +1,5 @@
|
||||
JETSTREAM_WS_URL=wss://bgs.${host}/xrpc/com.atproto.sync.subscribeRepos
|
||||
JETSTREAM_DATA_DIR=/data
|
||||
JETSTREAM_LISTEN_ADDR=:6008
|
||||
JETSTREAM_METRICS_LISTEN_ADDR=:6009
|
||||
JETSTREAM_LIVENESS_TTL=96h
|
||||
29
envs/ozone
Normal file
29
envs/ozone
Normal file
@@ -0,0 +1,29 @@
|
||||
OZONE_SERVER_DID=did:web:ozone.${host}
|
||||
OZONE_PUBLIC_URL=https://ozone.${host}
|
||||
OZONE_ADMIN_HANDLE=${user}.${host}
|
||||
OZONE_MODERATOR_DIDS=${did}
|
||||
OZONE_ADMIN_DIDS=${did}
|
||||
OZONE_DB_POSTGRES_URL=postgres://postgres:postgres@database/ozone
|
||||
OZONE_DID_PLC_URL=https://plc.${host}
|
||||
NEXT_PUBLIC_PLC_DIRECTORY_URL=https://plc.${host}
|
||||
NEXT_PUBLIC_OZONE_SERVICE_DID=did:web:ozone.${host}
|
||||
NEXT_PUBLIC_SOCIAL_APP_DOMAIN=mod.${host}
|
||||
NEXT_PUBLIC_SOCIAL_APP_URL=https://mod.${host}
|
||||
OZONE_APPVIEW_DID=did:web:bsky.${host}
|
||||
OZONE_APPVIEW_URL=https://bsky.${host}
|
||||
OZONE_APPVIEW_PUSH_EVENTS=false
|
||||
OZONE_PDS_DID=did:web:${host}
|
||||
OZONE_PDS_URL=https://${host}
|
||||
OZONE_DEV_MODE=true
|
||||
OZONE_DB_MIGRATE=1
|
||||
|
||||
OZONE_ADMIN_PASSWORD
|
||||
OZONE_SIGNING_KEY_HEX
|
||||
OZONE_BLOB_DIVERT_ADMIN_PASSWORD
|
||||
OZONE_VERIFIER_URL
|
||||
OZONE_VERIFIER_DID
|
||||
OZONE_VERIFIER_PASSWORD
|
||||
OZONE_VERIFIER_ISSUERS_TO_INDEX
|
||||
OZONE_VERIFIER_JETSTREAM_URL
|
||||
|
||||
OZONE_APPVIEW_PUSH_EVENTS=true
|
||||
23
envs/pds
Normal file
23
envs/pds
Normal file
@@ -0,0 +1,23 @@
|
||||
PDS_HOSTNAME=${host}
|
||||
PDS_DB_POSTGRES_URL=postgres://postgres:postgres@database/pds
|
||||
PDS_DATA_DIRECTORY=/data
|
||||
PDS_BLOBSTORE_DISK_LOCATION=/data/img/static
|
||||
#PDS_BLOBSTORE_DISK_TMP_LOCATION=/data/img/tmp
|
||||
PDS_BSKY_APP_VIEW_DID=did:web:bsky.${host}
|
||||
PDS_BSKY_APP_VIEW_URL=https://bsky.${host}
|
||||
PDS_CRAWLERS=https://bgs.${host}
|
||||
PDS_SEQUENCER_ENABLED=true
|
||||
PDS_SEQUENCER_DB_LOCATION=/data/sequencer.sqlite
|
||||
PDS_DEV_MODE=true
|
||||
PDS_DID_PLC_URL=https://plc.${host}
|
||||
PDS_ENABLE_DID_DOC_WITH_SESSION=true
|
||||
PDS_INVITE_INTERVAL=604800000
|
||||
PDS_SERVICE_DID=did:web:${host}
|
||||
PDS_EMAIL_FROM_ADDRESS=no-reply@${host}
|
||||
|
||||
PDS_INVITE_REQUIRED=true
|
||||
PDS_EMAIL_SMTP_URL=smtps://${user}:${app_password}@smtp.gmail.com
|
||||
PDS_ADMIN_PASSWORD
|
||||
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX
|
||||
PDS_REPO_SIGNING_KEY_K256_PRIVATE_KEY_HEX
|
||||
PDS_JWT_SECRET
|
||||
4
envs/plc
Normal file
4
envs/plc
Normal file
@@ -0,0 +1,4 @@
|
||||
DATABASE_URL=postgres://postgres:postgres@database/plc
|
||||
DB_CREDS_JSON='{"username":"postgres","password":"postgres","host":"database","port":"5432","database":"plc"}'
|
||||
ENABLE_MIGRATIONS=true
|
||||
DB_MIGRATE_CREDS_JSON='{"username":"postgres","password":"postgres","host":"database","port":"5432","database":"plc"}'
|
||||
4
envs/postgres
Normal file
4
envs/postgres
Normal file
@@ -0,0 +1,4 @@
|
||||
#POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_DB=healthcheck
|
||||
3
envs/social-app
Normal file
3
envs/social-app
Normal file
@@ -0,0 +1,3 @@
|
||||
ATP_APPVIEW_HOST=https://public.api.bsky.app
|
||||
EXPO_PUBLIC_BLUESKY_PROXY_DID=did:web:api.bsky.app
|
||||
EXPO_PUBLIC_ENV=production
|
||||
52
icons/Logotype.tsx
Normal file
52
icons/Logotype.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import React from 'react'
|
||||
import Svg, {Path, SvgProps, PathProps} from 'react-native-svg'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
|
||||
const ratio = 17 / 64
|
||||
|
||||
export function Logotype({
|
||||
fill,
|
||||
...rest
|
||||
}: {fill?: PathProps['fill']} & SvgProps) {
|
||||
const pal = usePalette('default')
|
||||
// @ts-ignore it's fiiiiine
|
||||
const size = parseInt(rest.width || 32)
|
||||
|
||||
return (
|
||||
<Svg
|
||||
fill="none"
|
||||
viewBox="0 0 2821.6379 794.29016"
|
||||
{...rest}
|
||||
width={size}
|
||||
height={Number(size) * ratio}>
|
||||
<g
|
||||
transform="matrix(0.1,0,0,-0.1,-282.80153,1445)"
|
||||
fill="#000000"
|
||||
stroke="none"
|
||||
>
|
||||
<path
|
||||
d="m 24787,14443 c -4,-3 -7,-224 -7,-490 v -483 h 545 545 v 490 490 h -538 c -296,0 -542,-3 -545,-7 z"
|
||||
/>
|
||||
<path
|
||||
d="m 5190,13285 c -8,-3 -96,-12 -195,-20 -199,-16 -296,-32 -430,-70 -49,-14 -115,-32 -145,-40 -153,-39 -504,-198 -662,-301 -21,-13 -57,-36 -80,-51 -24,-16 -72,-50 -109,-78 -241,-182 -377,-315 -528,-517 -119,-158 -120,-160 -106,-188 23,-45 140,-140 560,-457 110,-84 319,-242 465,-353 146,-110 369,-279 495,-375 791,-600 723,-549 1049,-799 269,-207 398,-307 524,-403 l 114,-86 -49,-49 c -128,-131 -378,-258 -588,-299 -66,-13 -357,-13 -420,0 -115,23 -172,39 -202,54 -18,10 -37,17 -43,17 -24,0 -171,81 -255,141 -50,35 -146,121 -215,192 -69,70 -133,127 -142,127 -19,0 -153,-63 -177,-83 -9,-7 -54,-35 -101,-62 -47,-26 -110,-64 -140,-85 -30,-20 -97,-61 -148,-91 -51,-30 -107,-62 -124,-72 -18,-10 -57,-38 -87,-61 -70,-53 -252,-168 -446,-281 -82,-49 -158,-95 -168,-104 -16,-16 -14,-21 34,-106 165,-289 544,-666 867,-860 9,-6 35,-22 58,-37 36,-23 267,-138 349,-173 108,-47 160,-67 240,-93 150,-48 201,-62 228,-62 14,0 64,-9 109,-19 197,-46 302,-56 573,-56 197,1 281,5 345,17 47,9 110,19 141,22 31,3 75,13 99,21 23,8 56,15 72,15 17,0 51,7 77,15 25,8 80,24 121,36 41,12 125,41 185,66 61,25 124,50 140,56 17,7 89,42 160,78 113,58 177,98 395,246 82,56 273,232 403,371 127,136 237,271 237,291 0,12 -208,179 -425,342 -186,140 -1121,843 -1720,1294 -264,199 -589,444 -723,546 -134,101 -274,208 -312,237 -39,29 -70,58 -70,66 0,21 107,115 203,179 95,64 237,133 295,143 20,4 49,12 63,20 96,48 519,48 619,-1 14,-7 41,-16 60,-20 65,-13 262,-118 360,-191 99,-74 250,-230 372,-384 34,-44 70,-80 80,-80 9,0 39,15 67,33 28,17 70,44 94,58 23,15 121,76 217,136 96,60 254,156 350,213 96,56 272,160 390,230 118,70 230,135 248,144 41,21 41,45 -3,116 -18,30 -46,75 -61,100 -64,106 -252,348 -352,454 -106,112 -169,171 -293,274 -197,164 -310,235 -594,376 -215,106 -519,205 -735,240 -137,22 -574,51 -610,41 z"
|
||||
/>
|
||||
<path
|
||||
d="m 29095,12736 c -421,-44 -744,-157 -975,-342 -259,-207 -396,-446 -465,-809 -16,-84 -23,-301 -14,-425 36,-518 257,-859 694,-1070 166,-80 284,-116 716,-215 449,-103 514,-121 646,-186 218,-107 308,-253 306,-494 -2,-303 -188,-477 -588,-551 -140,-26 -640,-27 -825,-1 -275,38 -486,94 -776,203 -94,35 -174,64 -178,64 -3,0 -6,-175 -6,-389 v -388 l 88,-41 c 404,-187 905,-282 1486,-282 675,0 1154,150 1465,459 196,194 311,434 362,756 20,121 17,476 -5,600 -89,517 -358,800 -945,994 -130,43 -241,71 -616,156 -137,31 -299,73 -360,92 -331,106 -455,246 -455,511 1,249 127,412 387,501 272,92 801,76 1269,-39 116,-28 326,-96 432,-138 l 52,-22 -2,406 -3,406 -66,28 c -154,66 -413,140 -604,174 -279,49 -756,69 -1020,42 z"
|
||||
/>
|
||||
<path
|
||||
d="m 9630,12676 c 0,-2 403,-996 896,-2208 493,-1211 898,-2211 901,-2220 6,-21 -135,-386 -193,-499 -104,-202 -256,-324 -471,-380 -118,-30 -340,-43 -516,-29 -84,6 -185,17 -225,24 -40,7 -75,10 -77,7 -3,-2 -5,-163 -5,-357 v -353 l 63,-30 c 194,-93 493,-138 801,-120 414,23 683,115 937,319 174,140 357,402 474,680 26,62 1945,5159 1945,5167 0,2 -232,2 -516,1 l -517,-3 -556,-1550 c -485,-1350 -560,-1550 -578,-1553 -18,-3 -26,11 -62,105 -23,59 -295,758 -605,1553 l -562,1445 -567,3 c -312,1 -567,0 -567,-2 z"
|
||||
/>
|
||||
<path
|
||||
d="m 15690,10867 c 0,-1970 -1,-1936 56,-2153 128,-497 461,-787 1014,-885 147,-26 440,-36 605,-20 413,40 834,200 1181,447 35,25 73,44 88,44 14,0 26,-1 26,-3 0,-2 20,-94 45,-205 25,-111 45,-204 45,-207 0,-3 209,-5 465,-5 h 465 v 2400 2400 h -535 -535 l -2,-1866 -3,-1866 -115,-50 c -425,-185 -743,-252 -1088,-227 -302,21 -472,109 -562,293 -79,161 -74,11 -77,1969 l -3,1747 h -535 -535 z"
|
||||
/>
|
||||
<path
|
||||
d="m 24785,12668 c -3,-7 -4,-1086 -3,-2398 l 3,-2385 538,-3 537,-2 v 2400 2400 h -535 c -419,0 -537,-3 -540,-12 z"
|
||||
/>
|
||||
<path
|
||||
d="m 21660,8275 v -545 h 565 565 v 545 545 h -565 -565 z"
|
||||
/>
|
||||
</g>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
32
icons/title.svg
Normal file
32
icons/title.svg
Normal file
@@ -0,0 +1,32 @@
|
||||
<svg
|
||||
viewBox="0 0 2821.6379 794.29016"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<g
|
||||
transform="matrix(0.1,0,0,-0.1,-282.80153,1445)"
|
||||
fill="#000000"
|
||||
stroke="none"
|
||||
>
|
||||
<path
|
||||
d="m 24787,14443 c -4,-3 -7,-224 -7,-490 v -483 h 545 545 v 490 490 h -538 c -296,0 -542,-3 -545,-7 z"
|
||||
/>
|
||||
<path
|
||||
d="m 5190,13285 c -8,-3 -96,-12 -195,-20 -199,-16 -296,-32 -430,-70 -49,-14 -115,-32 -145,-40 -153,-39 -504,-198 -662,-301 -21,-13 -57,-36 -80,-51 -24,-16 -72,-50 -109,-78 -241,-182 -377,-315 -528,-517 -119,-158 -120,-160 -106,-188 23,-45 140,-140 560,-457 110,-84 319,-242 465,-353 146,-110 369,-279 495,-375 791,-600 723,-549 1049,-799 269,-207 398,-307 524,-403 l 114,-86 -49,-49 c -128,-131 -378,-258 -588,-299 -66,-13 -357,-13 -420,0 -115,23 -172,39 -202,54 -18,10 -37,17 -43,17 -24,0 -171,81 -255,141 -50,35 -146,121 -215,192 -69,70 -133,127 -142,127 -19,0 -153,-63 -177,-83 -9,-7 -54,-35 -101,-62 -47,-26 -110,-64 -140,-85 -30,-20 -97,-61 -148,-91 -51,-30 -107,-62 -124,-72 -18,-10 -57,-38 -87,-61 -70,-53 -252,-168 -446,-281 -82,-49 -158,-95 -168,-104 -16,-16 -14,-21 34,-106 165,-289 544,-666 867,-860 9,-6 35,-22 58,-37 36,-23 267,-138 349,-173 108,-47 160,-67 240,-93 150,-48 201,-62 228,-62 14,0 64,-9 109,-19 197,-46 302,-56 573,-56 197,1 281,5 345,17 47,9 110,19 141,22 31,3 75,13 99,21 23,8 56,15 72,15 17,0 51,7 77,15 25,8 80,24 121,36 41,12 125,41 185,66 61,25 124,50 140,56 17,7 89,42 160,78 113,58 177,98 395,246 82,56 273,232 403,371 127,136 237,271 237,291 0,12 -208,179 -425,342 -186,140 -1121,843 -1720,1294 -264,199 -589,444 -723,546 -134,101 -274,208 -312,237 -39,29 -70,58 -70,66 0,21 107,115 203,179 95,64 237,133 295,143 20,4 49,12 63,20 96,48 519,48 619,-1 14,-7 41,-16 60,-20 65,-13 262,-118 360,-191 99,-74 250,-230 372,-384 34,-44 70,-80 80,-80 9,0 39,15 67,33 28,17 70,44 94,58 23,15 121,76 217,136 96,60 254,156 350,213 96,56 272,160 390,230 118,70 230,135 248,144 41,21 41,45 -3,116 -18,30 -46,75 -61,100 -64,106 -252,348 -352,454 -106,112 -169,171 -293,274 -197,164 -310,235 -594,376 -215,106 -519,205 -735,240 -137,22 -574,51 -610,41 z"
|
||||
/>
|
||||
<path
|
||||
d="m 29095,12736 c -421,-44 -744,-157 -975,-342 -259,-207 -396,-446 -465,-809 -16,-84 -23,-301 -14,-425 36,-518 257,-859 694,-1070 166,-80 284,-116 716,-215 449,-103 514,-121 646,-186 218,-107 308,-253 306,-494 -2,-303 -188,-477 -588,-551 -140,-26 -640,-27 -825,-1 -275,38 -486,94 -776,203 -94,35 -174,64 -178,64 -3,0 -6,-175 -6,-389 v -388 l 88,-41 c 404,-187 905,-282 1486,-282 675,0 1154,150 1465,459 196,194 311,434 362,756 20,121 17,476 -5,600 -89,517 -358,800 -945,994 -130,43 -241,71 -616,156 -137,31 -299,73 -360,92 -331,106 -455,246 -455,511 1,249 127,412 387,501 272,92 801,76 1269,-39 116,-28 326,-96 432,-138 l 52,-22 -2,406 -3,406 -66,28 c -154,66 -413,140 -604,174 -279,49 -756,69 -1020,42 z"
|
||||
/>
|
||||
<path
|
||||
d="m 9630,12676 c 0,-2 403,-996 896,-2208 493,-1211 898,-2211 901,-2220 6,-21 -135,-386 -193,-499 -104,-202 -256,-324 -471,-380 -118,-30 -340,-43 -516,-29 -84,6 -185,17 -225,24 -40,7 -75,10 -77,7 -3,-2 -5,-163 -5,-357 v -353 l 63,-30 c 194,-93 493,-138 801,-120 414,23 683,115 937,319 174,140 357,402 474,680 26,62 1945,5159 1945,5167 0,2 -232,2 -516,1 l -517,-3 -556,-1550 c -485,-1350 -560,-1550 -578,-1553 -18,-3 -26,11 -62,105 -23,59 -295,758 -605,1553 l -562,1445 -567,3 c -312,1 -567,0 -567,-2 z"
|
||||
/>
|
||||
<path
|
||||
d="m 15690,10867 c 0,-1970 -1,-1936 56,-2153 128,-497 461,-787 1014,-885 147,-26 440,-36 605,-20 413,40 834,200 1181,447 35,25 73,44 88,44 14,0 26,-1 26,-3 0,-2 20,-94 45,-205 25,-111 45,-204 45,-207 0,-3 209,-5 465,-5 h 465 v 2400 2400 h -535 -535 l -2,-1866 -3,-1866 -115,-50 c -425,-185 -743,-252 -1088,-227 -302,21 -472,109 -562,293 -79,161 -74,11 -77,1969 l -3,1747 h -535 -535 z"
|
||||
/>
|
||||
<path
|
||||
d="m 24785,12668 c -3,-7 -4,-1086 -3,-2398 l 3,-2385 538,-3 537,-2 v 2400 2400 h -535 c -419,0 -537,-3 -540,-12 z"
|
||||
/>
|
||||
<path
|
||||
d="m 21660,8275 v -545 h 565 565 v 545 545 h -565 -565 z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
328
install.zsh
Executable file
328
install.zsh
Executable file
@@ -0,0 +1,328 @@
|
||||
#!/bin/zsh
|
||||
|
||||
# ./install.zsh $HOST
|
||||
repos_v='{}'
|
||||
function at-repos-env() {
|
||||
host=$1
|
||||
if [ -z "$1" ];then
|
||||
host=syu.is
|
||||
fi
|
||||
did=did:plc:6qyecktefllvenje24fcxnie
|
||||
icon=https://git.syui.ai/ai/at/raw/branch/main/icons/Logotype.tsx
|
||||
repos=(
|
||||
https://github.com/did-method-plc/did-method-plc
|
||||
https://github.com/bluesky-social/indigo
|
||||
https://github.com/bluesky-social/atproto
|
||||
https://github.com/bluesky-social/social-app
|
||||
https://github.com/bluesky-social/feed-generator
|
||||
https://github.com/bluesky-social/ozone
|
||||
https://github.com/bluesky-social/jetstream
|
||||
)
|
||||
services=( bsky plc pds jetstream bgs ozone social-app )
|
||||
d=${0:a:h}
|
||||
dh=${0:a:h:h}
|
||||
name=${host%%.*}
|
||||
domain=${host##*.}
|
||||
dport=5000
|
||||
}
|
||||
|
||||
function at-repos-json() {
|
||||
f=~/.config/atproto/token.json
|
||||
j="{ \"did\": \"did:plc:6qyecktefllvenje24fcxnie\", \"didDoc\": { \"service\": [ { \"serviceEndpoint\": \"https://syu.is\" } ] }, \"handle\": \"ai.syu.is\", \"accessJwt\": \"xxx\" }"
|
||||
if [ ! -f "$f" ];then
|
||||
mkdir -p ~/.config/atproto
|
||||
echo $j >> $f
|
||||
fi
|
||||
echo $f
|
||||
}
|
||||
|
||||
function at-repos-token() {
|
||||
at-repos-json
|
||||
if [ -z "$host" ] && [ -f $f ];then
|
||||
host=`cat $f|jq -r ".didDoc.service.[].serviceEndpoint"`
|
||||
handle=`cat $f|jq -r ".handle"`
|
||||
did=`cat $f|jq -r ".did"`
|
||||
token=`cat $f|jq -r ".token"`
|
||||
host=${host##*/}
|
||||
fi
|
||||
name=${host%%.*}
|
||||
domain=${host##*.}
|
||||
}
|
||||
|
||||
function at-repos-clone() {
|
||||
if [ ! -d $d/repos ];then
|
||||
mkdir -p $d/repos
|
||||
fi
|
||||
cd $d/repos
|
||||
for ((i=1; i<=${#repos}; i++)); do
|
||||
repo=${repos[$i]}
|
||||
echo $repo
|
||||
if [ ! -d $d/repos/${repo##*/} ];then
|
||||
git clone $repo
|
||||
|
||||
fi
|
||||
done
|
||||
if [ ! -f $d/repos/feed-generator/Dockerfile ] && [ -f $d/docker/feed/Dockerfile ];then
|
||||
cp -rf $d/docker/feed/Dockerfile $d/repos/feed-generator/
|
||||
fi
|
||||
}
|
||||
|
||||
function at-repos-pull() {
|
||||
cd $d/repos
|
||||
for ((i=1; i<=${#repos}; i++)); do
|
||||
repo=${repos[$i]}
|
||||
echo $repo
|
||||
if [ -d $d/repos/${repo##*/} ];then
|
||||
cd $d/repos/${repo##*/}
|
||||
git stash
|
||||
if ! git pull;then
|
||||
rm -rf $d/repos/${repo##*/}
|
||||
at-repos-clone
|
||||
fi
|
||||
fi
|
||||
rv=$(echo "$repos_v" | jq -r ".[\"${repo##*/}\"]")
|
||||
if [ "$rv" != "null" ];then
|
||||
cd $d/repos/${repo##*/}
|
||||
git reset --hard $rv
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
cd $d
|
||||
}
|
||||
|
||||
function at-repos-social-app-icon() {
|
||||
curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/main/src/view/icons/Logotype.tsx -o $d/repos/social-app/src/view/icons/Logotype.tsx
|
||||
if [ -d $d/icons ];then
|
||||
mkdir -p $d/icons
|
||||
fi
|
||||
cp -rf $d/repos/social-app/src/view/icons/Logotype.tsx $d/icons/
|
||||
}
|
||||
|
||||
function at-repos-social-app-icon-origin() {
|
||||
curl -sL $icon -o $d/icons/Logotype.tsx
|
||||
}
|
||||
|
||||
function at-repos-social-app-avatar-write() {
|
||||
did_admin=did:plc:6qyecktefllvenje24fcxnie
|
||||
dt=$d/repos/social-app/src
|
||||
cd $dt
|
||||
f=$dt/lib/constants.ts
|
||||
sed -i "s#export const BSKY_SERVICE = 'https://bsky.social'#export const BSKY_SERVICE = 'https://${host}'#g" $f
|
||||
sed -i "s#export const BSKY_SERVICE_DID = 'did:web:bsky.social'#export const BSKY_SERVICE_DID = 'did:web:${host}'#g" $f
|
||||
sed -i "s#export const PUBLIC_BSKY_SERVICE = 'https://public.api.bsky.app'#export const PUBLIC_BSKY_SERVICE = 'https://bsky.${host}'#g" $f
|
||||
sed -i "s#export const PUBLIC_APPVIEW = 'https://api.bsky.app'#export const PUBLIC_APPVIEW = 'https://bsky.${host}'#g" $f
|
||||
sed -i "s#export const PUBLIC_APPVIEW_DID = 'did:web:api.bsky.app'#export const PUBLIC_APPVIEW_DID = 'did:web:bsky.${host}'#g" $f
|
||||
|
||||
# Disable external services (CORS fix)
|
||||
f=$dt/state/geolocation/const.ts
|
||||
curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/state/geolocation/const.ts -o $f
|
||||
cat > $f << 'GEOEOF'
|
||||
import {type GeolocationStatus} from '#/state/geolocation/types'
|
||||
import {BAPP_CONFIG_DEV_URL, IS_DEV} from '#/env'
|
||||
import {type Device} from '#/storage'
|
||||
|
||||
export const IPCC_URL = `https://bsky.app/ipcc`
|
||||
// Disabled for self-hosted environment to avoid CORS errors
|
||||
export const BAPP_CONFIG_URL_PROD = null
|
||||
export const BAPP_CONFIG_URL = null
|
||||
export const GEOLOCATION_CONFIG_URL = BAPP_CONFIG_URL
|
||||
|
||||
export const DEFAULT_GEOLOCATION_CONFIG: Device['geolocation'] = {
|
||||
countryCode: undefined,
|
||||
regionCode: undefined,
|
||||
ageRestrictedGeos: [],
|
||||
ageBlockedGeos: [],
|
||||
}
|
||||
|
||||
export const DEFAULT_GEOLOCATION_STATUS: GeolocationStatus = {
|
||||
countryCode: undefined,
|
||||
regionCode: undefined,
|
||||
isAgeRestrictedGeo: false,
|
||||
isAgeBlockedGeo: false,
|
||||
}
|
||||
GEOEOF
|
||||
|
||||
# Add null check to geolocation config.ts to prevent fetch(null) errors
|
||||
f=$dt/state/geolocation/config.ts
|
||||
curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/state/geolocation/config.ts -o $f
|
||||
# Add null check at the beginning of getGeolocationConfig function (after line with 'url: string,')
|
||||
sed -i "s/): Promise<Device\['geolocation'\]> {/): Promise<Device['geolocation']> {\n if (!url) return undefined/" $f
|
||||
|
||||
# Disable Statsig (CORS fix)
|
||||
f=$dt/lib/statsig/statsig.tsx
|
||||
sed -i "s#api: 'https://events.bsky.app/v2'#api: '' // Disabled for self-hosted#g" $f
|
||||
# Disable SDK initialization to prevent statsigapi.net connections
|
||||
sed -i "s#const SDK_KEY = 'client-SXJakO39w9vIhl3D44u8UupyzFl4oZ2qPIkjwcvuPsV'#const SDK_KEY = '' // Disabled for self-hosted#g" $f
|
||||
|
||||
f=$dt/view/icons/Logotype.tsx
|
||||
o=$d/icons/Logotype.tsx
|
||||
cp -rf $o $f
|
||||
|
||||
f=$dt/view/com/util/UserAvatar.tsx
|
||||
curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/view/com/util/UserAvatar.tsx -o $f
|
||||
sed -i "s#/img/avatar/plain/#https://cdn.web.syu.is/img/avatar/plain/#g" $f
|
||||
sed -i "s#/img/avatar_thumbnail/plain/#https://bsky.${host}/img/avatar/plain/#g" $f
|
||||
sed -i "s#source={{uri: avatar}}#source={{ uri: hackModifyThumbnailPath(avatar, 1 > 0), }}#g" $f
|
||||
curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/lib/strings/url-helpers.ts -o $dt/lib/strings/url-helpers.ts
|
||||
sed -i "s#https://go.web.syu.is/redirect?u=\${encodeURIComponent(url)}#\${url}#g" $dt/lib/strings/url-helpers.ts
|
||||
grep -R $did_admin .|cut -d : -f 1|sort -u|xargs sed -i "s/${did_admin}/${did}/g"
|
||||
}
|
||||
|
||||
function at-repos-atproto-service-bsky-api-patch() {
|
||||
# https://github.com/itaru2622/bluesky-selfhost-env/blob/master/patching/105-atproto-services-for-docker.diff
|
||||
f=$d/repos/atproto/services/bsky/api.js
|
||||
curl -sL https://raw.githubusercontent.com/bluesky-social/atproto/refs/heads/main/services/bsky/api.js -o $f
|
||||
d_=$d/repos/atproto
|
||||
p_=$d/patching/4367-atproto-services-bsky-api.diff
|
||||
echo "applying patch: under ${f} for ${p_}"
|
||||
pushd ${d_}
|
||||
patch -p1 < ${p_}
|
||||
popd
|
||||
}
|
||||
|
||||
function at-repos-atproto-service-pds-index-patch() {
|
||||
f=$d/repos/atproto/services/pds/index.js
|
||||
curl -sL https://raw.githubusercontent.com/bluesky-social/atproto/refs/heads/main/services/pds/index.js -o $f
|
||||
d_=$d/repos/atproto
|
||||
p_=$d/patching/4367-atproto-services-pds-index.diff
|
||||
echo "applying patch: under ${f} for ${p_}"
|
||||
pushd ${d_}
|
||||
patch -p1 < ${p_}
|
||||
popd
|
||||
}
|
||||
|
||||
function at-repos-social-app-agent-patch() {
|
||||
f=$d/repos/social-app/src/state/session/agent.ts
|
||||
p_=$d/patching/8980-social-app-disable-proxy.diff
|
||||
d_=$d/repos/social-app
|
||||
echo "applying patch: under ${f} for ${p_}"
|
||||
pushd ${d_}
|
||||
patch -p1 < ${p_}
|
||||
popd
|
||||
}
|
||||
|
||||
function at-repos-social-app-disable-external-services-patch() {
|
||||
f=$d/repos/social-app/src/state/geolocation/const.ts
|
||||
p_=$d/patching/8980-social-app-disable-external-services.diff
|
||||
d_=$d/repos/social-app
|
||||
echo "applying patch: under ${f} for ${p_}"
|
||||
pushd ${d_}
|
||||
patch -p1 < ${p_}
|
||||
popd
|
||||
}
|
||||
|
||||
function at-repos-atproto-service-ozone-api-patch() {
|
||||
f=$d/repos/atproto/services/ozone/api.js
|
||||
d_=$d/repos/atproto
|
||||
p_=$d/patching/130-atproto-ozone-enable-daemon-v2.patch
|
||||
echo "applying patch: under ${f} for ${p_}"
|
||||
pushd ${d_}
|
||||
patch -p1 < ${p_}
|
||||
popd
|
||||
}
|
||||
|
||||
function at-repos-ozone-patch() {
|
||||
#DOMAIN=syu.is
|
||||
cd $d/repos
|
||||
d_=$d/repos/ozone
|
||||
rm -rf ${d_}
|
||||
p_=$d/patching/120-ozone-runtimeEnvVars.diff
|
||||
git clone https://github.com/bluesky-social/ozone
|
||||
cd ${d_}
|
||||
pushd ${d_}
|
||||
echo "applying patch: under ${d_} for ${p_}"
|
||||
patch -p1 < ${p_}
|
||||
popd
|
||||
|
||||
p_=$d/patching/122-ozone-enable-daemon.diff
|
||||
echo "applying patch: under ${d_} for ${p_}"
|
||||
pushd ${d_}
|
||||
patch -p1 < ${p_}
|
||||
popd
|
||||
|
||||
p_=$d/patching/121-ozone-constants-fix.patch
|
||||
echo "applying patch: under ${d_} for ${p_}"
|
||||
pushd ${d_}
|
||||
patch -p1 < ${p_} || true
|
||||
popd
|
||||
}
|
||||
|
||||
function at-repos-build-docker-atproto() {
|
||||
cd $d
|
||||
docker image prune -a
|
||||
if [ -z "$1" ];then
|
||||
for ((i=1; i<=${#services}; i++)); do
|
||||
service=${services[$i]}
|
||||
docker compose build --no-cache $service
|
||||
done
|
||||
else
|
||||
docker compose build --no-cache $1
|
||||
fi
|
||||
}
|
||||
|
||||
function at-repos-push-reset() {
|
||||
docker restart registry
|
||||
docker stop registry
|
||||
docker rm registry
|
||||
docker volume rm registry-data 2>/dev/null || true
|
||||
docker run -d -p ${dport}:${dport} --name registry \
|
||||
--restart=always \
|
||||
-v registry-data:/var/lib/registry \
|
||||
registry:2
|
||||
sleep 3
|
||||
docker run -d -p ${dport}:${dport} --name registry --restart=always registry:2
|
||||
}
|
||||
|
||||
function at-repos-push-docker() {
|
||||
if [ -z "$1" ];then
|
||||
for ((i=1; i<=${#services}; i++)); do
|
||||
service=${services[$i]}
|
||||
docker tag at-${service}:latest localhost:${dport}/${service}:latest
|
||||
docker push localhost:${dport}/${service}:latest
|
||||
if [ "$service" = "ozone" ];then
|
||||
docker tag at-${service}:latest localhost:${dport}/${service}-web:latest
|
||||
docker push localhost:${dport}/${service}-web:latest
|
||||
fi
|
||||
done
|
||||
else
|
||||
docker tag at-${1}:latest localhost:${dport}/${1}:latest
|
||||
docker push localhost:${dport}/${1}:latest
|
||||
fi
|
||||
}
|
||||
|
||||
function at-repos-pull-docker() {
|
||||
cd $d
|
||||
docker image prune -a
|
||||
docker compose up -d --pull always
|
||||
}
|
||||
|
||||
at-repos-env
|
||||
case "`cat /etc/hostname`" in
|
||||
at)
|
||||
at-repos-pull-docker
|
||||
exit
|
||||
;;
|
||||
*)
|
||||
at-repos-push-reset
|
||||
at-repos-clone
|
||||
at-repos-pull
|
||||
at-repos-social-app-icon
|
||||
at-repos-social-app-icon-origin
|
||||
at-repos-social-app-avatar-write
|
||||
at-repos-social-app-agent-patch
|
||||
at-repos-social-app-disable-external-services-patch
|
||||
at-repos-atproto-service-bsky-api-patch
|
||||
at-repos-atproto-service-pds-index-patch
|
||||
at-repos-atproto-service-ozone-api-patch
|
||||
at-repos-ozone-patch
|
||||
if [ -n "$1" ];then
|
||||
at-repos-build-docker-atproto $1
|
||||
at-repos-push-docker $1
|
||||
exit
|
||||
fi
|
||||
at-repos-build-docker-atproto
|
||||
at-repos-push-docker
|
||||
cd $d; docker compose down
|
||||
;;
|
||||
esac
|
||||
|
||||
134
ios/AppInfo.tsx
Normal file
134
ios/AppInfo.tsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import React from 'react'
|
||||
import {View, Text, StyleSheet, Pressable, Linking} from 'react-native'
|
||||
|
||||
interface AppInfoProps {
|
||||
onLinkPress?: (url: string) => void
|
||||
}
|
||||
|
||||
export default function AppInfo({onLinkPress}: AppInfoProps) {
|
||||
const handleLinkPress = (url: string) => {
|
||||
if (onLinkPress) {
|
||||
onLinkPress(url)
|
||||
} else {
|
||||
Linking.openURL(url)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>About This App</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
This is a customized AT Protocol social networking client. It allows you to
|
||||
connect to any Personal Data Server (PDS) and participate in the decentralized
|
||||
social network.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Key Features</Text>
|
||||
<View style={styles.list}>
|
||||
<Text style={styles.listItem}>• Connect to any AT Protocol PDS</Text>
|
||||
<Text style={styles.listItem}>• Post text, images, and videos</Text>
|
||||
<Text style={styles.listItem}>• Follow users and view timelines</Text>
|
||||
<Text style={styles.listItem}>• Customize feeds and moderation settings</Text>
|
||||
<Text style={styles.listItem}>• Direct messaging support</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Open Source</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
This application is based on the Bluesky social-app, licensed under the MIT
|
||||
License. The original source code is available at:
|
||||
</Text>
|
||||
<Pressable
|
||||
onPress={() =>
|
||||
handleLinkPress('https://github.com/bluesky-social/social-app')
|
||||
}>
|
||||
<Text style={styles.link}>github.com/bluesky-social/social-app</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>AT Protocol</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
This app uses the AT Protocol (Authenticated Transfer Protocol), an open and
|
||||
decentralized standard for social applications.
|
||||
</Text>
|
||||
<Pressable onPress={() => handleLinkPress('https://atproto.com')}>
|
||||
<Text style={styles.link}>atproto.com</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>License</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Copyright 2023–2025 Bluesky Social PBC
|
||||
</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software.
|
||||
</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Contact</Text>
|
||||
<Pressable onPress={() => handleLinkPress('https://syu.is')}>
|
||||
<Text style={styles.link}>https://syu.is</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.versionText}>Version 1.0.0</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
section: {
|
||||
marginBottom: 24,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '600',
|
||||
color: '#1d1d1f',
|
||||
marginBottom: 12,
|
||||
},
|
||||
paragraph: {
|
||||
fontSize: 15,
|
||||
lineHeight: 22,
|
||||
color: '#3a3a3c',
|
||||
marginBottom: 8,
|
||||
},
|
||||
list: {
|
||||
marginLeft: 8,
|
||||
marginTop: 8,
|
||||
},
|
||||
listItem: {
|
||||
fontSize: 15,
|
||||
lineHeight: 24,
|
||||
color: '#3a3a3c',
|
||||
},
|
||||
link: {
|
||||
fontSize: 15,
|
||||
color: '#007aff',
|
||||
textDecorationLine: 'underline',
|
||||
marginTop: 8,
|
||||
},
|
||||
versionText: {
|
||||
fontSize: 13,
|
||||
color: '#8e8e93',
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
})
|
||||
95
ios/LicenseNotice.tsx
Normal file
95
ios/LicenseNotice.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import React from 'react'
|
||||
import {View, Text, StyleSheet, Pressable, Linking} from 'react-native'
|
||||
|
||||
export default function LicenseNotice() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Open Source Licenses</Text>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.projectName}>Bluesky Social App</Text>
|
||||
<Text style={styles.license}>MIT License</Text>
|
||||
<Text style={styles.copyright}>Copyright 2023–2025 Bluesky Social PBC</Text>
|
||||
|
||||
<Text style={styles.licenseText}>
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
</Text>
|
||||
|
||||
<Text style={styles.licenseText}>
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
</Text>
|
||||
|
||||
<Text style={styles.licenseText}>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
</Text>
|
||||
|
||||
<Pressable
|
||||
onPress={() =>
|
||||
Linking.openURL('https://github.com/bluesky-social/social-app')
|
||||
}>
|
||||
<Text style={styles.link}>View Source Code</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 16,
|
||||
},
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 20,
|
||||
color: '#1d1d1f',
|
||||
},
|
||||
section: {
|
||||
marginBottom: 24,
|
||||
padding: 16,
|
||||
backgroundColor: '#f5f5f7',
|
||||
borderRadius: 8,
|
||||
},
|
||||
projectName: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
marginBottom: 8,
|
||||
color: '#1d1d1f',
|
||||
},
|
||||
license: {
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
color: '#007aff',
|
||||
marginBottom: 4,
|
||||
},
|
||||
copyright: {
|
||||
fontSize: 13,
|
||||
color: '#3a3a3c',
|
||||
marginBottom: 12,
|
||||
},
|
||||
licenseText: {
|
||||
fontSize: 12,
|
||||
lineHeight: 18,
|
||||
color: '#3a3a3c',
|
||||
marginBottom: 12,
|
||||
},
|
||||
link: {
|
||||
fontSize: 14,
|
||||
color: '#007aff',
|
||||
textDecorationLine: 'underline',
|
||||
marginTop: 8,
|
||||
},
|
||||
})
|
||||
163
ios/PrivacyContent.tsx
Normal file
163
ios/PrivacyContent.tsx
Normal file
@@ -0,0 +1,163 @@
|
||||
import React from 'react'
|
||||
import {View, Text, StyleSheet, Pressable, Linking} from 'react-native'
|
||||
|
||||
interface PrivacyContentProps {
|
||||
onLinkPress?: (url: string) => void
|
||||
}
|
||||
|
||||
export default function PrivacyContent({onLinkPress}: PrivacyContentProps) {
|
||||
const handleLinkPress = (url: string) => {
|
||||
if (onLinkPress) {
|
||||
onLinkPress(url)
|
||||
} else {
|
||||
Linking.openURL(url)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Introduction</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
This Privacy Policy explains how this AT Protocol client application
|
||||
(hereinafter referred to as "the App") handles personal information.
|
||||
Please read this policy carefully before using the App.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Information We Collect</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
The App may collect and use the following information:
|
||||
</Text>
|
||||
|
||||
<Text style={styles.subTitle}>1. Information Collected Automatically</Text>
|
||||
<View style={styles.list}>
|
||||
<Text style={styles.listItem}>• Device information (model, OS version)</Text>
|
||||
<Text style={styles.listItem}>• App usage data (sessions, features used)</Text>
|
||||
<Text style={styles.listItem}>• Crash logs and performance data</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.subTitle}>2. Information Provided by Users</Text>
|
||||
<View style={styles.list}>
|
||||
<Text style={styles.listItem}>
|
||||
• DID (Decentralized Identifier) and handle for authentication
|
||||
</Text>
|
||||
<Text style={styles.listItem}>• Posts, media, and social interactions</Text>
|
||||
<Text style={styles.listItem}>• Profile information (avatar, display name, bio)</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.highlight}>
|
||||
<Text style={styles.highlightText}>
|
||||
Important: Your data is stored on your chosen PDS (Personal Data Server).
|
||||
This app does not store your content on our servers.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>How We Use Your Information</Text>
|
||||
<View style={styles.list}>
|
||||
<Text style={styles.listItem}>
|
||||
• To provide AT Protocol social networking features
|
||||
</Text>
|
||||
<Text style={styles.listItem}>• To improve app performance and user experience</Text>
|
||||
<Text style={styles.listItem}>• To diagnose and fix technical issues</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Data Sharing</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
The App interacts with your chosen PDS and AppView services. Your posts and
|
||||
profile information are shared according to the AT Protocol specification and
|
||||
your privacy settings.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Your Rights</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
You have the right to access, modify, or delete your data through your PDS.
|
||||
You can also switch to a different PDS at any time while maintaining your
|
||||
identity.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Contact</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
For questions about this Privacy Policy, please contact:
|
||||
</Text>
|
||||
<Pressable onPress={() => handleLinkPress('https://syu.is')}>
|
||||
<Text style={styles.link}>https://syu.is</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.lastUpdated}>Last Updated: December 3, 2025</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
section: {
|
||||
marginBottom: 24,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '600',
|
||||
color: '#1d1d1f',
|
||||
marginBottom: 12,
|
||||
},
|
||||
subTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
color: '#1d1d1f',
|
||||
marginTop: 12,
|
||||
marginBottom: 8,
|
||||
},
|
||||
paragraph: {
|
||||
fontSize: 15,
|
||||
lineHeight: 22,
|
||||
color: '#3a3a3c',
|
||||
marginBottom: 8,
|
||||
},
|
||||
list: {
|
||||
marginLeft: 8,
|
||||
marginTop: 8,
|
||||
},
|
||||
listItem: {
|
||||
fontSize: 15,
|
||||
lineHeight: 24,
|
||||
color: '#3a3a3c',
|
||||
},
|
||||
highlight: {
|
||||
backgroundColor: '#fff3cd',
|
||||
borderLeftWidth: 4,
|
||||
borderLeftColor: '#ffc107',
|
||||
padding: 12,
|
||||
marginTop: 12,
|
||||
borderRadius: 4,
|
||||
},
|
||||
highlightText: {
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
color: '#856404',
|
||||
},
|
||||
link: {
|
||||
fontSize: 15,
|
||||
color: '#007aff',
|
||||
textDecorationLine: 'underline',
|
||||
marginTop: 8,
|
||||
},
|
||||
lastUpdated: {
|
||||
fontSize: 13,
|
||||
color: '#8e8e93',
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
})
|
||||
42
ios/PrivacyPolicy.screen.tsx
Normal file
42
ios/PrivacyPolicy.screen.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {
|
||||
type CommonNavigatorParams,
|
||||
type NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {s} from '#/lib/styles'
|
||||
import {useSetMinimalShellMode} from '#/state/shell'
|
||||
import {ScrollView} from '#/view/com/util/Views'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {ViewHeader} from '../com/util/ViewHeader'
|
||||
import PrivacyContent from '#/components/custom/PrivacyContent'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PrivacyPolicy'>
|
||||
export const PrivacyPolicyScreen = (_props: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const {_} = useLingui()
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
return (
|
||||
<Layout.Screen>
|
||||
<ViewHeader title={_(msg`Privacy Policy`)} />
|
||||
<ScrollView style={[s.hContentRegion, pal.view]}>
|
||||
<View style={[s.p20]}>
|
||||
<PrivacyContent />
|
||||
</View>
|
||||
<View style={s.footerSpacer} />
|
||||
</ScrollView>
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
38
ios/Support.screen.tsx
Normal file
38
ios/Support.screen.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import React from 'react'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {
|
||||
type CommonNavigatorParams,
|
||||
type NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {s} from '#/lib/styles'
|
||||
import {useSetMinimalShellMode} from '#/state/shell'
|
||||
import {ViewHeader} from '#/view/com/util/ViewHeader'
|
||||
import {ScrollView} from '#/view/com/util/Views'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import AppInfo from '#/components/custom/AppInfo'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Support'>
|
||||
export const SupportScreen = (_props: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {_} = useLingui()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
return (
|
||||
<Layout.Screen>
|
||||
<ViewHeader title={_(msg`App Info`)} />
|
||||
<ScrollView style={[s.hContentRegion, pal.view]}>
|
||||
<AppInfo />
|
||||
</ScrollView>
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
9
ios/app.config.patch.js
Normal file
9
ios/app.config.patch.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// Aiat app configuration overrides
|
||||
module.exports = {
|
||||
name: 'Aiat',
|
||||
slug: 'aiat',
|
||||
scheme: 'aiat',
|
||||
owner: 'syui', // Your Expo account
|
||||
bundleIdentifier: 'ai.syui.at',
|
||||
// Icon will be set separately
|
||||
}
|
||||
44
ios/bin/build.zsh
Executable file
44
ios/bin/build.zsh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/zsh
|
||||
set -e
|
||||
|
||||
d=~/ai/at/repos/social-app
|
||||
APP_NAME=Aiat
|
||||
PKG=aiat
|
||||
TEAM_NAME=
|
||||
TEAM_ID=
|
||||
CERT="Apple Distribution: ${TEAM_NAME} (${TEAM_ID})"
|
||||
MAIL=user@example.com
|
||||
KEY_CHAIN=EXAMPLE
|
||||
|
||||
cd $d
|
||||
# npx expo prebuild --clean
|
||||
# cd ios && pod install && cd ..
|
||||
|
||||
## アーカイブ
|
||||
xcodebuild -workspace ios/${PKG}.xcworkspace \
|
||||
-scheme ${PKG} \
|
||||
-configuration Release \
|
||||
-archivePath build/${APP_NAME}.xcarchive \
|
||||
-allowProvisioningUpdates \
|
||||
archive
|
||||
|
||||
cd build
|
||||
|
||||
# IPA作成
|
||||
rm -rf Payload ${APP_NAME}.ipa
|
||||
mkdir -p Payload
|
||||
cp -R ${APP_NAME}.xcarchive/Products/Applications/${PKG}.app Payload/
|
||||
cp ../store.mobileprovision Payload/${PKG}.app/embedded.mobileprovision
|
||||
|
||||
# entitlements抽出
|
||||
security cms -D -i Payload/${PKG}.app/embedded.mobileprovision > /tmp/profile.plist
|
||||
/usr/libexec/PlistBuddy -x -c "Print :Entitlements" /tmp/profile.plist > /tmp/entitlements.plist
|
||||
|
||||
codesign -f -s "$CERT" Payload/${PKG}.app/Frameworks/*.framework 2>/dev/null || true
|
||||
codesign -f -s "$CERT" --entitlements /tmp/entitlements.plist Payload/${PKG}.app
|
||||
|
||||
zip -r ${APP_NAME}.ipa Payload
|
||||
|
||||
xcrun altool --upload-app -f ${APP_NAME}.ipa -t ios -u "${MAIL}" -p "@keychain:${KEY_CHAIN}"
|
||||
|
||||
echo "Upload complete"
|
||||
86
ios/bin/install.zsh
Normal file
86
ios/bin/install.zsh
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/bin/zsh
|
||||
|
||||
if [ "$1" = "social-app-custom" ];then
|
||||
at-social-app-custom-pages
|
||||
at-social-app-custom-screens
|
||||
at-social-app-aiat-config
|
||||
at-social-app-aiat-logo
|
||||
at-origin-social-app
|
||||
exit
|
||||
fi
|
||||
|
||||
function at-social-app-custom-pages() {
|
||||
d_=$d/repos/social-app
|
||||
custom=$d/social-app-custom
|
||||
|
||||
echo "copying custom components to social-app"
|
||||
|
||||
# Create components directory if not exists
|
||||
mkdir -p ${d_}/src/components/custom
|
||||
|
||||
# Copy custom components
|
||||
cp ${custom}/PrivacyContent.tsx ${d_}/src/components/custom/
|
||||
cp ${custom}/AppInfo.tsx ${d_}/src/components/custom/
|
||||
|
||||
echo "custom components copied successfully"
|
||||
}
|
||||
|
||||
function at-social-app-aiat-config() {
|
||||
d_=$d/repos/social-app
|
||||
custom=$d/social-app-custom
|
||||
|
||||
echo "applying Aiat configuration"
|
||||
|
||||
# Update app.config.js
|
||||
cd ${d_}
|
||||
|
||||
# Backup original
|
||||
cp app.config.js app.config.js.orig
|
||||
|
||||
# Apply changes using sed
|
||||
sed -i "s/name: 'Bluesky'/name: 'Aiat'/g" app.config.js
|
||||
sed -i "s/slug: 'bluesky'/slug: 'aiat'/g" app.config.js
|
||||
sed -i "s/scheme: 'bluesky'/scheme: 'aiat'/g" app.config.js
|
||||
sed -i "s/owner: 'blueskysocial'/owner: 'syui'/g" app.config.js
|
||||
sed -i "s/bundleIdentifier: 'xyz.blueskyweb.app'/bundleIdentifier: 'ai.syui.at'/g" app.config.js
|
||||
|
||||
# Update package.json name
|
||||
sed -i 's/"name": "bsky.app"/"name": "aiat"/g' package.json
|
||||
|
||||
echo "Aiat configuration applied"
|
||||
}
|
||||
|
||||
function at-social-app-aiat-logo() {
|
||||
d_=$d/repos/social-app
|
||||
custom=$d/social-app-custom
|
||||
|
||||
echo "applying Aiat logo"
|
||||
|
||||
# Create logo directory if not exists
|
||||
mkdir -p ${custom}/assets
|
||||
|
||||
# Copy logo if exists in custom folder
|
||||
if [ -f ${custom}/assets/icon.png ]; then
|
||||
cp ${custom}/assets/icon.png ${d_}/assets/app-icons/ios_icon_default_next.png
|
||||
echo "Aiat logo applied"
|
||||
else
|
||||
echo "Warning: Logo file not found at ${custom}/assets/icon.png"
|
||||
echo "Please add your logo file there"
|
||||
fi
|
||||
}
|
||||
|
||||
function at-social-app-custom-screens() {
|
||||
d_=$d/repos/social-app
|
||||
custom=$d/social-app-custom
|
||||
|
||||
echo "applying custom screens"
|
||||
|
||||
# Copy custom screen files
|
||||
cp ${custom}/PrivacyPolicy.screen.tsx ${d_}/src/view/screens/PrivacyPolicy.tsx
|
||||
cp ${custom}/Support.screen.tsx ${d_}/src/view/screens/Support.tsx
|
||||
cp ${custom}/LicenseNotice.tsx ${d_}/src/components/custom/
|
||||
|
||||
echo "custom screens applied"
|
||||
}
|
||||
|
||||
|
||||
0
patching/.keep
Normal file
0
patching/.keep
Normal file
119
patching/120-ozone-runtimeEnvVars.diff
Normal file
119
patching/120-ozone-runtimeEnvVars.diff
Normal file
@@ -0,0 +1,119 @@
|
||||
diff --git a/app/layout.tsx b/app/layout.tsx
|
||||
index bfc3470..9350629 100644
|
||||
--- a/app/layout.tsx
|
||||
+++ b/app/layout.tsx
|
||||
@@ -5,6 +5,7 @@ import 'yet-another-react-lightbox/styles.css'
|
||||
import 'yet-another-react-lightbox/plugins/thumbnails.css'
|
||||
import 'yet-another-react-lightbox/plugins/captions.css'
|
||||
import { ToastContainer } from 'react-toastify'
|
||||
+import { PublicEnvScript } from 'next-runtime-env';
|
||||
|
||||
import { Shell } from '@/shell/Shell'
|
||||
import { CommandPaletteRoot } from '@/shell/CommandPalette/Root'
|
||||
@@ -36,6 +37,7 @@ export default function RootLayout({
|
||||
isDarkModeEnabled() ? 'dark' : ''
|
||||
}`}
|
||||
>
|
||||
+ <head>
|
||||
<title>Ozone</title>
|
||||
<link
|
||||
rel="icon"
|
||||
@@ -43,6 +45,8 @@ export default function RootLayout({
|
||||
sizes="any"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
+ <PublicEnvScript />
|
||||
+ </head>
|
||||
<body className="h-full overflow-hidden">
|
||||
<ToastContainer
|
||||
position="bottom-right"
|
||||
diff --git a/environment.d.ts b/environment.d.ts
|
||||
index 7a47cc2..33ab29f 100644
|
||||
--- a/environment.d.ts
|
||||
+++ b/environment.d.ts
|
||||
@@ -9,6 +9,8 @@ declare global {
|
||||
NEXT_PUBLIC_OZONE_SERVICE_DID?: string // e.g. did:plc:xxx#atproto_labeler
|
||||
NEXT_PUBLIC_OZONE_PUBLIC_URL?: string // e.g. https://ozone.example.com (falls back to window.location.origin)
|
||||
NEXT_PUBLIC_SOCIAL_APP_URL?: string // e.g. https://bsky.app
|
||||
+ NEXT_PUBLIC_SOCIAL_APP_DOMAIN?: string // e.g. bsky.app
|
||||
+ NEXT_PUBLIC_HANDLE_RESOLVER_URL?: string // e.g. https://api.bsky.app
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/lib/constants.ts b/lib/constants.ts
|
||||
index fe7c0e8..c286ac6 100644
|
||||
--- a/lib/constants.ts
|
||||
+++ b/lib/constants.ts
|
||||
@@ -1,29 +1,32 @@
|
||||
+import { env } from 'next-runtime-env';
|
||||
+
|
||||
export const OAUTH_SCOPE = 'atproto transition:generic'
|
||||
|
||||
export const OZONE_SERVICE_DID =
|
||||
- process.env.NEXT_PUBLIC_OZONE_SERVICE_DID || undefined
|
||||
+ env('NEXT_PUBLIC_OZONE_SERVICE_DID') || undefined
|
||||
|
||||
export const OZONE_PUBLIC_URL =
|
||||
- process.env.NEXT_PUBLIC_OZONE_PUBLIC_URL || undefined
|
||||
+ env('NEXT_PUBLIC_OZONE_PUBLIC_URL') || undefined
|
||||
|
||||
export const PLC_DIRECTORY_URL =
|
||||
- process.env.NEXT_PUBLIC_PLC_DIRECTORY_URL ||
|
||||
+ env('NEXT_PUBLIC_PLC_DIRECTORY_URL') ||
|
||||
(process.env.NODE_ENV === 'development'
|
||||
? 'http://localhost:2582'
|
||||
: 'https://plc.directory')
|
||||
|
||||
-export const QUEUE_CONFIG = process.env.NEXT_PUBLIC_QUEUE_CONFIG || '{}'
|
||||
+export const QUEUE_CONFIG = env('NEXT_PUBLIC_QUEUE_CONFIG') || '{}'
|
||||
|
||||
-export const QUEUE_SEED = process.env.NEXT_PUBLIC_QUEUE_SEED || ''
|
||||
+export const QUEUE_SEED = env('NEXT_PUBLIC_QUEUE_SEED') || ''
|
||||
|
||||
+export const SOCIAL_APP_DOMAIN = env('NEXT_PUBLIC_SOCIAL_APP_DOMAIN') || 'bsky.app'
|
||||
export const SOCIAL_APP_URL =
|
||||
- process.env.NEXT_PUBLIC_SOCIAL_APP_URL ||
|
||||
+ env('NEXT_PUBLIC_SOCIAL_APP_URL') ||
|
||||
(process.env.NODE_ENV === 'development'
|
||||
? 'http://localhost:2584'
|
||||
- : 'https://bsky.app')
|
||||
+ : `https://${SOCIAL_APP_DOMAIN}`)
|
||||
|
||||
export const HANDLE_RESOLVER_URL =
|
||||
- process.env.NEXT_PUBLIC_HANDLE_RESOLVER_URL ||
|
||||
+ env('NEXT_PUBLIC_HANDLE_RESOLVER_URL') ||
|
||||
(process.env.NODE_ENV === 'development'
|
||||
? 'http://localhost:2584'
|
||||
: 'https://api.bsky.app')
|
||||
diff --git a/lib/util.ts b/lib/util.ts
|
||||
index 0aa4460..ecec7d1 100644
|
||||
--- a/lib/util.ts
|
||||
+++ b/lib/util.ts
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CollectionId } from '@/reports/helpers/subject'
|
||||
-import { SOCIAL_APP_URL } from './constants'
|
||||
+import { SOCIAL_APP_URL, SOCIAL_APP_DOMAIN } from './constants'
|
||||
import { AtUri } from '@atproto/api'
|
||||
|
||||
export function classNames(...classes: (string | undefined)[]) {
|
||||
@@ -57,7 +57,7 @@ export function takesKeyboardEvt(el?: EventTarget | null) {
|
||||
)
|
||||
}
|
||||
|
||||
-const blueSkyUrlMatcher = new RegExp('(https?://)?.*bsky.app')
|
||||
+const blueSkyUrlMatcher = new RegExp('(https?://)?.*'+ `${SOCIAL_APP_DOMAIN}`)
|
||||
|
||||
export const isBlueSkyAppUrl = (url: string) => blueSkyUrlMatcher.test(url)
|
||||
|
||||
diff --git a/package.json b/package.json
|
||||
index 8919841..750dce9 100644
|
||||
--- a/package.json
|
||||
+++ b/package.json
|
||||
@@ -37,6 +37,7 @@
|
||||
"kbar": "^0.1.0-beta.45",
|
||||
"lande": "^1.0.10",
|
||||
"next": "15.2.4",
|
||||
+ "next-runtime-env": "^3.2.1",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-dropzone": "^14.3.5",
|
||||
99
patching/121-ozone-constants-fix.patch
Normal file
99
patching/121-ozone-constants-fix.patch
Normal file
@@ -0,0 +1,99 @@
|
||||
--- a/lib/constants.ts
|
||||
+++ b/lib/constants.ts
|
||||
@@ -1,29 +1,32 @@
|
||||
+import { env } from 'next-runtime-env';
|
||||
+
|
||||
export const OAUTH_SCOPE = 'atproto transition:generic transition:chat.bsky'
|
||||
|
||||
export const OZONE_SERVICE_DID =
|
||||
- process.env.NEXT_PUBLIC_OZONE_SERVICE_DID || undefined
|
||||
+ env('NEXT_PUBLIC_OZONE_SERVICE_DID') || undefined
|
||||
|
||||
export const OZONE_PUBLIC_URL =
|
||||
- process.env.NEXT_PUBLIC_OZONE_PUBLIC_URL || undefined
|
||||
+ env('NEXT_PUBLIC_OZONE_PUBLIC_URL') || undefined
|
||||
|
||||
export const PLC_DIRECTORY_URL =
|
||||
- process.env.NEXT_PUBLIC_PLC_DIRECTORY_URL ||
|
||||
+ env('NEXT_PUBLIC_PLC_DIRECTORY_URL') ||
|
||||
(process.env.NODE_ENV === 'development'
|
||||
? 'http://localhost:2582'
|
||||
: 'https://plc.directory')
|
||||
|
||||
-export const QUEUE_CONFIG = process.env.NEXT_PUBLIC_QUEUE_CONFIG || '{}'
|
||||
+export const QUEUE_CONFIG = env('NEXT_PUBLIC_QUEUE_CONFIG') || '{}'
|
||||
|
||||
-export const QUEUE_SEED = process.env.NEXT_PUBLIC_QUEUE_SEED || ''
|
||||
+export const QUEUE_SEED = env('NEXT_PUBLIC_QUEUE_SEED') || ''
|
||||
|
||||
+export const SOCIAL_APP_DOMAIN = env('NEXT_PUBLIC_SOCIAL_APP_DOMAIN') || 'bsky.app'
|
||||
export const SOCIAL_APP_URL =
|
||||
- process.env.NEXT_PUBLIC_SOCIAL_APP_URL ||
|
||||
+ env('NEXT_PUBLIC_SOCIAL_APP_URL') ||
|
||||
(process.env.NODE_ENV === 'development'
|
||||
? 'http://localhost:2584'
|
||||
- : 'https://bsky.app')
|
||||
+ : `https://${SOCIAL_APP_DOMAIN}`)
|
||||
|
||||
export const HANDLE_RESOLVER_URL =
|
||||
- process.env.NEXT_PUBLIC_HANDLE_RESOLVER_URL ||
|
||||
+ env('NEXT_PUBLIC_HANDLE_RESOLVER_URL') ||
|
||||
(process.env.NODE_ENV === 'development'
|
||||
? 'http://localhost:2584'
|
||||
: 'https://api.bsky.app')
|
||||
@@ -36,25 +39,25 @@
|
||||
|
||||
export const NEW_ACCOUNT_MARKER_THRESHOLD_IN_DAYS = process.env
|
||||
.NEXT_PUBLIC_NEW_ACCOUNT_MARKER_THRESHOLD_IN_DAYS
|
||||
- ? parseInt(process.env.NEXT_PUBLIC_NEW_ACCOUNT_MARKER_THRESHOLD_IN_DAYS)
|
||||
+ ? parseInt(env('NEXT_PUBLIC_NEW_ACCOUNT_MARKER_THRESHOLD_IN_DAYS'))
|
||||
: 7
|
||||
|
||||
export const YOUNG_ACCOUNT_MARKER_THRESHOLD_IN_DAYS = process.env
|
||||
.NEXT_PUBLIC_YOUNG_ACCOUNT_MARKER_THRESHOLD_IN_DAYS
|
||||
- ? parseInt(process.env.NEXT_PUBLIC_YOUNG_ACCOUNT_MARKER_THRESHOLD_IN_DAYS)
|
||||
+ ? parseInt(env('NEXT_PUBLIC_YOUNG_ACCOUNT_MARKER_THRESHOLD_IN_DAYS'))
|
||||
: 30
|
||||
|
||||
export const DOMAINS_ALLOWING_EMAIL_COMMUNICATION = (
|
||||
- process.env.NEXT_PUBLIC_DOMAINS_ALLOWING_EMAIL_COMMUNICATION || ''
|
||||
+ env('NEXT_PUBLIC_DOMAINS_ALLOWING_EMAIL_COMMUNICATION') || ''
|
||||
).split(',')
|
||||
|
||||
export const HIGH_PROFILE_FOLLOWER_THRESHOLD = process.env
|
||||
.NEXT_PUBLIC_HIGH_PROFILE_FOLLOWER_THRESHOLD
|
||||
- ? parseInt(process.env.NEXT_PUBLIC_HIGH_PROFILE_FOLLOWER_THRESHOLD)
|
||||
+ ? parseInt(env('NEXT_PUBLIC_HIGH_PROFILE_FOLLOWER_THRESHOLD'))
|
||||
: Infinity
|
||||
|
||||
export const FALLBACK_VIDEO_URL = (
|
||||
- process.env.NEXT_PUBLIC_FALLBACK_VIDEO_URL || ''
|
||||
+ env('NEXT_PUBLIC_FALLBACK_VIDEO_URL') || ''
|
||||
).split(':')
|
||||
|
||||
// strike to account suspension duration mapping (in hours)
|
||||
@@ -87,18 +90,18 @@
|
||||
|
||||
export const STRIKE_TO_SUSPENSION_DURATION_IN_HOURS =
|
||||
parseStrikeSuspensionConfig(
|
||||
- process.env.NEXT_PUBLIC_STRIKE_SUSPENSION_CONFIG || '',
|
||||
+ env('NEXT_PUBLIC_STRIKE_SUSPENSION_CONFIG') || '',
|
||||
)
|
||||
|
||||
export const AUTOMATED_ACTION_EMAIL_IDS = {
|
||||
warningWithTakedown:
|
||||
- process.env.NEXT_PUBLIC_WARNING_WITH_TAKEDOWN_EMAIL_TEMPLATE_ID,
|
||||
+ env('NEXT_PUBLIC_WARNING_WITH_TAKEDOWN_EMAIL_TEMPLATE_ID'),
|
||||
suspensionWithTakedown:
|
||||
- process.env.NEXT_PUBLIC_SUSPENSION_WITH_TAKEDOWN_EMAIL_TEMPLATE_ID,
|
||||
+ env('NEXT_PUBLIC_SUSPENSION_WITH_TAKEDOWN_EMAIL_TEMPLATE_ID'),
|
||||
suspensionWithoutTakedown:
|
||||
- process.env.NEXT_PUBLIC_SUSPENSION_WITHOUT_TAKEDOWN_EMAIL_TEMPLATE_ID,
|
||||
+ env('NEXT_PUBLIC_SUSPENSION_WITHOUT_TAKEDOWN_EMAIL_TEMPLATE_ID'),
|
||||
permanentTakedown:
|
||||
- process.env.NEXT_PUBLIC_PERMANENT_TAKEDOWN_EMAIL_TEMPLATE_ID,
|
||||
+ env('NEXT_PUBLIC_PERMANENT_TAKEDOWN_EMAIL_TEMPLATE_ID'),
|
||||
takedownWithoutStrike:
|
||||
- process.env.NEXT_PUBLIC_TAKEDOWN_WITHOUT_STRIKE_EMAIL_TEMPLATE_ID,
|
||||
+ env('NEXT_PUBLIC_TAKEDOWN_WITHOUT_STRIKE_EMAIL_TEMPLATE_ID'),
|
||||
}
|
||||
82
patching/122-ozone-enable-daemon.diff
Normal file
82
patching/122-ozone-enable-daemon.diff
Normal file
@@ -0,0 +1,82 @@
|
||||
diff --git a/service/index.js b/service/index.js
|
||||
index 943c281..7721cd9 100644
|
||||
--- a/service/index.js
|
||||
+++ b/service/index.js
|
||||
@@ -1,5 +1,7 @@
|
||||
const next = require('next')
|
||||
-const {
|
||||
+const ozone = require('@atproto/ozone')
|
||||
+/*
|
||||
+{
|
||||
readEnv,
|
||||
httpLogger,
|
||||
envToCfg,
|
||||
@@ -7,6 +9,7 @@ const {
|
||||
OzoneService,
|
||||
Database,
|
||||
} = require('@atproto/ozone')
|
||||
+*/
|
||||
const pkg = require('@atproto/ozone/package.json')
|
||||
|
||||
async function main() {
|
||||
@@ -16,37 +19,48 @@ async function main() {
|
||||
const frontendHandler = frontend.getRequestHandler()
|
||||
await frontend.prepare()
|
||||
// backend
|
||||
- const env = readEnv()
|
||||
+ const env = ozone.readEnv()
|
||||
env.version ??= pkg.version
|
||||
- const config = envToCfg(env)
|
||||
- const secrets = envToSecrets(env)
|
||||
+ const config = ozone.envToCfg(env)
|
||||
+ const secrets = ozone.envToSecrets(env)
|
||||
const migrate = process.env.OZONE_DB_MIGRATE === '1'
|
||||
if (migrate) {
|
||||
- const db = new Database({
|
||||
+ const db = new ozone.Database({
|
||||
url: config.db.postgresUrl,
|
||||
schema: config.db.postgresSchema,
|
||||
})
|
||||
await db.migrateToLatestOrThrow()
|
||||
await db.close()
|
||||
}
|
||||
- const ozone = await OzoneService.create(config, secrets)
|
||||
+ const server = await ozone.OzoneService.create(config, secrets)
|
||||
// setup handlers
|
||||
- ozone.app.get('/.well-known/ozone-metadata.json', (_req, res) => {
|
||||
+ server.app.get('/.well-known/ozone-metadata.json', (_req, res) => {
|
||||
return res.json({
|
||||
- did: ozone.ctx.cfg.service.did,
|
||||
- url: ozone.ctx.cfg.service.publicUrl,
|
||||
- publicKey: ozone.ctx.signingKey.did(),
|
||||
+ did: server.ctx.cfg.service.did,
|
||||
+ url: server.ctx.cfg.service.publicUrl,
|
||||
+ publicKey: server.ctx.signingKey.did(),
|
||||
})
|
||||
})
|
||||
// Note: We must use `use()` here. This should be the last middleware.
|
||||
- ozone.app.use((req, res) => {
|
||||
+ server.app.use((req, res) => {
|
||||
void frontendHandler(req, res, undefined)
|
||||
})
|
||||
// run
|
||||
- const httpServer = await ozone.start()
|
||||
+ const httpServer = await server.start()
|
||||
+ // starts: involve ops from atproto/packages/dev-env/src/ozone.ts >>>
|
||||
+ ozone.httpLogger.info('starts ozone daemon')
|
||||
+ const daemon = await ozone.OzoneDaemon.create(config, secrets)
|
||||
+ await daemon.start()
|
||||
+ //if (process.env.OZONE_ENABLE_EVENT_REVERSER != 'true') // atproto/services/ozone/daemon.js doesn't stop eventReverser
|
||||
+ //{
|
||||
+ // ozone.httpLogger.info('disable ozone daemon eventReverser')
|
||||
+ // await daemon.ctx.eventReverser.destroy()
|
||||
+ //}
|
||||
+ // ends: involve ops from atproto/packages/dev-env/src/ozone.ts <<<
|
||||
+
|
||||
/** @type {import('net').AddressInfo} */
|
||||
const addr = httpServer.address()
|
||||
- httpLogger.info(`Ozone is running at http://localhost:${addr.port}`)
|
||||
+ ozone.httpLogger.info(`Ozone is running at http://localhost:${addr.port}`)
|
||||
}
|
||||
|
||||
main().catch(console.error)
|
||||
28
patching/130-atproto-ozone-enable-daemon-v2.patch
Normal file
28
patching/130-atproto-ozone-enable-daemon-v2.patch
Normal file
@@ -0,0 +1,28 @@
|
||||
--- a/services/ozone/api.js
|
||||
+++ b/services/ozone/api.js
|
||||
@@ -23,6 +23,7 @@
|
||||
Database,
|
||||
OzoneService,
|
||||
envToCfg,
|
||||
+ OzoneDaemon,
|
||||
envToSecrets,
|
||||
httpLogger,
|
||||
readEnv,
|
||||
@@ -79,10 +80,17 @@
|
||||
|
||||
httpLogger.info('ozone is running')
|
||||
|
||||
+ // Start OzoneDaemon for label events
|
||||
+ httpLogger.info('starting ozone daemon')
|
||||
+ const daemon = await OzoneDaemon.create(cfg, secrets)
|
||||
+ await daemon.start()
|
||||
+ httpLogger.info('ozone daemon is running')
|
||||
+
|
||||
// Graceful shutdown (see also https://aws.amazon.com/blogs/containers/graceful-shutdowns-with-ecs/)
|
||||
process.on('SIGTERM', async () => {
|
||||
httpLogger.info('ozone is stopping')
|
||||
|
||||
+ await daemon.destroy()
|
||||
await ozone.destroy()
|
||||
|
||||
httpLogger.info('ozone is stopped')
|
||||
33
patching/130-atproto-ozone-enable-daemon.patch
Normal file
33
patching/130-atproto-ozone-enable-daemon.patch
Normal file
@@ -0,0 +1,33 @@
|
||||
--- a/services/ozone/api.js
|
||||
+++ b/services/ozone/api.js
|
||||
@@ -20,6 +20,7 @@ const {
|
||||
MultiImageInvalidator,
|
||||
} = require('@atproto/aws')
|
||||
const {
|
||||
Database,
|
||||
OzoneService,
|
||||
+ OzoneDaemon,
|
||||
envToCfg,
|
||||
envToSecrets,
|
||||
httpLogger,
|
||||
@@ -76,10 +77,17 @@ const main = async () => {
|
||||
const ozone = await OzoneService.create(cfg, secrets, { imgInvalidator })
|
||||
|
||||
await ozone.start()
|
||||
|
||||
httpLogger.info('ozone is running')
|
||||
|
||||
+ // Start OzoneDaemon for label events
|
||||
+ httpLogger.info('starting ozone daemon')
|
||||
+ const daemon = await OzoneDaemon.create(cfg, secrets)
|
||||
+ await daemon.start()
|
||||
+ httpLogger.info('ozone daemon is running')
|
||||
+
|
||||
// Graceful shutdown (see also https://aws.amazon.com/blogs/containers/graceful-shutdowns-with-ecs/)
|
||||
process.on('SIGTERM', async () => {
|
||||
httpLogger.info('ozone is stopping')
|
||||
|
||||
+ await daemon.destroy()
|
||||
await ozone.destroy()
|
||||
|
||||
httpLogger.info('ozone is stopped')
|
||||
160
patching/4367-atproto-services-bsky-api.diff
Normal file
160
patching/4367-atproto-services-bsky-api.diff
Normal file
@@ -0,0 +1,160 @@
|
||||
--- a/services/bsky/api.js 2025-12-03 11:04:54
|
||||
+++ b/services/bsky/api.js 2025-12-03 11:00:02
|
||||
@@ -1,62 +1,105 @@
|
||||
/* eslint-env node */
|
||||
/* eslint-disable import/order */
|
||||
-
|
||||
+// https://github.com/bluesky-social/atproto/blob/main/services/bsky/api.js
|
||||
'use strict'
|
||||
|
||||
-const dd = require('dd-trace')
|
||||
+//const dd = require('dd-trace')
|
||||
+//
|
||||
+//dd.tracer
|
||||
+// .init()
|
||||
+// .use('http2', {
|
||||
+// client: true, // calls into dataplane
|
||||
+// server: false,
|
||||
+// })
|
||||
+// .use('express', {
|
||||
+// hooks: {
|
||||
+// request: (span, req) => {
|
||||
+// maintainXrpcResource(span, req)
|
||||
+// },
|
||||
+// },
|
||||
+// })
|
||||
|
||||
-dd.tracer
|
||||
- .init()
|
||||
- .use('http2', {
|
||||
- client: true, // calls into dataplane
|
||||
- server: false,
|
||||
- })
|
||||
- .use('express', {
|
||||
- hooks: {
|
||||
- request: (span, req) => {
|
||||
- maintainXrpcResource(span, req)
|
||||
- },
|
||||
- },
|
||||
- })
|
||||
-
|
||||
// modify tracer in order to track calls to dataplane as a service with proper resource names
|
||||
const DATAPLANE_PREFIX = '/bsky.Service/'
|
||||
-const origStartSpan = dd.tracer._tracer.startSpan
|
||||
-dd.tracer._tracer.startSpan = function (name, options) {
|
||||
- if (
|
||||
- name !== 'http.request' ||
|
||||
- options?.tags?.component !== 'http2' ||
|
||||
- !options?.tags?.['http.url']
|
||||
- ) {
|
||||
- return origStartSpan.call(this, name, options)
|
||||
- }
|
||||
- const uri = new URL(options.tags['http.url'])
|
||||
- if (!uri.pathname.startsWith(DATAPLANE_PREFIX)) {
|
||||
- return origStartSpan.call(this, name, options)
|
||||
- }
|
||||
- options.tags['service.name'] = 'dataplane-bsky'
|
||||
- options.tags['resource.name'] = uri.pathname.slice(DATAPLANE_PREFIX.length)
|
||||
- return origStartSpan.call(this, name, options)
|
||||
-}
|
||||
+//const origStartSpan = dd.tracer._tracer.startSpan
|
||||
+//dd.tracer._tracer.startSpan = function (name, options) {
|
||||
+// if (
|
||||
+// name !== 'http.request' ||
|
||||
+// options?.tags?.component !== 'http2' ||
|
||||
+// !options?.tags?.['http.url']
|
||||
+// ) {
|
||||
+// return origStartSpan.call(this, name, options)
|
||||
+// }
|
||||
+// const uri = new URL(options.tags['http.url'])
|
||||
+// if (!uri.pathname.startsWith(DATAPLANE_PREFIX)) {
|
||||
+// return origStartSpan.call(this, name, options)
|
||||
+// }
|
||||
+// options.tags['service.name'] = 'dataplane-bsky'
|
||||
+// options.tags['resource.name'] = uri.pathname.slice(DATAPLANE_PREFIX.length)
|
||||
+// return origStartSpan.call(this, name, options)
|
||||
+//}
|
||||
|
||||
// Tracer code above must come before anything else
|
||||
const assert = require('node:assert')
|
||||
const cluster = require('node:cluster')
|
||||
const path = require('node:path')
|
||||
|
||||
-const { BskyAppView, ServerConfig } = require('@atproto/bsky')
|
||||
-const { Secp256k1Keypair } = require('@atproto/crypto')
|
||||
+const bsky = require('/app/packages/bsky') // import all bsky features
|
||||
+const { Secp256k1Keypair } = require('/app/packages/crypto')
|
||||
|
||||
const main = async () => {
|
||||
const env = getEnv()
|
||||
- const config = ServerConfig.readEnv()
|
||||
+ const config = bsky.ServerConfig.readEnv()
|
||||
assert(env.serviceSigningKey, 'must set BSKY_SERVICE_SIGNING_KEY')
|
||||
const signingKey = await Secp256k1Keypair.import(env.serviceSigningKey)
|
||||
- const bsky = BskyAppView.create({ config, signingKey })
|
||||
- await bsky.start()
|
||||
+
|
||||
+// starts: involve logics in packages/dev-env/src/bsky.ts >>>>>>>>>>>>>
|
||||
+// Separate migration db in case migration changes some connection state that we need in the tests, e.g. "alter database ... set ..."
|
||||
+ const migrationDb = new bsky.Database({
|
||||
+ url: env.dbPostgresUrl,
|
||||
+ schema: env.dbPostgresSchema,
|
||||
+ })
|
||||
+ if (env.migration) {
|
||||
+ await migrationDb.migrateToOrThrow(env.migration)
|
||||
+ } else {
|
||||
+ await migrationDb.migrateToLatestOrThrow()
|
||||
+ }
|
||||
+ await migrationDb.close()
|
||||
+
|
||||
+ const db = new bsky.Database({
|
||||
+ url: env.dbPostgresUrl,
|
||||
+ schema: env.dbPostgresSchema,
|
||||
+ poolSize: 10,
|
||||
+ })
|
||||
+
|
||||
+ const dataplane = await bsky.DataPlaneServer.create(
|
||||
+ db,
|
||||
+ env.dataplanePort,
|
||||
+ config.didPlcUrl
|
||||
+ )
|
||||
+
|
||||
+ const bsync = await bsky.MockBsync.create(db, env.bsyncPort)
|
||||
+
|
||||
+// ends: involve logics in packages/dev-env/src/bsky.ts <<<<<<<<<<<<<
|
||||
+
|
||||
+ const server = bsky.BskyAppView.create({ config, signingKey })
|
||||
+// starts: involve logics in packages/dev-env/src/bsky.ts >>>>>>>>>>>>>
|
||||
+ const sub = new bsky.RepoSubscription({
|
||||
+ service: env.repoProvider,
|
||||
+ db,
|
||||
+ idResolver: dataplane.idResolver,
|
||||
+ background: new bsky.BackgroundQueue(db),
|
||||
+ })
|
||||
+// ends: involve logics in packages/dev-env/src/bsky.ts <<<<<<<<<<<<<
|
||||
+ await server.start()
|
||||
+ sub.start() // involve logics in packages/dev-env/src/bsky.ts
|
||||
// Graceful shutdown (see also https://aws.amazon.com/blogs/containers/graceful-shutdowns-with-ecs/)
|
||||
const shutdown = async () => {
|
||||
- await bsky.destroy()
|
||||
+ await server.destroy()
|
||||
+ await bsync.destroy()
|
||||
+ await dataplane.destroy()
|
||||
+ await sub.destroy()
|
||||
+ await db.close()
|
||||
}
|
||||
process.on('SIGTERM', shutdown)
|
||||
process.on('disconnect', shutdown) // when clustering
|
||||
@@ -64,6 +107,12 @@
|
||||
|
||||
const getEnv = () => ({
|
||||
serviceSigningKey: process.env.BSKY_SERVICE_SIGNING_KEY || undefined,
|
||||
+ dbPostgresUrl: process.env.BSKY_DB_POSTGRES_URL || undefined,
|
||||
+ dbPostgresSchema: process.env.BSKY_DB_POSTGRES_SCHEMA || undefined,
|
||||
+ dataplanePort : maybeParseInt(process.env.BSKY_DATAPLANE_PORT) || undefined,
|
||||
+ bsyncPort : maybeParseInt(process.env.BSKY_BSYNC_PORT) || undefined,
|
||||
+ migration: process.env.ENABLE_MIGRATIONS === 'true' || undefined,
|
||||
+ repoProvider: process.env.BSKY_REPO_PROVIDER || undefined
|
||||
})
|
||||
|
||||
const maybeParseInt = (str) => {
|
||||
20
patching/4367-atproto-services-pds-index.diff
Normal file
20
patching/4367-atproto-services-pds-index.diff
Normal file
@@ -0,0 +1,20 @@
|
||||
--- a/services/pds/index.js 2025-12-03 11:04:54
|
||||
+++ b/services/pds/index.js 2025-12-02 22:11:39
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-env node */
|
||||
-
|
||||
+// https://github.com/bluesky-social/atproto/blob/main/services/pds/index.js
|
||||
'use strict'
|
||||
|
||||
const {
|
||||
@@ -8,8 +8,8 @@
|
||||
envToSecrets,
|
||||
httpLogger,
|
||||
readEnv,
|
||||
-} = require('@atproto/pds')
|
||||
-const pkg = require('@atproto/pds/package.json')
|
||||
+} = require('/app/packages/pds')
|
||||
+const pkg = require('/app/packages/pds/package.json')
|
||||
|
||||
const main = async () => {
|
||||
const env = readEnv()
|
||||
17
patching/8980-social-app-disable-external-services.diff
Normal file
17
patching/8980-social-app-disable-external-services.diff
Normal file
@@ -0,0 +1,17 @@
|
||||
--- a/src/state/geolocation/const.ts
|
||||
+++ b/src/state/geolocation/const.ts
|
||||
@@ -3,9 +3,10 @@ import {BAPP_CONFIG_DEV_URL, IS_DEV} from '#/env'
|
||||
import {type Device} from '#/storage'
|
||||
|
||||
export const IPCC_URL = `https://bsky.app/ipcc`
|
||||
-export const BAPP_CONFIG_URL_PROD = `https://ip.bsky.app/config`
|
||||
-export const BAPP_CONFIG_URL = IS_DEV
|
||||
- ? (BAPP_CONFIG_DEV_URL ?? BAPP_CONFIG_URL_PROD)
|
||||
- : BAPP_CONFIG_URL_PROD
|
||||
+// Disabled for self-hosted environment to avoid CORS errors
|
||||
+// export const BAPP_CONFIG_URL_PROD = `https://ip.bsky.app/config`
|
||||
+// export const BAPP_CONFIG_URL = IS_DEV
|
||||
+// ? (BAPP_CONFIG_DEV_URL ?? BAPP_CONFIG_URL_PROD)
|
||||
+// : BAPP_CONFIG_URL_PROD
|
||||
+export const BAPP_CONFIG_URL = null
|
||||
export const GEOLOCATION_CONFIG_URL = BAPP_CONFIG_URL
|
||||
44
patching/8980-social-app-disable-proxy.diff
Normal file
44
patching/8980-social-app-disable-proxy.diff
Normal file
@@ -0,0 +1,44 @@
|
||||
diff --git a/src/state/session/agent.ts b/src/state/session/agent.ts
|
||||
index 36d19299b..ba095436a 100644
|
||||
--- a/src/state/session/agent.ts
|
||||
+++ b/src/state/session/agent.ts
|
||||
@@ -39,7 +39,8 @@ export function createPublicAgent() {
|
||||
configureModerationForGuest() // Side effect but only relevant for tests
|
||||
|
||||
const agent = new BskyAppAgent({service: PUBLIC_BSKY_SERVICE})
|
||||
- agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Disable proxy for self-hosted environments
|
||||
+ // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
return agent
|
||||
}
|
||||
|
||||
@@ -77,7 +78,8 @@ export async function createAgentAndResume(
|
||||
}
|
||||
}
|
||||
|
||||
- agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Disable proxy for self-hosted environments
|
||||
+ // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
|
||||
return agent.prepare(gates, moderation, onSessionChange)
|
||||
}
|
||||
@@ -112,7 +114,8 @@ export async function createAgentAndLogin(
|
||||
const gates = tryFetchGates(account.did, 'prefer-fresh-gates')
|
||||
const moderation = configureModerationForAccount(agent, account)
|
||||
|
||||
- agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Disable proxy for self-hosted environments
|
||||
+ // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
|
||||
return agent.prepare(gates, moderation, onSessionChange)
|
||||
}
|
||||
@@ -201,7 +204,8 @@ export async function createAgentAndCreateAccount(
|
||||
logger.error(e, {message: `session: failed snoozeEmailConfirmationPrompt`})
|
||||
}
|
||||
|
||||
- agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
+ // Disable proxy for self-hosted environments
|
||||
+ // agent.configureProxy(BLUESKY_PROXY_HEADER.get())
|
||||
|
||||
return agent.prepare(gates, moderation, onSessionChange)
|
||||
}
|
||||
Reference in New Issue
Block a user