Map server integration#86
Merged
Merged
Conversation
* 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)
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
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
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
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> -->
This was referenced Jun 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integrates
@comapeo/map-serverinto the backend so the app can render maps from a local HTTP server.Changes
createMapServerwhich starts a@comapeo/map-serverinstance (fallback + custom SMP maps, online style fallback) keyed off the device root key.appRpcClient/createAppRpcServer).ComapeoRpcServer→ComapeoRpc; it now serves both the Mapeo manager and the map server over a single message port, closing both on disconnect.StartStopStateMachinesolisten()/close()are idempotent and reconnects don't hitERR_SERVER_ALREADY_LISTEN.@comapeo/ipcprerelease, refresh patches/lockfiles, update@mapeo/crypto.Warning
Draft — work in progress. Tests are still being fixed.
🤖 Generated with Claude Code