fix: build standalone — five things the monorepo was quietly providing

The extraction typechecked from day one and had never been built. It took five
attempts, each failing further along, and every cause was the same shape: something the
shared node_modules or the monorepo's layout supplied without anyone declaring it.

1. The config plugin had the monorepo's geometry written into it —
   ../../../packages/officer-net/ios/libs, correct from apps/<name>/ios and meaningless
   from a repo root. It reported a path belonging to neither repo. Now derived from the
   plugin's own location with path.relative, so it is right wherever the module sits.

2. That fix appeared to do nothing, because officer-net was a  dependency and bun
   COPIES those. Prebuild ran a week-old copy while the source was edited — a clean edit
   and a stale build, the same shadow-copy trap that cost a night in the monorepo.
   Making it a workspace turns node_modules/officer-net into a symlink.

3. @babel/plugin-transform-react-jsx was never declared by anything. It was hoisted into
   the monorepo by some other package, so babel-preset-expo with jsxImportSource found
   it by luck.

4. Same for react-native-reanimated and react-native-worklets: nativewind depends on
   react-native-css-interop, which lists reanimated as a PEER, whose babel plugin
   requires react-native-worklets/plugin. Three levels of nobody-declared-it.

5. And the self-inflicted one. Adding  for (2) silently flipped bun to its
   isolated linker — only direct dependencies at top level, everything else symlinked
   into node_modules/.bun, which Metro cannot resolve. It surfaced as 'Unable to resolve
   module react-native-css-interop/jsx-runtime', naming a package that was installed and
   in the lockfile and simply not where the resolver looks. bunfig.toml now pins both
   properties that are needed at once: workspaces for the symlink, hoisted for the
   layout.

Result: OffScale.app, 82 MB, with OffTailTunnel.appex at 20 MB carrying 129 Tailcore
symbols — the Go core is in the extension, which is the half that matters.

Not yet run on a device. It builds; that is a different claim.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 23:04:09 +01:00
co-authored by Claude Opus 5
parent c63662082a
commit 79fbfee5fb
4 changed files with 57 additions and 13 deletions
+8 -2
View File
@@ -3,6 +3,9 @@
"version": "1.0.0",
"license": "MIT",
"private": true,
"workspaces": [
"modules/*"
],
"main": "src/index.tsx",
"scripts": {
"start": "expo start",
@@ -21,14 +24,17 @@
"expo-status-bar": "57.0.1",
"expo-system-ui": "57.0.1",
"nativewind": "4.2.6",
"officer-net": "file:./modules/officer-net",
"officer-net": "workspace:*",
"react": "19.2.3",
"react-native": "0.86.0",
"react-native-reanimated": "4.5.3",
"react-native-safe-area-context": "5.7.0",
"react-native-svg": "15.15.4"
"react-native-svg": "15.15.4",
"react-native-worklets": "0.11.3"
},
"devDependencies": {
"@babel/core": "7.29.7",
"@babel/plugin-transform-react-jsx": "7.29.7",
"@types/react": "19.2.17",
"babel-preset-expo": "57.0.4",
"tailwindcss": "3.4.19",