Skip to content

Map server integration#86

Merged
gmaclennan merged 24 commits into
mainfrom
map-server-integration
Jun 19, 2026
Merged

Map server integration#86
gmaclennan merged 24 commits into
mainfrom
map-server-integration

Conversation

@gmaclennan

Copy link
Copy Markdown
Member

Integrates @comapeo/map-server into the backend so the app can render maps from a local HTTP server.

Changes

  • Add createMapServer which starts a @comapeo/map-server instance (fallback + custom SMP maps, online style fallback) keyed off the device root key.
  • Start the map server during backend boot and expose its base URL to the app over a new app RPC channel (appRpcClient / createAppRpcServer).
  • Rename ComapeoRpcServerComapeoRpc; it now serves both the Mapeo manager and the map server over a single message port, closing both on disconnect.
  • Wrap the map server in a StartStopStateMachine so listen()/close() are idempotent and reconnects don't hit ERR_SERVER_ALREADY_LISTEN.
  • Update example app to use the app RPC client; add an e2e map-server test.
  • Bump to @comapeo/ipc prerelease, refresh patches/lockfiles, update @mapeo/crypto.

Warning

Draft — work in progress. Tests are still being fixed.

🤖 Generated with Claude Code

achou11 and others added 12 commits May 21, 2026 10:58
* origin/main:
  chore(e2e): add e2e tests on browserstack via Maestro (#56)
  fix(sentry): make exit telemetry lossless and stop cross-process clobbering (#84)
  feat(sentry): land Phases 6 + 7a — Android exit reasons & iOS MetricKit app-exit telemetry (#72)
  chore(build): use npm list instead of custom traversal to get native module versions (#70)
@socket-security

socket-security Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​comapeo/​ipc@​8.0.0 ⏵ 9.0.0-pre.276 +210099 +496100

View full report

@gmaclennan gmaclennan marked this pull request as ready for review June 17, 2026 13:58
gmaclennan and others added 11 commits June 18, 2026 16:08
Adopt the breaking factory/type renames: Mapeo/AppRpc -> ComapeoCore/
ComapeoServices. Rename the public `appRpcClient` export to
`comapeoServicesClient` to match. The services implementation type now
comes from `@comapeo/ipc/server.js` (ComapeoServicesApi).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* origin/main:
  feat(sentry): migrate to @sentry/react-native v8; exit telemetry as Application Metrics (#73)
The embedded map server serves tiles over cleartext HTTP on 127.0.0.1.
Release builds block cleartext by default (Android targetSdk 28+, iOS
ATS), so `fetch()` to the local server fails — the map server was
unusable in release. Scope the exception to loopback only:

- Android: a network-security-config permitting cleartext for
  127.0.0.1/localhost, referenced from the manifest. The rest of the
  app keeps the secure default.
- iOS: NSAllowsLocalNetworking, which lifts ATS for loopback/.local
  while keeping it enforced for the public internet.

Verified on an Android emulator: the e2e suite goes from 37/38 to 38/38
(both map-server specs pass).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Android BrowserStack run overran the 30-min poll: seven real
devices serialise behind a small parallel-session quota, and the
~240 MB app installs slowly per device. Reduce to three devices
spanning the supported OS range (8.1 / 11 / 16) and drop the poll
timeout 1800s -> 1200s on both platforms so a stuck run fails sooner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nodejs-mobile on iOS is a jitless Node 18 build (v8_enable_webassembly
=false) that ships without the undici-backed global fetch/Response/
Request/Headers — `new Response(...)` throws "Response is not defined"
(ReadableStream is present). @comapeo/map-server serves over
@whatwg-node + itty-router, both of which construct Response/Request
against the globals, so the HTTP handler threw and never replied: every
request to the in-process map server hung until the client timed out.
Android's nodejs-mobile build keeps these globals, so it was unaffected.

install-fetch.js pulls the implementations from undici (which loads
because install-polywasm runs first) onto globalThis, wired into the iOS
entry right after the WebAssembly polyfill. Verified on BrowserStack
(iPhone 15/17.5 + iPhone 17/26.5): the map server now answers and the
e2e suite is 38/38.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The upload/trigger curls used --fail, which discards the JSON error
body (e.g. queue/parallel-limit messages) and leaves only an opaque
exit code. Capture body + status separately and print the real message
on failure, so a queue-limit rejection is diagnosable instead of an
anonymous non-zero exit.

Also drop the Android matrix to two reliably-available devices: the
2018 Galaxy Note 9 sat queued behind the BrowserStack parallel quota
long enough to overrun the poll timeout while the other devices had
already passed. Keeping the set small (4 sessions total with iOS) keeps
a run inside the quota.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Black-box checks that the in-process map server actually serves over
loopback on device — the nodejs-mobile request→response pipeline, which
differs from plain Node (see the fetch-globals fix). Covers the
fallback map style.json (200 JSON), info, a structured 404, and CORS
headers, using only the built-in fallback map (no project, no uploaded
SMP, no network). The module's own suite covers route/logic behaviour
in Node; these cover the on-device integration. Assertions verified by
running the map server in Node locally; the suite passes on BrowserStack
(iPhone 15/17.5 + iPhone 17/26.5), 41/41.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cover the map-server addition: the `comapeoServicesClient.mapServer`
export and `getBaseUrl()`, the built-in `fallback`/`default`/`custom`
map IDs, and the plugin's loopback-scoped cleartext exception that lets
release builds reach the local HTTP server.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BrowserStack real devices route app traffic through a system HTTP proxy,
and Android applies it to 127.0.0.1 too (no loopback exclusion list), so
React Native's OkHttp sent the in-process map server's loopback requests
to the proxy — which can't reach the device's own loopback and answers
503 with an HTML error page. Only the map-server HTTP tests failed on CI
(the unix-socket RPC tests don't use OkHttp); they passed locally where
no proxy is configured.

Install an OkHttp ProxySelector that bypasses the proxy for loopback
hosts and delegates everything else to the system default. Scoped to the
e2e app via a config plugin (android/ is generated by expo prebuild), so
the published module and production apps are untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rver boot/shutdown

The map server is now created and listened to directly in index.js (its
listen promise feeds getBaseUrl), so the StartStopStateMachine-based
MapServerApi wrapper in comapeo-rpc.js and its start-stop-state-machine
dependency are dead. Remove them.

Also:
- index.js: isolate each shutdown close() so one failure can't leak the
  others; treat the map server as non-critical at boot (a listen()
  rejection surfaces only to getBaseUrl() callers, never trips the
  global unhandledRejection handler).
- comapeo-rpc.js: register the messagePort "close" listener before
  start() flushes queued messages, so a socket that closes mid-flush
  can't leak the core/services servers.
- index.ios.js: add assert-webassembly.js between install-polywasm and
  install-fetch to turn a wrong import order into a clear failure.
- run-browserstack-maestro action: dump the per-session report on a
  non-pass terminal state so the real Maestro failure is visible in CI.
- Add unit tests for comapeo-rpc, create-map-server, message-port and
  simple-rpc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The removed comment claimed registering the close listener before
start() avoids a leak from a socket closing "during the flush", but the
setup is fully synchronous so no close event can interleave start() in
either ordering. The handler closing both servers on disconnect is
self-explanatory.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gmaclennan gmaclennan enabled auto-merge (squash) June 19, 2026 09:18
@gmaclennan gmaclennan merged commit 5caff5f into main Jun 19, 2026
11 checks passed
@gmaclennan gmaclennan deleted the map-server-integration branch June 19, 2026 09:29
gmaclennan added a commit that referenced this pull request Jun 22, 2026
## Optic Release Automation

This **draft** PR is opened by Github action
[optic-release-automation-action](https://github.com/nearform-actions/optic-release-automation-action).

A new **draft** GitHub release
[v1.0.0-pre.2](https://github.com/digidem/comapeo-core-react-native/releases/tag/untagged-c499977757c9745e56b2)
has been created.

Release author: @gmaclennan

#### If you want to go ahead with the release, please merge this PR.
When you merge:

- The GitHub release will be published

- The npm package with tag pre will be published according to the
publishing rules you have configured



- No major or minor tags will be updated as configured


#### If you close the PR

- The new draft release will be deleted and nothing will change

## What's Changed
* Android Testing Infrastructure & Bug Fixes by @gmaclennan in
#3
* chore: prebuild example/android; harden instrumented tests by
@gmaclennan in
#10
* Integrate @comapeo/core via IPC over Unix sockets by @gmaclennan in
#5
* chore: adjust repo setup by @achou11 in
#12
* chore: minor fixes based on expo-doctor by @achou11 in
#13
* Add iOS support & test infrastructure by @gmaclennan in
#6
* chore: add architecture docs & plans by @gmaclennan in
#11
* update some native deps used in backend by @achou11 in
#14
* iOS Phase 1: unified JS bundle + smoke test (simulator-only) by
@gmaclennan in
#15
* iOS Phase 2: xcframework Embed & Sign for native addons by @gmaclennan
in #16
* Phase 2 Android: jniLibs packaging + unified rollup loader plugin by
@gmaclennan in
#17
* chore: post-Phase-2 cleanup — comments, plan docs, agents.md by
@gmaclennan in
#33
* android: read abiFilters from reactNativeArchitectures (#30) by
@gmaclennan in
#35
* refactor: simplify build-backend.ts; rollup writes directly to native
asset trees by @gmaclennan in
#34
* chore: fix eslint configuration by @achou11 in
#41
* android: audit 16 KB page alignment on every shipped .so by
@gmaclennan in
#43
* Add rootkey persistence and lifecycle state management by @gmaclennan
in #36
* chore: move example app into apps directory by @achou11 in
#18
* refactor: per-component lifecycle state with derived ComapeoState by
@gmaclennan in
#47
* android: fold waitForFile into connect retry loop by @gmaclennan in
#52
* chore: add e2e testing app by @achou11 in
#49
* fix(android): drop setUnlockedDeviceRequired from rootkey wrapper key
by @gmaclennan in
#57
* fix(backend): cache stopping/error frames for late joiners by
@gmaclennan in
#58
* fix(ios-tests): wait for STOPPING before signalling node exit by
@gmaclennan in
#59
* fix(android): drain JNI stdio pumps before returning from node::Start
by @gmaclennan in
#60
* Sentry integration: Phase 1 + Phase 2a + Phase 2b by @gmaclennan in
#54
* feat(backend): polywasm-backed undici on iOS, re-enable maps plugin by
@gmaclennan in
#62
* ci: drop unreliable Android emulator snapshot caching by @gmaclennan
in #64
* feat(sentry): land Phase 3 — backend loader + RPC tracing by
@gmaclennan in
#63
* fix(ios-tests): serialise STOPPING/STOPPED observers in
testFullLifecycleStateTransitions by @gmaclennan in
#71
* use npm list instead of custom traversal to get native module versions
by @achou11 in
#70
* feat(sentry): land Phases 6 + 7a — Android exit reasons & iOS
MetricKit app-exit telemetry by @gmaclennan in
#72
* fix(sentry): make exit telemetry lossless and stop cross-process
clobbering by @gmaclennan in
#84
* chore(e2e): add e2e tests on browserstack via Maestro by @achou11 in
#56
* feat(sentry): migrate to @sentry/react-native v8; exit telemetry as
Application Metrics by @gmaclennan in
#73
* Map server integration by @gmaclennan in
#86
* chore(deps): upgrade to Expo SDK 56 (React Native 0.85) by @gmaclennan
in #87
* chore(ci): add release workflow by @gmaclennan in
#90
* chore: fix npm script and release build script by @gmaclennan in
#91
* chore(pack): don't try to package build files by @gmaclennan in
#92
* fix: start fastify listening by @gmaclennan in
#93
* perf(backend): switch bundler from rollup to rolldown by @gmaclennan
in #94
* fix(ci): ignore-scripts in ios npm installs by @gmaclennan in
#96
* fix(ci): replace --ignore-scripts with npm strict-allow-scripts
allowlist by @gmaclennan in
#106
* feat(config): let the consuming app supply the default project config
by @gmaclennan in
#95
* chore(release): merge prerelease branch. by @gmaclennan in
#110

## New Contributors
* @achou11 made their first contribution in
#12

**Full Changelog**:
https://github.com/digidem/comapeo-core-react-native/commits/v1.0.0-pre.2

<!--

<release-meta>{"id":342868678,"version":"v1.0.0-pre.2","npmTag":"pre","opticUrl":"https://optic-zf3votdk5a-ew.a.run.app/api/generate/"}</release-meta>
-->
@gmaclennan gmaclennan added the feature New feature (changelog) label Jun 22, 2026
gmaclennan added a commit that referenced this pull request Jun 22, 2026
## Optic Release Automation

This **draft** PR is opened by Github action
[optic-release-automation-action](https://github.com/nearform-actions/optic-release-automation-action).

A new **draft** GitHub release
[v1.0.0-pre.2](https://github.com/digidem/comapeo-core-react-native/releases/tag/untagged-352a6c41c12fd02dec37)
has been created.

Release author: @gmaclennan

#### If you want to go ahead with the release, please merge this PR.
When you merge:

- The GitHub release will be published

- The npm package with tag pre will be published according to the
publishing rules you have configured



- No major or minor tags will be updated as configured


#### If you close the PR

- The new draft release will be deleted and nothing will change

<!-- Release notes generated using configuration in .github/release.yml
at 7fe80b4 -->

## What's Changed
### 🚀 Features
* Integrate @comapeo/core via IPC over Unix sockets by @gmaclennan in
#5
* Add iOS support & test infrastructure by @gmaclennan in
#6
* iOS Phase 1: unified JS bundle + smoke test (simulator-only) by
@gmaclennan in
#15
* iOS Phase 2: xcframework Embed & Sign for native addons by @gmaclennan
in #16
* Phase 2 Android: jniLibs packaging + unified rollup loader plugin by
@gmaclennan in
#17
* android: read abiFilters from reactNativeArchitectures (#30) by
@gmaclennan in
#35
* Add rootkey persistence and lifecycle state management by @gmaclennan
in #36
* Sentry integration: Phase 1 + Phase 2a + Phase 2b by @gmaclennan in
#54
* feat(backend): polywasm-backed undici on iOS, re-enable maps plugin by
@gmaclennan in
#62
* feat(sentry): land Phase 3 — backend loader + RPC tracing by
@gmaclennan in
#63
* feat(sentry): land Phases 6 + 7a — Android exit reasons & iOS
MetricKit app-exit telemetry by @gmaclennan in
#72
* feat(sentry): migrate to @sentry/react-native v8; exit telemetry as
Application Metrics by @gmaclennan in
#73
* Map server integration by @gmaclennan in
#86
* feat(config): let the consuming app supply the default project config
by @gmaclennan in
#95
### 🐛 Bug Fixes
* fix(android): drop setUnlockedDeviceRequired from rootkey wrapper key
by @gmaclennan in
#57
* fix(backend): cache stopping/error frames for late joiners by
@gmaclennan in
#58
* fix(ios-tests): wait for STOPPING before signalling node exit by
@gmaclennan in
#59
* fix(android): drain JNI stdio pumps before returning from node::Start
by @gmaclennan in
#60
* fix(ios-tests): serialise STOPPING/STOPPED observers in
testFullLifecycleStateTransitions by @gmaclennan in
#71
* fix(sentry): make exit telemetry lossless and stop cross-process
clobbering by @gmaclennan in
#84
* fix: start fastify listening by @gmaclennan in
#93
* fix(ci): ignore-scripts in ios npm installs by @gmaclennan in
#96
* fix(ci): replace --ignore-scripts with npm strict-allow-scripts
allowlist by @gmaclennan in
#106
* fix(release): stop `npm pack --dry-run` leaking dry-run into backend
install by @gmaclennan in
#129
### ⚡ Performance
* perf(backend): switch bundler from rollup to rolldown by @gmaclennan
in #94
### ⬆️ Dependencies
* update some native deps used in backend by @achou11 in
#14
* chore(deps): upgrade to Expo SDK 56 (React Native 0.85) by @gmaclennan
in #87
### 🏗️ Maintenance
* Android Testing Infrastructure & Bug Fixes by @gmaclennan in
#3
* chore: prebuild example/android; harden instrumented tests by
@gmaclennan in
#10
* chore: adjust repo setup by @achou11 in
#12
* chore: minor fixes based on expo-doctor by @achou11 in
#13
* chore: add architecture docs & plans by @gmaclennan in
#11
* chore: post-Phase-2 cleanup — comments, plan docs, agents.md by
@gmaclennan in
#33
* refactor: simplify build-backend.ts; rollup writes directly to native
asset trees by @gmaclennan in
#34
* chore: fix eslint configuration by @achou11 in
#41
* android: audit 16 KB page alignment on every shipped .so by
@gmaclennan in
#43
* chore: move example app into apps directory by @achou11 in
#18
* refactor: per-component lifecycle state with derived ComapeoState by
@gmaclennan in
#47
* android: fold waitForFile into connect retry loop by @gmaclennan in
#52
* chore: add e2e testing app by @achou11 in
#49
* ci: drop unreliable Android emulator snapshot caching by @gmaclennan
in #64
* use npm list instead of custom traversal to get native module versions
by @achou11 in
#70
* chore(e2e): add e2e tests on browserstack via Maestro by @achou11 in
#56
* chore(ci): add release workflow by @gmaclennan in
#90
* chore: fix npm script and release build script by @gmaclennan in
#91
* chore(pack): don't try to package build files by @gmaclennan in
#92
* chore(release): merge prerelease branch. by @gmaclennan in
#110
* ci(e2e): retry BrowserStack builds on infra-class flakes by
@gmaclennan in
#113
### Other Changes
* ci: derive changelog labels from PR titles + add Dependabot by
@gmaclennan in
#114

## New Contributors
* @achou11 made their first contribution in
#12
* @optic-release-automation[bot] made their first contribution in
#112

**Full Changelog**:
https://github.com/digidem/comapeo-core-react-native/commits/v1.0.0-pre.2

<!--

<release-meta>{"id":342970724,"version":"v1.0.0-pre.2","npmTag":"pre","opticUrl":"https://optic-zf3votdk5a-ew.a.run.app/api/generate/"}</release-meta>
-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature (changelog)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants