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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The committed generated artifacts. They belong in the tree — a fresh clone
# needs no build step to run the CLI or read its reference — but they are
# output, so a review should not have to scroll them and the language
# statistics should not count them.
docs/api/dist/** linguist-generated=true
src/cli/generated/** linguist-generated=true
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ coverage/
/ios/EdgeApiSecret.h
/android/app/src/main/cpp/edge_api_secret.c
/android/app/src/main/cpp/edge_api_secret.h
/native/edge-api-signer/node/edge_api_secret.c
/native/edge-api-signer/node/edge_api_secret.h
/native/edge-api-signer/node/build/
/vendor/*.tgz
/vendor/edge-core-js-*.tgz
/*.tgz
Expand Down Expand Up @@ -143,3 +146,9 @@ yarn-error.log

# Maestro run output
/maestro/screenshots

# Edge CLI runtime
.edge-cli/

# Built CLI
/lib/
49 changes: 48 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ branches:
if: head_branch !~ ^dependabot/
dist: jammy
language: node_js
# 22, not 18: `cli:plugins:check` loads every plugin family the CLI bundles,
# and Solana's tools reach an ESM-only `uuid` through `rpc-websockets`, which
# Node can `require()` only from 20.19 / 22.12. Every step below was run on
# 22.23.3 before the change.
node_js:
- 18
- 22
before_install:
- node scripts/hack-travis.mjs
install:
Expand All @@ -15,4 +19,47 @@ install:
script:
- npm run lint
- npx tsc
# The five documentation gates. Read-only and seconds between them, but
# inert on their own here: `npm run prepare` above has already regenerated
# the committed artifacts, so the first gate compares fresh output against
# fresh output and passes whatever was committed. Demonstrated by editing
# one JSDoc summary — the gates fail locally and exit 0 after a prepare.
- npm run docs:api:gates
# So this is the gate that actually catches a stale artifact in CI: prepare
# skips a write when nothing changed, so a dirty generated path *is* the
# staleness, and git is the oracle. The husky hook is the only other live
# check and `git commit --no-verify` skips it.
- npm run docs:api:committed
# The published CLI's dependency list, derived from the module graph: a new
# import that did not reach the manifest is an `npm install` that succeeds
# and a CLI that cannot resolve a module. `npm run prepare` regenerates
# this too — a routine version bump used to stale it and turn `develop` red
# — so here it is as inert as the gates above, and `docs:api:committed`
# catches a stale one: `src/cli/generated/npmPackage.json` is under the
# paths it compares against git.
- npm run cli:manifest:check
# Beside the manifest check, for the same reason and against a different
# input: this one reads the *installed* plugin packages, and its allowlists
# fail both on a new breakage and on a known one starting to work — which
# is what a routine `edge-currency-accountbased` or `edge-currency-plugins`
# bump does. `precommit:cli` and `verify` both run it; without it here a
# `git commit --no-verify` by an author who never runs `verify` lands a
# broken plugin family on develop with nothing to notice.
- npm run cli:plugins:check
- npm run test:cli:node-safe
- npm test
- npm run test:cli:offline
# And again against the rollup bundle. Three transforms produce a working
# CLI — `sucrase` above, `@react-native/babel-preset` for jest,
# `@babel/preset-env` for the bundle — so a defect can exist in only one of
# them, and two severity-0 defects have existed in the bundle alone.
# `build:cli` is a two-second rollup.
- npm run test:cli:offline:built
# Last, because it is the only check that reads the built bundles' own
# `require` calls, and `--require-bundles` makes an absent `lib/` a failure
# rather than a skip. Run where `cli:manifest:check` is, nine lines above
# the build, `built` was false and the one direction that matters — a
# package the bundles require and the manifest does not declare, which a
# published CLI could not resolve — printed "bundles absent, so the require
# cross-check did not run" and passed.
- npm run cli:manifest -- --check --require-bundles
30 changes: 28 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,34 @@
- `npm test` - Run Jest tests (single run)
- `npm run watch` - Run Jest tests in watch mode
- `npm test -- --testNamePattern="test name"` - Run specific test by name
- `npm run verify` - Run lint, typechain, tsc, and test (full verification)
- `npm run precommit` - Full pre-commit check (localize, lint-staged, tsc, test)
- `npm run verify` - Full verification: lint, typechain, tsc, the five
documentation gates, the published CLI manifest check, the plugin-package
check, the Node-safety smoke test, Jest, and the CLI's offline suites
against both the sources and the built bundle
- `npm run precommit` - Pre-commit check: localize, update-eslint-warnings,
lint-staged, tsc and Jest on every commit. The documentation gates, the
manifest check, the plugin-package check, the Node-safety smoke test and
the CLI's offline suites run
only when the commit stages a path in `GATE_PATHS`
(`scripts/util/cliGatePaths.js`, which is the list) — about two and a half
minutes that a commit elsewhere has no reason to pay, and a hook people skip
with `--no-verify` also skips the `tsc` and `jest` that predate the CLI. CI
runs all of them regardless.
- `tsc` - TypeScript type checking (via package.json script)

### Edge CLI

The repository also builds `edge-cli` and `edge-engine` from `src/cli/`.
[`docs/EDGE_CLI.md`](docs/EDGE_CLI.md) is the guide; `docs/api/README.md`
covers the route declarations the reference is generated from.

- `npm run cli -- <command>` / `npm run engine` - run either half from source
- `npm run build:cli` - the single-file bundles in `lib/`
- `npm run docs:api` - regenerate the committed reference and command table
- `npm run docs:api:gates` - the five read-only checks that it is in step
- `npm run test:cli:offline` - the fake-world suites, no network
- `npm run test:cli:network` - the suites that need the tester servers

## Swap Provider Integration

The plugin itself lives in `edge-exchange-plugins`; this repo only wires it up, and every wiring point below fails SILENTLY when missed (no error, just a blank icon or a provider that never initializes). Registering a new swap `pluginId` means all of:
Expand All @@ -39,6 +63,8 @@ New swap icons live at `https://content.edge.app/exchangeIcons/<pluginId>/icon.p
- **Naming**: camelCase for variables/functions, PascalCase for components/types
- **Files**: `.tsx` for React components, `.ts` for utilities/hooks
- **Error Handling**: Use proper error boundaries, avoid throwing in render
- **Node-safe modules**: every module the CLI loads must stay importable under plain Node, with no `react-native*` module anywhere on its require graph — the CLI engine loads them without the app's bundler. That set is the CLI's module graph (`walkGraph(CLI_ENTRIES)` in `scripts/util/moduleGraph.js`) plus `SHARED_MODULES` in `scripts/util/cliGatePaths.js`; it is most of `src/cli`, `src/locales` and `src/util`, but not all of them — `src/util/rnUtils.ts` and `src/locales/initLocale.ts` are app-only and import `react-native` freely. Adding a `react-native*` import to a module in that set is what breaks the rule; reach platform code through an injected dependency or a `src/cli`-side module instead. `npm run test:cli:node-safe` is the check
- **lstrings at module scope**: in those same three trees, read `lstrings` inside a function, never at module scope. `applyLocale` mutates `lstrings` in place and the CLI boots the locale from somewhere these modules do not import, so a module-scope capture is right only if the boot happened to run first. `src/util/txDisplay/txActionLabels.ts` is the pattern; `edge/no-module-scope-lstrings` enforces it
- **Text Components**: Use `EdgeText`, `Paragraph`, `SmallText`, `WarningText` instead of raw text
- **Component Reuse**: Strongly prefer reusing existing shared components over building new ones or dropping to raw library primitives. Before adding UI, look for a component that already covers the need (e.g. text via `EdgeText`), and keep color, sizing, and styling driven by `useTheme()` rather than hard-coded per call site. When nothing suitable exists, add a reusable, themed definition instead of a one-off
- **Spacing**: Keep a minimum of 1rem TOTAL space between an element and its neighbors, including screen edges. "Total" is the sum contributed across nearby and parent elements, so examine them rather than each element in isolation: scene-edge padding from `SceneWrapper`/`SceneContainer` (`DEFAULT_MARGIN_REM`, 0.5rem) plus an element's own 0.5rem margins via `Space`/`useSpaceStyle` compose to the 1rem total. An explicit override always takes precedence: the "unless otherwise specified" escape hatch applies to every case, screen edges included. The only built-in exception is flex layouts, which rely on flex gap and alignment for sibling spacing; even there, the 1rem screen-edge minimum still applies. Express spacing in rem through the layout primitives instead of hard-coded pixel margins
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
## Unreleased (develop)

- added: `AGENT_TEST_MODE` config setting and iOS debug-build `EdgeTestAnimations` switch that quiet the app for automated UI tests
- added: Every secret the CLI takes also reads from its own environment variable — `EDGE_CLI_PASSWORD`, `EDGE_CLI_PIN`, `EDGE_CLI_LOGIN_KEY`, `EDGE_CLI_DATA_KEY` and the rest — because `ps` shows a command line to every user on the host. `check-password-rules`, `admin-repo-list` and `admin-repo-get` take their secret in a POST body rather than a query string.
- added: Edge CLI (`edge-cli`) and its engine daemon: a long-lived process owning an `EdgeContext`, a JSON REST API over a Unix socket with an optional loopback TCP listener, and a thin client that spawns the engine on demand. 118 routes, generated command table, help text and OpenAPI reference.
- changed: `npm run precommit`, `npm run verify` and CI gained the CLI's gates. The husky hook runs the five documentation gates, `cli:manifest:check`, `cli:plugins:check`, `test:cli:node-safe` and `test:cli:offline` only when a commit stages one of the paths `scripts/util/cliGatePaths.js` lists, so a commit elsewhere pays nothing. `verify` adds those plus `test:all`, which builds the rollup bundle and runs the offline suites against it. Travis runs all of them unconditionally, plus `docs:api:committed`, which fails on a stale committed artifact. The offline suites spawn a real engine daemon on a Unix socket under a temporary data directory; they need no network and no API key.
- changed: Moved transaction display metadata, denominations, spam-threshold resolution, local settings, the transaction export pipeline, transaction tagging, locale selection, exchange rates and the network helpers out of GUI-only modules so they load under plain Node, with no behaviour change to the app.
- fixed: Historical rates no longer re-query a pair the server has answered but cannot price, which looped without delay and never settled the caller's promise.
- fixed: Historical rate requests are capped below the rates server's 100-asset limit, where the previous check let a batch reach 101 and the rejection priced the whole page at zero.
- fixed: An unusable OS number format no longer also falls the language back to English when resolving info-server localized strings.
- fixed: `splitCategory` keeps an unrecognised category exactly as stored, where a one-character prefix such as `X:` was dropped and a bare name gained a trailing colon, and opening and saving the transaction wrote either change back.
- fixed: Transaction fiat amounts are fetched in one batch rather than in groups of ten, each of which paid a fresh one-second debounce.
- fixed: QBO exports escape a non-ASCII payee or memo, so the `ENCODING:USASCII` header the file declares is true.
- fixed: Recognize promotions that only set a preferred exchange in the exchange settings, which now say the promotion is choosing it and offer to remove it, instead of showing a list whose taps were saved but silently overridden for the promotion's whole window

## 4.52.0 (staging)
Expand Down
4 changes: 4 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ module.exports = function (api) {
return {
presets: ['module:@react-native/babel-preset'],
plugins: [
// `typechain` emits `export * as factories from './factories'` in
// src/plugins/contracts, which the React Native preset does not
// transform on its own.
'@babel/plugin-transform-export-namespace-from',
isAndroid
? './node_modules/r3-hack/node_modules/react-native-reanimated/plugin'
: 'react-native-worklets/plugin'
Expand Down
Loading
Loading