Amethyst
직접 관리하는 소셜 네트워크에 가입하고 Android용 가장 기능이 풍부한 Nostr 클라이언트
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Stage is a private, encrypted messenger built on XMTP, with group channels,
multi-account support, free onchain names and avatars (*.stage.base.eth on
Base), and a smart-account wallet (assets, balances, transfers, passkeys,
social recovery). It ships as one universal Expo app serving Android, iOS,
web and desktop from the same React Native codebase (web via
react-native-web), backed by a framework-agnostic TypeScript core, a
design-system kit, a Cloudflare Worker and a push-notification server.
Each workspace has its own README with details; CLAUDE.md is the
architecture guide.README 전문 보기 ↗Stage is a private, encrypted messenger built on XMTP, with group channels,
multi-account support, free onchain names and avatars (*.stage.base.eth on
Base), and a smart-account wallet (assets, balances, transfers,
recovery phrase backup). It ships as one universal Expo app serving Android, iOS,
web, desktop and a Chrome side-panel extension from the same React Native codebase (web via
react-native-web), backed by a framework-agnostic TypeScript core, a
design-system kit, a Cloudflare Worker and a push-notification server.
apps/
stage/ # stage — the universal Expo + React Native app (android · ios · web · desktop)
# app/ expo-router file routes (routes only — helpers live in components/)
# components/ kit-JSX screens + colocated *.model.ts pure models, one folder per family
# lib/ state + SDK orchestration (incl. the xmtp.*.web adapters and *.core.ts)
# modules/ messaging/ (rows, queries, feed, consent; no barrel) + the stage-pill native module
# platform/ storage seams (.ts native / .web.ts overrides)
# test/ pure-model tests (bun test)
# desktop/ Electron shell that bundles the web export (nested workspace)
# extension/ Chrome Manifest V3 shell around the same web export
proxy/ # Cloudflare Worker: link previews, image resize, x402, XMTP history/push relays,
# the *.stage.base.eth names service, user node publishing (/nodes), and the
# bundler.stage.box manifest proxy
dispatch/ # Cloudflare Workers dispatch (nodes.stage.box) and nodes-outbound: run the nodes users
# publish, each in its own Workers for Platforms sandbox (no node code in this repo)
push/ # XMTP notification server (upstream image, deployed to Fly as stage-push)
packages/
client/ # @stage-labs/client — framework-agnostic shared logic (XMTP cores + codecs,
# identity/names, wallet, accounts + zerodev, read-only APIs, x402)
kit/ # @stage-labs/kit — design system: tokens, icons, theme contracts,
# and one React Native component family (renders on web via RNW)
config/ # @stage-labs/config — shared TS/knip presets, oxlint JS plugins + the stage CLI
Each workspace has its own README with details; CLAUDE.md is the
architecture guide.
1.4.4 (pinned via the packageManager field) — the only package manager>= 22 (per the engines field)bun install
Run from the repo root:
bun run build # bun run --workspaces --if-present build (only the desktop shell has one)
bun run test # bun test --parallel: every test file in the repo, one run
bun run test:changed # only the test files affected by changes since origin/main
bun check # stage check (bun check per workspace)
bun run lint # stage lint (oxlint with type-aware rules over the whole repo)
bun run lint:fix # stage lint --fix
bun run lint:changed # lint only the files changed since the upstream branch
bun fmt # stage fmt (bun fmt with bunfig.toml [fmt])
bun fmt --check # fail when a file needs formatting (the first CI gate)
bun run knip # unused files / deps / exports
stage lint runs oxlint --type-aware with the root .oxlintrc.json: the
type-aware rules run through oxlint-tsgolint, and the rules oxlint does not
have natively (no comments, no em dash, stage/*, no-restricted-syntax)
run as JS plugins; quotes are left to bun fmt. import/no-cycle fails on circular imports. It skips git-ignored files. stage lint <paths>
lints only those paths. CI always runs the full lint, because a type change in
one file can create findings in another.
stage/no-custom-font-size requires named Kit font sizes in Stage's app,
components, lib, modules and platform JS/TS source. It checks object and
StyleSheet properties, assignments, JSX font-size props and CSS font declarations
in strings. Native inputs and Markdown body sizing can use FONT_SIZE or
fontSize() imported from Kit. Imported Kit Text (including aliases) must use
size, not a style override, even when that override contains a token. The check
follows local const aliases and destructuring, static computed keys, arrays,
spreads, branches and StyleSheet.create / flatten. Direct arithmetic writes
are rejected; destructuring reads are not declarations. CSS-like strings are
checked at declaration boundaries, not by matching ordinary prose. This is not
cross-module or runtime data-flow analysis of arbitrary wrappers, functions,
mutations, dynamic property keys or generated CSS. Kit's semantic Title, wallet
and computed Markdown styles, test fixtures and standalone HTML support pages
are outside this app rule. Existing Kit-specific lint rules still apply there.
The CLI/config regression suite lives in apps/stage/scripts/test, separate
from the app's pure-model test directory. Run it with
bun test apps/stage/scripts/test/typographyLint.test.mjs; bun run test includes it.
Bun runs the workspace tasks itself (no Turbo): bun run --workspaces for scripts
and one bun test --parallel for every test file.
Per-app dev servers and builds:
bun --cwd apps/stage start # Expo bundler (Metro)
bun --cwd apps/stage android # build + run on Android
bun --cwd apps/stage ios # build + run on iOS
bun --cwd apps/stage web # run the app in a browser
bun --cwd apps/stage run build:web # web export (Netlify publishes dist/, config in apps/stage/netlify.toml)
bun --cwd apps/proxy dev # Cloudflare Worker (wrangler dev)
bun --cwd apps/dispatch dev # the nodes.stage.box dispatch Worker (wrangler dev)
bun run --cwd apps/stage/desktop start # Electron desktop app with the bundled web UI
bun run --cwd packages/kit storybook # gallery of every kit component (Vite, port 6006)
apps/stage reads EXPO_PUBLIC_* vars at build time (inlined by Expo, so every
value is public). Set them in the Netlify site (web) and the EAS build profiles
(eas.json, mobile); secrets never go in eas.json or the repo.
| Var | Purpose |
|---|---|
EXPO_PUBLIC_ZERODEV_PROJECT_ID | ZeroDev smart-account project (Base) |
EXPO_PUBLIC_ZERODEV_RPC | Optional RPC override for the smart-account client |
EXPO_PUBLIC_LINKPROXY_URL | Base URL of the proxy Worker (default https://proxy.stage.box) |
EXPO_PUBLIC_PUSH_SERVER_URL | Push server base URL |
Attachments (already client-side encrypted) upload to the proxy Worker
(POST /attachments), which stores the ciphertext in the stage R2 bucket
as attachments/<random id> and serves it back from
proxy.stage.box/attachments/<id>. Messages from before the move carry Swarm
links (/bzz/<ref>/), which the app reads from the public Swarm gateway
(download.gateway.ethswarm.org).
Composer text over 4,096 UTF-8 bytes sends as message.txt through this same
encrypted attachment pipeline, in existing and new chats. This is a readability
cutoff, kept well below XMTP's message-size ceiling, not a transport maximum.
The file keeps the original Unicode, whitespace and newlines without trimming
or adding a BOM. Short messages keep their existing behavior. Picked attachments
and locations still follow the text, and a reply reference stays on the text file.
A failed file send restores the original draft; text that already sent is not
restored if a later attachment fails.
bun run build:web from apps/stage on every push to main.version in apps/stage/app.config.js triggers
release-mobile.yml (EAS Build + Submit to Play and TestFlight); every push
publishes a JS-OTA dev-client preview. See docs/mobile-release.md.release-desktop.yml, which builds the
macOS / Windows / Linux installers and publishes them to the GitHub Release
that the landing page links to. See docs/desktop-release.md.bun scripts/build-extension.mjs builds an unpacked beta. PR builds attach it as an Actions artifact, without publishing to the Chrome Web Store. See docs/chrome-extension.md.main (bun check and tests run first); deploy-nodes.yml deploys the dispatch and nodes-outbound Workers from GitHub Actions; deploy-push-server.yml deploys the push server.CI runs on every push to main and on pull requests (.github/workflows/ci.yml).
The gates, in
order, are: format → lint → check → knip → build → test, all on Bun
1.4.4 with a frozen lockfile.