sootsim 0.1.82 → 0.1.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/expectations.ts +477 -0
- package/detox/gestures.ts +442 -0
- package/detox/index.ts +1436 -0
- package/detox/jest-environment.ts +86 -0
- package/detox/jest-preset.cjs +50 -0
- package/detox/matchers.ts +29 -0
- package/detox/navigation.ts +43 -0
- package/detox/run-test.ts +113 -0
- package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
- package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
- package/detox/screenshots/color-test-rest-norngh.png +0 -0
- package/detox/screenshots/theme-blue-toggle.png +0 -0
- package/detox/screenshots/theme-blue.png +0 -0
- package/detox/screenshots/theme-red-toggle.png +0 -0
- package/detox/screenshots/theme-red.png +0 -0
- package/dist-cli/bin.js +3 -3
- package/dist-cli/chunks/{agent-3C6Z6YXA.js → agent-2CWD6W6P.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-7Z4UFACX.js → agent-wrapper-5W3LOX6S.js} +2 -2
- package/dist-cli/chunks/{assert-XYBIZRDK.js → assert-ZOMAMKRT.js} +2 -2
- package/dist-cli/chunks/auto-bootstrap-NYYSMTIM.js +2 -0
- package/dist-cli/chunks/beta-4K2SQACK.js +2 -0
- package/dist-cli/chunks/chunk-3HXQ7MJK.js +79 -0
- package/dist-cli/chunks/{chunk-EJGEDUOC.js → chunk-4K7BH2D4.js} +3 -3
- package/dist-cli/chunks/{chunk-2EFQQWEC.js → chunk-4OPRODFA.js} +2 -2
- package/dist-cli/chunks/{chunk-Z6G5SDG7.js → chunk-4OWVPRZV.js} +2 -2
- package/dist-cli/chunks/{chunk-DCFGNIJC.js → chunk-5XCXOLG2.js} +2 -2
- package/dist-cli/chunks/chunk-67ZZ2CM5.js +1 -0
- package/dist-cli/chunks/{chunk-M3OULYY3.js → chunk-73UZXB4B.js} +2 -2
- package/dist-cli/chunks/{chunk-QPDWMYCA.js → chunk-7NWNTUJF.js} +1 -1
- package/dist-cli/chunks/chunk-7YHDJLO2.js +119 -0
- package/dist-cli/chunks/{chunk-EX6IOT23.js → chunk-AJVTY6KY.js} +2 -2
- package/dist-cli/chunks/chunk-AWSQUOAS.js +67 -0
- package/dist-cli/chunks/{chunk-JVNGH5S7.js → chunk-BCBNVJVG.js} +1 -1
- package/dist-cli/chunks/{chunk-WZLKUS54.js → chunk-BKBL6K2G.js} +1 -1
- package/dist-cli/chunks/{chunk-DSYW2NOW.js → chunk-C3DPQZ4J.js} +2 -2
- package/dist-cli/chunks/chunk-D3ZSBIIY.js +2 -0
- package/dist-cli/chunks/{chunk-PYDAVGCZ.js → chunk-D4HUVLZR.js} +1 -1
- package/dist-cli/chunks/{chunk-H6NBDJIO.js → chunk-DUUSJDES.js} +1 -1
- package/dist-cli/chunks/{chunk-BVXP2GDN.js → chunk-ELJLF4SG.js} +3 -3
- package/dist-cli/chunks/{chunk-TR7NIFSL.js → chunk-EQ7TFQ2F.js} +1 -1
- package/dist-cli/chunks/{chunk-UOWBKSSI.js → chunk-EQCKGC4B.js} +1 -1
- package/dist-cli/chunks/chunk-FUCGLWNN.js +1 -0
- package/dist-cli/chunks/{chunk-BISEHRNE.js → chunk-HYPJW65U.js} +2 -2
- package/dist-cli/chunks/chunk-IILJQCZA.js +2 -0
- package/dist-cli/chunks/{chunk-2XULSYS6.js → chunk-KU6MSPAH.js} +2 -2
- package/dist-cli/chunks/{chunk-QTJJHBCI.js → chunk-OOOR7NT2.js} +1 -1
- package/dist-cli/chunks/{chunk-U3XCDQRH.js → chunk-P7WDNKOS.js} +3 -3
- package/dist-cli/chunks/{chunk-C7JOLDDQ.js → chunk-PPKKA5VW.js} +2 -2
- package/dist-cli/chunks/{chunk-JUCV3VHM.js → chunk-PS2G44GT.js} +2 -2
- package/dist-cli/chunks/{chunk-PO64TMRT.js → chunk-QMSJR5R2.js} +2 -2
- package/dist-cli/chunks/{chunk-4QUAOBUB.js → chunk-RF4R2U46.js} +2 -2
- package/dist-cli/chunks/{chunk-D3SM2JYB.js → chunk-RIXUH3NK.js} +2 -2
- package/dist-cli/chunks/{chunk-2JQIKL3B.js → chunk-SFGUPL2X.js} +2 -2
- package/dist-cli/chunks/{chunk-GI5MF6LP.js → chunk-SQX5CAYG.js} +1 -1
- package/dist-cli/chunks/{chunk-Q4JNA5VO.js → chunk-SQZAC7C4.js} +1 -1
- package/dist-cli/chunks/{chunk-M4ERVRM4.js → chunk-SV7FOGJ3.js} +2 -2
- package/dist-cli/chunks/{chunk-ZN2C7V5R.js → chunk-TK3OJSEO.js} +2 -2
- package/dist-cli/chunks/{chunk-7SCQEPXK.js → chunk-TL7SIZ7S.js} +1 -1
- package/dist-cli/chunks/{chunk-IZ2OO47Y.js → chunk-V2GQ4WXJ.js} +2 -2
- package/dist-cli/chunks/{chunk-JUDJXJSE.js → chunk-VH7F45CN.js} +1 -1
- package/dist-cli/chunks/chunk-WNVNU2OW.js +4 -0
- package/dist-cli/chunks/{chunk-O3AOQP3V.js → chunk-XQ2OBHBE.js} +2 -2
- package/dist-cli/chunks/{chunk-MQXYJTXM.js → chunk-YCIA4BHJ.js} +2 -2
- package/dist-cli/chunks/chunk-ZSMMJMPA.js +1 -0
- package/dist-cli/chunks/cli-version-QB4VH24H.js +2 -0
- package/dist-cli/chunks/{compat-2DVSCCR7.js → compat-FWSEEGEH.js} +3 -3
- package/dist-cli/chunks/{config-YDX4Q4XM.js → config-CYI2WAGP.js} +2 -2
- package/dist-cli/chunks/control-UXY7YQVX.js +2 -0
- package/dist-cli/chunks/{cpu-profile-GU62WVZZ.js → cpu-profile-IKAE3KTY.js} +2 -2
- package/dist-cli/chunks/{daemon-V5NLDTSB.js → daemon-ZUMF53YB.js} +2 -2
- package/dist-cli/chunks/{debug-HAOCONNB.js → debug-P6KULKKS.js} +3 -3
- package/dist-cli/chunks/{detox-YLC4DLXB.js → detox-SPWAZCYG.js} +2 -2
- package/dist-cli/chunks/{device-ZQ4DN4H6.js → device-JWEPK6I2.js} +2 -2
- package/dist-cli/chunks/{diagnose-HNUO3Z5F.js → diagnose-IZODTXV2.js} +2 -2
- package/dist-cli/chunks/drivers-MK6WJKBC.js +2 -0
- package/dist-cli/chunks/{electron-ZAASAHSW.js → electron-R5GP6RVB.js} +3 -3
- package/dist-cli/chunks/flow-6O4GEOPJ.js +2 -0
- package/dist-cli/chunks/{hints-BA3GE5W5.js → hints-DYDNYX7N.js} +2 -2
- package/dist-cli/chunks/{home-paths-MQXRHBTW.js → home-paths-GLMX5OKL.js} +2 -2
- package/dist-cli/chunks/{inspect-T4RMS5KX.js → inspect-FJOPCTY2.js} +3 -3
- package/dist-cli/chunks/install-A3TUGGHN.js +2 -0
- package/dist-cli/chunks/{install-desktop-MH26VONS.js → install-desktop-YPJZMZM5.js} +3 -3
- package/dist-cli/chunks/{keys-IELIDRGB.js → keys-GSYPHWNY.js} +2 -2
- package/dist-cli/chunks/{launch-VMT3OWOB.js → launch-4G2PKW5X.js} +3 -3
- package/dist-cli/chunks/{login-VZBANVLU.js → login-KJQGHA64.js} +4 -4
- package/dist-cli/chunks/{logout-GWXBTQ4H.js → logout-XM2SYH5C.js} +2 -2
- package/dist-cli/chunks/{maestro-JYHR4HFR.js → maestro-EOWGI7DG.js} +2 -2
- package/dist-cli/chunks/{preview-RPZ4UQ2B.js → preview-F73TKK37.js} +2 -2
- package/dist-cli/chunks/{profile-7FLDF2AP.js → profile-22FDKBUO.js} +2 -2
- package/dist-cli/chunks/{react-3RC4CNDZ.js → react-5L6VPFUP.js} +2 -2
- package/dist-cli/chunks/record-JZXCQ4IN.js +70 -0
- package/dist-cli/chunks/runtime-EEBX7CFV.js +2 -0
- package/dist-cli/chunks/{runtime-delivery-Z7I2KIRB.js → runtime-delivery-LXUM3R4A.js} +2 -2
- package/dist-cli/chunks/{screenshot-GRCZ6AM4.js → screenshot-HDRRG33Q.js} +2 -2
- package/dist-cli/chunks/{screenshot-mode-E4YHXHH5.js → screenshot-mode-WY63LZIX.js} +2 -2
- package/dist-cli/chunks/{screenshots-7SXMX2AY.js → screenshots-MPV2ENL5.js} +2 -2
- package/dist-cli/chunks/{server-GDJ2TCRV.js → server-5LBMCJ3G.js} +2 -2
- package/dist-cli/chunks/setup-repo-SZSYNKNI.js +2 -0
- package/dist-cli/chunks/{skills-62E7NDRC.js → skills-BQ73YOBF.js} +2 -2
- package/dist-cli/chunks/{start-Y7KR5ZQ3.js → start-2WU4W6ZU.js} +4 -4
- package/dist-cli/chunks/store-RE45SUBF.js +2 -0
- package/dist-cli/chunks/telemetry-DG6GJLCP.js +2 -0
- package/dist-cli/chunks/{test-IYMSUPVC.js → test-OVO4CQTG.js} +3 -3
- package/dist-cli/chunks/{three-mode-QKKXCCC2.js → three-mode-BKM3KFM7.js} +2 -2
- package/dist-cli/chunks/{timeline-PF6NQ7RT.js → timeline-MDXGEDQL.js} +2 -2
- package/dist-cli/chunks/{upgrade-CE2Y3TAN.js → upgrade-JGQABWVF.js} +2 -2
- package/dist-cli/chunks/upload-UJNUA4ZV.js +2 -0
- package/dist-cli/chunks/{web-XEO3ZCPF.js → web-WYFAYQ72.js} +2 -2
- package/dist-cli/chunks/{what-happened-372J7YF7.js → what-happened-PZW2KW6A.js} +2 -2
- package/dist-cli/chunks/{whoami-B4E7KCT5.js → whoami-7ATWJQS6.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +44 -0
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1770 -0
- package/dist-lib/detox/jest-preset.cjs +50 -0
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/demo-app-registry.cjs +809 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1269 -0
- package/dist-lib/skills.cjs +8322 -0
- package/dist-lib/vite-base.cjs +3 -3
- package/dist-lib/vite.cjs +1 -1
- package/package.json +39 -10
- package/scripts/demo-app-registry.ts +989 -0
- package/scripts/dev-server-scanner.ts +674 -0
- package/src/agent-daemon-client.ts +390 -0
- package/src/agent-events.ts +71 -0
- package/src/agent-prompt.ts +71 -0
- package/src/agent-sessions.ts +572 -0
- package/src/attached-projects.ts +536 -0
- package/src/auth/shared-session.ts +199 -0
- package/src/backend-origin.ts +49 -0
- package/src/beta.ts +21 -0
- package/src/bridge-constants.ts +10 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +30 -0
- package/src/codex-client.ts +215 -0
- package/src/config.ts +110 -0
- package/src/dev-bundle-resolution.ts +180 -0
- package/src/home-paths.ts +382 -0
- package/src/host/agent-host.ts +576 -0
- package/src/host/bridge-host.ts +2293 -0
- package/src/host/fetch-proxy-handler.ts +288 -0
- package/src/host/fetch-proxy-overrides.ts +39 -0
- package/src/host/open-url.ts +234 -0
- package/src/index.ts +9 -0
- package/src/metro-plugin.ts +207 -0
- package/src/native-dev-bundle-url.ts +62 -0
- package/src/native-seam-manifest.ts +313 -0
- package/src/profiles.ts +179 -0
- package/src/render-mode.ts +27 -0
- package/src/runtime-delivery.ts +334 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +438 -0
- package/src/screenshots/orchestrate.ts +244 -0
- package/src/screenshots/registry.ts +58 -0
- package/src/screenshots/schema.ts +364 -0
- package/src/skills/builtin/a11y-review.ts +126 -0
- package/src/skills/builtin/compat-check.ts +104 -0
- package/src/skills/builtin/perf-profile.ts +84 -0
- package/src/skills/builtin/screenshot-all.ts +46 -0
- package/src/skills/builtin/test-flow.ts +118 -0
- package/src/skills/builtin/visual-diff.ts +94 -0
- package/src/skills/registry.ts +107 -0
- package/src/skills/types.ts +41 -0
- package/src/vite-plugin-one.ts +187 -0
- package/src/vite-plugin.ts +1381 -0
- package/src/worklets-babel.ts +132 -0
- package/dist-cli/chunks/auto-bootstrap-D2EQVL7R.js +0 -2
- package/dist-cli/chunks/beta-VHPXECZY.js +0 -2
- package/dist-cli/chunks/chunk-27HBWBE6.js +0 -4
- package/dist-cli/chunks/chunk-2W5C5J4O.js +0 -64
- package/dist-cli/chunks/chunk-3OH4VCJA.js +0 -1
- package/dist-cli/chunks/chunk-45HLFQRI.js +0 -2
- package/dist-cli/chunks/chunk-7YLCK5HG.js +0 -5
- package/dist-cli/chunks/chunk-BRDUKIZI.js +0 -119
- package/dist-cli/chunks/chunk-GADW2Q5S.js +0 -1
- package/dist-cli/chunks/chunk-HST43CVE.js +0 -2
- package/dist-cli/chunks/chunk-QJBQOGTK.js +0 -73
- package/dist-cli/chunks/chunk-V26REV7G.js +0 -1
- package/dist-cli/chunks/cli-version-WF7T6IKI.js +0 -2
- package/dist-cli/chunks/control-EAK2OPGB.js +0 -2
- package/dist-cli/chunks/demo-app-registry-52A2MI72.js +0 -2
- package/dist-cli/chunks/drivers-B4QPIZ4B.js +0 -2
- package/dist-cli/chunks/flow-PFLHFNVM.js +0 -2
- package/dist-cli/chunks/install-ZCPEMK6U.js +0 -2
- package/dist-cli/chunks/record-CZ33G5FT.js +0 -70
- package/dist-cli/chunks/runtime-AZKHZHJ4.js +0 -2
- package/dist-cli/chunks/setup-repo-3Y2QAZRK.js +0 -2
- package/dist-cli/chunks/store-TDTFZMGA.js +0 -2
- package/dist-cli/chunks/telemetry-G3NIU5NP.js +0 -2
- package/dist-cli/chunks/upload-CLWFS7IL.js +0 -2
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// sootsim metro plugin — serves the sootsim shell at /__soot/ on metro's server.
|
|
2
|
+
// shell assets come from the active engine runtime under ~/.sootsim/runtimes/,
|
|
3
|
+
// which is fetched by `sootsim runtime install` / `sootsim setup-repo`. resolved
|
|
4
|
+
// per-request so swapping runtimes (`sootsim runtime use <v>`) takes effect
|
|
5
|
+
// without restarting metro.
|
|
6
|
+
//
|
|
7
|
+
// usage in metro.config.js:
|
|
8
|
+
// const { withSootsim } = require('sootsim/metro')
|
|
9
|
+
// module.exports = withSootsim(getDefaultConfig(__dirname))
|
|
10
|
+
|
|
11
|
+
import fs from 'fs'
|
|
12
|
+
import path from 'path'
|
|
13
|
+
import { readActiveRuntime, runtimeDir } from './home-paths'
|
|
14
|
+
|
|
15
|
+
const prefix = '/__soot'
|
|
16
|
+
|
|
17
|
+
function resolveRuntimeRoot(): string | null {
|
|
18
|
+
const active = readActiveRuntime()
|
|
19
|
+
if (!active) return null
|
|
20
|
+
const dir = runtimeDir(active)
|
|
21
|
+
if (!fs.existsSync(path.join(dir, 'index.html'))) return null
|
|
22
|
+
return dir
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const RUNTIME_MISSING_MESSAGE =
|
|
26
|
+
'[sootsim] no engine runtime installed — run `sootsim setup-repo` in your project, or `sootsim runtime install`'
|
|
27
|
+
|
|
28
|
+
const MIME_TYPES: Record<string, string> = {
|
|
29
|
+
'.js': 'application/javascript',
|
|
30
|
+
'.css': 'text/css',
|
|
31
|
+
'.html': 'text/html',
|
|
32
|
+
'.wasm': 'application/wasm',
|
|
33
|
+
'.json': 'application/json',
|
|
34
|
+
'.jpg': 'image/jpeg',
|
|
35
|
+
'.jpeg': 'image/jpeg',
|
|
36
|
+
'.png': 'image/png',
|
|
37
|
+
'.svg': 'image/svg+xml',
|
|
38
|
+
'.webp': 'image/webp',
|
|
39
|
+
'.glb': 'model/gltf-binary',
|
|
40
|
+
'.ttf': 'font/ttf',
|
|
41
|
+
'.otf': 'font/otf',
|
|
42
|
+
'.mp3': 'audio/mpeg',
|
|
43
|
+
'.wav': 'audio/wav',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const ROOT_RUNTIME_PATHS = [
|
|
47
|
+
'/assets/',
|
|
48
|
+
'/engine/',
|
|
49
|
+
'/engine-tenant/',
|
|
50
|
+
'/photos/',
|
|
51
|
+
'/three-mode/',
|
|
52
|
+
'/canvaskit.wasm',
|
|
53
|
+
'/fonts/',
|
|
54
|
+
'/icons/',
|
|
55
|
+
'/sounds/',
|
|
56
|
+
'/spike/',
|
|
57
|
+
'/test-wallpaper.jpg',
|
|
58
|
+
'/preview-sw.js',
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
export function isRootRuntimeAssetPath(pathname: string): boolean {
|
|
62
|
+
return ROOT_RUNTIME_PATHS.some((p) => pathname === p || pathname.startsWith(p))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function resolveRuntimeFilePath(
|
|
66
|
+
runtimeRoot: string,
|
|
67
|
+
pathname: string,
|
|
68
|
+
): string | null {
|
|
69
|
+
if (!pathname.startsWith('/')) return null
|
|
70
|
+
if (pathname.includes('\0') || pathname.includes('\\')) return null
|
|
71
|
+
for (const segment of pathname.split('/')) {
|
|
72
|
+
if (segment === '..') return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fullPath = path.resolve(runtimeRoot, pathname.replace(/^\/+/, ''))
|
|
76
|
+
const rootWithSep = runtimeRoot.endsWith(path.sep)
|
|
77
|
+
? runtimeRoot
|
|
78
|
+
: runtimeRoot + path.sep
|
|
79
|
+
if (!fullPath.startsWith(rootWithSep) && fullPath !== runtimeRoot) return null
|
|
80
|
+
if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) return null
|
|
81
|
+
return fullPath
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface SootsimMetroOptions {
|
|
85
|
+
bundleUrl?: string
|
|
86
|
+
enabled?: boolean
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// the slice of metro's config we touch — keeps `T` open for whatever
|
|
90
|
+
// shape consumers pass while letting us extend `server.enhanceMiddleware`.
|
|
91
|
+
type MetroConfigWithServer = {
|
|
92
|
+
server?: {
|
|
93
|
+
enhanceMiddleware?: (middleware: unknown, server: unknown) => unknown
|
|
94
|
+
[key: string]: unknown
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function withSootsim<T extends Record<string, unknown>>(
|
|
99
|
+
config: T,
|
|
100
|
+
options: SootsimMetroOptions = {},
|
|
101
|
+
): T {
|
|
102
|
+
if (options.enabled === false) return config
|
|
103
|
+
|
|
104
|
+
const bundleUrl =
|
|
105
|
+
options.bundleUrl || '/index.bundle?platform=ios&dev=true&hot=true&minify=false'
|
|
106
|
+
|
|
107
|
+
const cfgServer = (config as MetroConfigWithServer).server
|
|
108
|
+
const existingEnhance = cfgServer?.enhanceMiddleware
|
|
109
|
+
|
|
110
|
+
const serverConfig = {
|
|
111
|
+
...cfgServer,
|
|
112
|
+
enhanceMiddleware: (metroMiddleware: any, metroServer: any) => {
|
|
113
|
+
let middleware = metroMiddleware
|
|
114
|
+
if (existingEnhance) {
|
|
115
|
+
middleware = existingEnhance(metroMiddleware, metroServer)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let connect: any
|
|
119
|
+
try {
|
|
120
|
+
connect = require('connect')
|
|
121
|
+
} catch {
|
|
122
|
+
console.warn('[sootsim] connect not available')
|
|
123
|
+
return middleware
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const server = connect()
|
|
127
|
+
|
|
128
|
+
server.use((req: any, res: any, next: any) => {
|
|
129
|
+
const url = req.url || ''
|
|
130
|
+
const pathname = url.split('?')[0]
|
|
131
|
+
const runtimeRoot = resolveRuntimeRoot()
|
|
132
|
+
|
|
133
|
+
if (!runtimeRoot) {
|
|
134
|
+
if (pathname === prefix || pathname === prefix + '/') {
|
|
135
|
+
res.statusCode = 500
|
|
136
|
+
res.end(RUNTIME_MISSING_MESSAGE)
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
next()
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// root-relative runtime assets emitted by the shell and engine vite
|
|
144
|
+
// builds. if a user app has its own /assets/foo request, we only
|
|
145
|
+
// intercept when that exact file exists in the runtime; otherwise
|
|
146
|
+
// metro handles it normally.
|
|
147
|
+
if (isRootRuntimeAssetPath(pathname)) {
|
|
148
|
+
const fullPath = resolveRuntimeFilePath(runtimeRoot, pathname)
|
|
149
|
+
if (fullPath) {
|
|
150
|
+
serveRuntimeFile(res, fullPath)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// /__soot/* — serve runtime assets
|
|
156
|
+
if (pathname.startsWith(prefix + '/')) {
|
|
157
|
+
const fullPath = resolveRuntimeFilePath(
|
|
158
|
+
runtimeRoot,
|
|
159
|
+
pathname.slice(prefix.length),
|
|
160
|
+
)
|
|
161
|
+
if (fullPath) {
|
|
162
|
+
serveRuntimeFile(res, fullPath)
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// serve HTML shell for /__soot and extensionless in-shell routes.
|
|
168
|
+
if (
|
|
169
|
+
pathname === prefix ||
|
|
170
|
+
pathname === prefix + '/' ||
|
|
171
|
+
pathname.startsWith(prefix + '/')
|
|
172
|
+
) {
|
|
173
|
+
const ext = path.extname(pathname)
|
|
174
|
+
if (!ext) {
|
|
175
|
+
const htmlPath = path.join(runtimeRoot, 'index.html')
|
|
176
|
+
let html = fs.readFileSync(htmlPath, 'utf8')
|
|
177
|
+
html = html.replace(
|
|
178
|
+
'</head>',
|
|
179
|
+
`<script>history.replaceState(null,'','${prefix}/?bundle=${encodeURIComponent(bundleUrl)}')</script></head>`,
|
|
180
|
+
)
|
|
181
|
+
res.setHeader('content-type', 'text/html')
|
|
182
|
+
res.end(html)
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
next()
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
server.use(middleware)
|
|
191
|
+
|
|
192
|
+
console.log(`[sootsim] serving at ${prefix}/`)
|
|
193
|
+
return server
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return { ...config, server: serverConfig } as T
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export default withSootsim
|
|
201
|
+
|
|
202
|
+
function serveRuntimeFile(res: any, fullPath: string) {
|
|
203
|
+
const ext = path.extname(fullPath)
|
|
204
|
+
res.setHeader('content-type', MIME_TYPES[ext] || 'application/octet-stream')
|
|
205
|
+
res.setHeader('cache-control', 'max-age=31536000,immutable')
|
|
206
|
+
fs.createReadStream(fullPath).pipe(res)
|
|
207
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// canonical entry path for a plain Metro packager that serves no Expo
|
|
2
|
+
// manifest. only used when `/status` confirms `packager-status:running` and
|
|
3
|
+
// the server reports nothing else — never as a guess for a manifest-capable
|
|
4
|
+
// dev server, whose `launchAsset.url` is always the source of truth.
|
|
5
|
+
export const METRO_BUNDLE_PATH =
|
|
6
|
+
'/index.bundle?platform=ios&dev=true&hot=true&minify=false'
|
|
7
|
+
|
|
8
|
+
function isAbsoluteHttpUrl(url: string): boolean {
|
|
9
|
+
return /^https?:\/\//i.test(url)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function isNativeDevBundlePath(pathname: string): boolean {
|
|
13
|
+
return pathname.endsWith('.bundle')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// opt-in (sootbot preview-recording context only): serve a production
|
|
17
|
+
// minified bundle instead of the default dev=true unminified one. a
|
|
18
|
+
// preview run just records the app — it never needs fast-refresh or dev
|
|
19
|
+
// warnings — and the ~28MB unminified dev bundle cold-(re)boots
|
|
20
|
+
// unreliably on small CI runners (tens of seconds when metro is warm,
|
|
21
|
+
// minutes cold, sometimes past any wait-ready budget). a minified bundle
|
|
22
|
+
// parses/executes far faster and reboots reliably. gated on
|
|
23
|
+
// SOOTSIM_PREVIEW_PROD_BUNDLE so normal interactive `sootsim open` keeps
|
|
24
|
+
// dev=true. app-agnostic: rewrites whatever metro/launchAsset advertised.
|
|
25
|
+
function applyPreviewProdBundle(parsed: URL): void {
|
|
26
|
+
if (!process.env.SOOTSIM_PREVIEW_PROD_BUNDLE) return
|
|
27
|
+
parsed.searchParams.set('dev', 'false')
|
|
28
|
+
parsed.searchParams.set('minify', 'true')
|
|
29
|
+
// prod bundles have no HMR; keep metro's cache key consistent.
|
|
30
|
+
if (parsed.searchParams.has('hot')) parsed.searchParams.set('hot', 'false')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function normalizeNativeDevBundleUrl(bundleUrl: string): string {
|
|
34
|
+
try {
|
|
35
|
+
const isAbsolute = isAbsoluteHttpUrl(bundleUrl)
|
|
36
|
+
const parsed = new URL(bundleUrl, 'http://soot.local')
|
|
37
|
+
parsed.pathname = parsed.pathname.replace(/\.\.bundle$/, '.bundle')
|
|
38
|
+
if (!isNativeDevBundlePath(parsed.pathname)) return bundleUrl
|
|
39
|
+
// do NOT force dev=true or minify=false — metro's dev server already
|
|
40
|
+
// defaults to dev mode + unminified, and iOS sim's launchAsset URL
|
|
41
|
+
// omits both params. forcing them gives metro a different cache key
|
|
42
|
+
// for the same bundle. only the prod-bundle override path
|
|
43
|
+
// (demo-upload-specs) sets dev=false&minify=true on purpose.
|
|
44
|
+
// do NOT touch `hot` either. real RN iOS clients load launchAsset.url
|
|
45
|
+
// verbatim — expo's createBundleUrlSearchParams hardcodes hot=false
|
|
46
|
+
// (with a `// TODO: Is this still needed?` comment) for every manifest
|
|
47
|
+
// it emits, and HMR still works on iOS because RN's HMRClient.js
|
|
48
|
+
// polyfill connects to /hot independently. sootsim's HmrClient is the
|
|
49
|
+
// same — connection happens via /hot regardless of this query param —
|
|
50
|
+
// so matching the iOS sim's URL exactly lets metro share its bundle
|
|
51
|
+
// cache between the two clients (otherwise the 28MB+ bundle rebuilds
|
|
52
|
+
// twice on first cold metro request).
|
|
53
|
+
// strip transform.bytecode — metro would return hermes bytecode and our
|
|
54
|
+
// bundle-loader can only execute plain JS.
|
|
55
|
+
parsed.searchParams.delete('transform.bytecode')
|
|
56
|
+
applyPreviewProdBundle(parsed)
|
|
57
|
+
if (isAbsolute) return parsed.toString()
|
|
58
|
+
return `${parsed.pathname}${parsed.search}${parsed.hash}`
|
|
59
|
+
} catch {
|
|
60
|
+
return bundleUrl
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// native-seam manifest — the canonical registry of upstream packages whose
|
|
2
|
+
// native-module spec files we override.
|
|
3
|
+
//
|
|
4
|
+
// the rule: when a guest bundle imports from one of these packages, vite lets
|
|
5
|
+
// the package's JS resolve from node_modules normally. only the listed
|
|
6
|
+
// `seamBasenames` are redirected to our stub. this keeps the upstream JS layer
|
|
7
|
+
// (hooks, helpers, transforms, listeners) running unchanged.
|
|
8
|
+
//
|
|
9
|
+
// adding a new entry:
|
|
10
|
+
// 1. identify upstream's native-module file (look for files calling
|
|
11
|
+
// `requireNativeModule`, `TurboModuleRegistry.getEnforced`,
|
|
12
|
+
// `requireNativeComponent`, or in `src/specs/Native*Module.ts`)
|
|
13
|
+
// 2. write a thin stub at `packages/compat/src/stubs/native-seams/<pkg>.ts`
|
|
14
|
+
// that exports the same default + named exports upstream's seam file
|
|
15
|
+
// exports — except the implementation calls into sootsim's engine.
|
|
16
|
+
// 3. append an entry below. the plugin handles the rest.
|
|
17
|
+
//
|
|
18
|
+
// canonical example: react-native-reanimated. see
|
|
19
|
+
// - `packages/compat/src/stubs/react-native-reanimated.ts` (the seam stub)
|
|
20
|
+
// - `reanimatedNativeSeamRedirect` in vite-plugin.ts (still hard-coded
|
|
21
|
+
// because it has package-specific edge cases — fabricUtils,
|
|
22
|
+
// validate-worklets-version. new entries should use this manifest path
|
|
23
|
+
// for the simple basename-match case.)
|
|
24
|
+
|
|
25
|
+
export interface NativeSeamEntry {
|
|
26
|
+
/**
|
|
27
|
+
* upstream npm package name. all imports whose importer path includes
|
|
28
|
+
* `/<pkg>/` are candidates for redirect.
|
|
29
|
+
*/
|
|
30
|
+
pkg: string
|
|
31
|
+
/**
|
|
32
|
+
* basenames of upstream files to redirect. each entry matches the file
|
|
33
|
+
* name (no extension, no platform suffix like `.ios` / `.android`) of any
|
|
34
|
+
* upstream module imported transitively from within `pkg`.
|
|
35
|
+
*
|
|
36
|
+
* example: if upstream has
|
|
37
|
+
* `node_modules/expo-notifications/src/NotificationsHandler.ts`, list
|
|
38
|
+
* `'NotificationsHandler'` here and we'll redirect any import resolving
|
|
39
|
+
* to that file to our seam stub.
|
|
40
|
+
*/
|
|
41
|
+
seamBasenames: string[]
|
|
42
|
+
/**
|
|
43
|
+
* absolute path to the seam stub. typically
|
|
44
|
+
* `packages/compat/src/stubs/native-seams/<pkg>.ts` — but a single stub
|
|
45
|
+
* file may export every native module the package exposes, so the same
|
|
46
|
+
* `target` can appear in multiple entries if a package has multiple native
|
|
47
|
+
* modules that share an implementation file.
|
|
48
|
+
*
|
|
49
|
+
* authors set this via the `seamPath(<pkg>)` helper below.
|
|
50
|
+
*/
|
|
51
|
+
target: string
|
|
52
|
+
/**
|
|
53
|
+
* notes — short reason this entry exists. shown by the debug logger when
|
|
54
|
+
* `SOOTSIM_NATIVE_SEAM_DEBUG=1` is set.
|
|
55
|
+
*/
|
|
56
|
+
notes?: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
import path from 'node:path'
|
|
60
|
+
import { fileURLToPath } from 'node:url'
|
|
61
|
+
|
|
62
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url))
|
|
63
|
+
const NATIVE_SEAMS_DIR = path.resolve(HERE, '../../compat/src/stubs/native-seams')
|
|
64
|
+
|
|
65
|
+
/** resolve a stub path under `packages/compat/src/stubs/native-seams/`. */
|
|
66
|
+
export function seamPath(basename: string): string {
|
|
67
|
+
return path.resolve(NATIVE_SEAMS_DIR, `${basename}.ts`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* the manifest. agents append entries here during the native-seam migration
|
|
72
|
+
* (plans/compat-stubs-native-seam-audit.md). keep alphabetical by `pkg` to
|
|
73
|
+
* minimise merge conflicts.
|
|
74
|
+
*/
|
|
75
|
+
export const NATIVE_SEAM_MANIFEST: NativeSeamEntry[] = [
|
|
76
|
+
// entries land here during the Phase 1 migration. example shape:
|
|
77
|
+
//
|
|
78
|
+
// {
|
|
79
|
+
// pkg: 'expo-notifications',
|
|
80
|
+
// seamBasenames: [
|
|
81
|
+
// 'NotificationsHandler',
|
|
82
|
+
// 'NotificationsEmitter',
|
|
83
|
+
// 'NotificationScheduler',
|
|
84
|
+
// 'NotificationCategoriesService',
|
|
85
|
+
// 'ServerRegistrationModule',
|
|
86
|
+
// ],
|
|
87
|
+
// target: seamPath('expo-notifications'),
|
|
88
|
+
// notes: 'route through engine NotificationBus',
|
|
89
|
+
// },
|
|
90
|
+
{
|
|
91
|
+
pkg: '@metamask/react-native-search-api',
|
|
92
|
+
// upstream is single-file `index.js`; no sub-imports inside the package
|
|
93
|
+
// to redirect at the basename layer. listed here for documentation parity
|
|
94
|
+
// — the bundle-loader's stub-registry routes the package-entry directly to
|
|
95
|
+
// `stubs/metamask-react-native-search-api.ts`, which pairs the upstream
|
|
96
|
+
// JS wrapper with the native seam below.
|
|
97
|
+
seamBasenames: ['index'],
|
|
98
|
+
target: seamPath('metamask-react-native-search-api'),
|
|
99
|
+
notes:
|
|
100
|
+
'iOS CoreSpotlight + NSUserActivity native seam; pure-JS wrapper class lives at stubs/metamask-react-native-search-api.ts',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
pkg: '@ua/react-native-airship',
|
|
104
|
+
seamBasenames: [
|
|
105
|
+
// src/NativeRNAirship.ts — the RNAirship TurboModule
|
|
106
|
+
'NativeRNAirship',
|
|
107
|
+
// codegen host components (no native backing in sootsim)
|
|
108
|
+
'RNAirshipEmbeddedViewNativeComponent',
|
|
109
|
+
'RNAirshipMessageViewNativeComponent',
|
|
110
|
+
],
|
|
111
|
+
target: seamPath('react-native-airship'),
|
|
112
|
+
notes:
|
|
113
|
+
'push-notification SAAS — noop the SAAS layer, route banners through NotificationBus',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
pkg: 'react-native-background-fetch',
|
|
117
|
+
// src/NativeBackgroundFetch.ts — TurboModuleRegistry.getEnforcing('RNBackgroundFetch')
|
|
118
|
+
seamBasenames: ['NativeBackgroundFetch'],
|
|
119
|
+
target: seamPath('react-native-background-fetch'),
|
|
120
|
+
notes:
|
|
121
|
+
'iOS BGTaskScheduler / Android WorkManager TurboModule — no real scheduler in browser; acknowledge registrations, never fire periodic events',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
pkg: 'expo-asset',
|
|
125
|
+
// src/ExpoAsset.ts — `requireNativeModule('ExpoAsset')`; only
|
|
126
|
+
// `downloadAsync` is on the native surface. all the rest (`Asset`,
|
|
127
|
+
// `AssetHooks`, `AssetSourceResolver`, ...) is pure JS that composes on
|
|
128
|
+
// top.
|
|
129
|
+
seamBasenames: ['ExpoAsset'],
|
|
130
|
+
target: seamPath('expo-asset'),
|
|
131
|
+
notes:
|
|
132
|
+
'expo-modules-core requireNativeModule(ExpoAsset) — only downloadAsync; mirror upstream web build (return remote URL)',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
pkg: '@bam.tech/react-native-image-resizer',
|
|
136
|
+
// upstream is not shipped to most guest bundles via node_modules — it
|
|
137
|
+
// arrives through the bundle-loader stub-registry which routes the
|
|
138
|
+
// package entry to `stubs/bam-react-native-image-resizer.ts`. listed here
|
|
139
|
+
// for documentation parity; vite-path redirect would key on
|
|
140
|
+
// `NativeImageResizer`.
|
|
141
|
+
seamBasenames: ['NativeImageResizer'],
|
|
142
|
+
target: seamPath('bam-react-native-image-resizer'),
|
|
143
|
+
notes:
|
|
144
|
+
'ImageResizer TurboModule — browser-side canvas resize implementing the iOS contain/cover/stretch + onlyScaleDown semantics from ios/ImageResizer.mm',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
pkg: 'react-native-adjust',
|
|
148
|
+
// upstream's `index.js` reads `NativeModules.Adjust` and
|
|
149
|
+
// `NativeModules.AdjustEventEmitter` directly — there is no NativeAdjust
|
|
150
|
+
// spec file. listed for documentation parity; the actual seam delivery is
|
|
151
|
+
// through the bundle-loader stub-registry routing the package entry to
|
|
152
|
+
// `stubs/react-native-adjust.ts`, which imports the native seam from this
|
|
153
|
+
// target.
|
|
154
|
+
seamBasenames: ['index'],
|
|
155
|
+
target: seamPath('react-native-adjust'),
|
|
156
|
+
notes:
|
|
157
|
+
'Adjust attribution SAAS — noop native side (Adjust + AdjustEventEmitter NativeModules), pure-JS classes (AdjustConfig/AdjustEvent/...) live in stubs/react-native-adjust.ts',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
pkg: 'expo-clipboard',
|
|
161
|
+
// src/ExpoClipboard.ts — `requireNativeModule<ExpoClipboardModule>('ExpoClipboard')`.
|
|
162
|
+
// upstream also ships `ExpoClipboard.web.ts` (which we mirror); the
|
|
163
|
+
// redirect catches both `.ts` and `.web.ts` since basenames match.
|
|
164
|
+
seamBasenames: ['ExpoClipboard'],
|
|
165
|
+
target: seamPath('expo-clipboard'),
|
|
166
|
+
notes:
|
|
167
|
+
'expo-modules-core requireNativeModule(ExpoClipboard) — real navigator.clipboard text + ClipboardItem image; mirrors upstream ExpoClipboard.web.ts',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
pkg: 'expo-font',
|
|
171
|
+
// src/ExpoFontLoader.ts — `requireNativeModule<ExpoFontLoaderModule>('ExpoFontLoader')`.
|
|
172
|
+
// we mirror upstream's web variant `ExpoFontLoader.web.ts` (FontFace API
|
|
173
|
+
// + managed <style id="expo-generated-fonts">).
|
|
174
|
+
seamBasenames: ['ExpoFontLoader'],
|
|
175
|
+
target: seamPath('expo-font'),
|
|
176
|
+
notes:
|
|
177
|
+
'expo-modules-core requireNativeModule(ExpoFontLoader) — FontFace API registration; mirrors upstream ExpoFontLoader.web.ts',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
pkg: '@react-native-async-storage/async-storage',
|
|
181
|
+
// src/NativeAsyncStorageModule.ts — TurboModule spec for `RNCAsyncStorage`.
|
|
182
|
+
// src/RCTAsyncStorage.ts — legacy `NativeModules['RNCAsyncStorage']` resolver.
|
|
183
|
+
// both basenames redirect to the same seam; upstream's AsyncStorage.ts
|
|
184
|
+
// imports default from either depending on bridgeless vs paper.
|
|
185
|
+
seamBasenames: ['NativeAsyncStorageModule', 'RCTAsyncStorage'],
|
|
186
|
+
target: seamPath('async-storage'),
|
|
187
|
+
notes:
|
|
188
|
+
'RNCAsyncStorage TurboModule — localStorage-backed; preserves multiMerge JSON deep-merge semantics from upstream iOS module',
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
pkg: 'expo-contacts',
|
|
192
|
+
// src/ExpoContacts.ts — `requireNativeModule('ExpoContacts')`. seam
|
|
193
|
+
// exposes the native iOS module shape through sootsim's in-memory store.
|
|
194
|
+
seamBasenames: ['ExpoContacts'],
|
|
195
|
+
target: seamPath('expo-contacts'),
|
|
196
|
+
notes:
|
|
197
|
+
'expo-modules-core requireNativeModule(ExpoContacts) — granted native iOS-style contacts module backed by an in-memory store',
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
pkg: 'expo-calendar',
|
|
201
|
+
// src/ExpoCalendar.ts — `requireNativeModule('ExpoCalendar')`. seam
|
|
202
|
+
// exposes the native iOS module shape through sootsim's in-memory store.
|
|
203
|
+
seamBasenames: ['ExpoCalendar'],
|
|
204
|
+
target: seamPath('expo-calendar'),
|
|
205
|
+
notes:
|
|
206
|
+
'expo-modules-core requireNativeModule(ExpoCalendar) — granted native iOS-style calendar/reminders module backed by an in-memory store',
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
pkg: 'expo-media-library',
|
|
210
|
+
// src/ExpoMediaLibrary.ts — `requireNativeModule('ExpoMediaLibrary')`.
|
|
211
|
+
// seam mirrors upstream's `ExpoMediaLibrary.web.ts` (refuse permissions
|
|
212
|
+
// + expose MediaType/SortBy constants).
|
|
213
|
+
seamBasenames: ['ExpoMediaLibrary'],
|
|
214
|
+
target: seamPath('expo-media-library'),
|
|
215
|
+
notes:
|
|
216
|
+
'expo-modules-core requireNativeModule(ExpoMediaLibrary) — refuses permissions + exposes MediaType/SortBy enums per upstream ExpoMediaLibrary.web.ts',
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
pkg: 'expo-file-system',
|
|
220
|
+
// src/ExpoFileSystem.ts — `requireNativeModule('ExpoFileSystem')`. seam
|
|
221
|
+
// mirrors upstream's `ExpoFileSystem.web.ts` (warn-not-supported stubs).
|
|
222
|
+
seamBasenames: ['ExpoFileSystem'],
|
|
223
|
+
target: seamPath('expo-file-system'),
|
|
224
|
+
notes:
|
|
225
|
+
'expo-modules-core requireNativeModule(ExpoFileSystem) — warn-not-supported stubs per upstream ExpoFileSystem.web.ts; no general browser fs access',
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
pkg: 'expo-image-picker',
|
|
229
|
+
// src/ExponentImagePicker.ts — `requireNativeModule('ExponentImagePicker')`.
|
|
230
|
+
// seam routes selection requests through sootsim's engine-owned image
|
|
231
|
+
// picker (`SootSim.bridges.imagePicker.pickFromLibrary`) so the same
|
|
232
|
+
// canvas-rendered iOS picker handles every image-source library.
|
|
233
|
+
seamBasenames: ['ExponentImagePicker'],
|
|
234
|
+
target: seamPath('expo-image-picker'),
|
|
235
|
+
notes:
|
|
236
|
+
"expo-modules-core requireNativeModule(ExponentImagePicker) — routes through engine SootSim.bridges.imagePicker (shell-worker ImagePickerView) instead of upstream web build's DOM <input type=file>",
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
pkg: 'expo-camera',
|
|
240
|
+
// upstream splits the native surface across two files:
|
|
241
|
+
// - src/ExpoCamera.ts → requireNativeViewManager('ExpoCamera')
|
|
242
|
+
// - src/ExpoCameraManager.ts → requireNativeModule('ExpoCamera')
|
|
243
|
+
// each basename redirects to a different seam — the view component vs.
|
|
244
|
+
// the imperative module. live preview + capture route through the same
|
|
245
|
+
// engine `camera-stream` module the built-in sootsim Camera app uses,
|
|
246
|
+
// so guest <CameraView> sees the same feed as the OS camera app.
|
|
247
|
+
seamBasenames: ['ExpoCamera'],
|
|
248
|
+
target: seamPath('expo-camera'),
|
|
249
|
+
notes:
|
|
250
|
+
'expo-camera native view manager — host component backed by engine camera-stream (same getUserMedia pipeline as the built-in CameraApp); exposes CameraViewRef methods (takePicture/...) via useImperativeHandle',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
pkg: 'expo-camera',
|
|
254
|
+
seamBasenames: ['ExpoCameraManager'],
|
|
255
|
+
target: seamPath('expo-camera-manager'),
|
|
256
|
+
notes:
|
|
257
|
+
'expo-camera native module — permissions/feature-gates/codecs/Type/FlashMode constants; barcode scanner is noop (no engine scanner integration)',
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
pkg: 'expo-image',
|
|
261
|
+
// upstream splits the native surface across two files:
|
|
262
|
+
// - src/ExpoImage.tsx → requireNativeViewManager('ExpoImage')
|
|
263
|
+
// - src/ImageModule.ts → requireNativeModule('ExpoImage')
|
|
264
|
+
// the view-component seam translates expo-image's prop shape
|
|
265
|
+
// (contentFit, tintColor, source) onto sootsim's existing
|
|
266
|
+
// <sootsim-image> host. no new canvas component is needed — sootsim's
|
|
267
|
+
// image-loader + canvaskit-renderer already handle resizeMode,
|
|
268
|
+
// tintColor, and onLoad/onError lifecycle.
|
|
269
|
+
seamBasenames: ['ExpoImage'],
|
|
270
|
+
target: seamPath('expo-image'),
|
|
271
|
+
notes:
|
|
272
|
+
'expo-image native view — thin prop translator onto sootsim-image host (contentFit→resizeMode, tintColor passthrough); upstream Image.tsx + ImageBackground + useImage resolve from node_modules unchanged',
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
pkg: 'expo-image',
|
|
276
|
+
seamBasenames: ['ImageModule'],
|
|
277
|
+
target: seamPath('expo-image-module'),
|
|
278
|
+
notes:
|
|
279
|
+
'expo-image native module — prefetch/loadAsync route through sootsim image-loader; cache controls noop (browser owns HTTP cache); blurhash encode not yet implemented',
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
pkg: '@notifee/react-native',
|
|
283
|
+
// src/NotifeeNativeModule.ts — the base class NotifeeApiModule extends.
|
|
284
|
+
// upstream also ships .web.ts (returns `{}` from `native`); both
|
|
285
|
+
// basenames redirect to the same seam — a real implementation that
|
|
286
|
+
// routes `this.native.*` calls through the engine NotificationBus.
|
|
287
|
+
seamBasenames: ['NotifeeNativeModule'],
|
|
288
|
+
target: seamPath('notifee'),
|
|
289
|
+
notes:
|
|
290
|
+
'Notifee NotifeeApiModule base class — routes display/cancel/channel/badge calls through engine NotificationBus; tap events fan out via the shared NotifeeJSEventEmitter so onForegroundEvent listeners fire',
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
pkg: 'expo-notifications',
|
|
294
|
+
// five native module spec files, each `requireNativeModule(...)`-shaped.
|
|
295
|
+
// every one redirects to the same `expo-notifications` seam — see
|
|
296
|
+
// `stubs/native-seams/expo-notifications.ts` for the union surface.
|
|
297
|
+
seamBasenames: [
|
|
298
|
+
// src/NotificationsHandlerModule.ts — presentation policy
|
|
299
|
+
'NotificationsHandlerModule',
|
|
300
|
+
// src/NotificationsEmitterModule.ts — last-tap response + listener
|
|
301
|
+
'NotificationsEmitterModule',
|
|
302
|
+
// src/NotificationScheduler.ts — schedule / cancel
|
|
303
|
+
'NotificationScheduler',
|
|
304
|
+
// src/BadgeModule.ts — app badge count
|
|
305
|
+
'BadgeModule',
|
|
306
|
+
// src/ServerRegistrationModule.ts — expo push registration
|
|
307
|
+
'ServerRegistrationModule',
|
|
308
|
+
],
|
|
309
|
+
target: seamPath('expo-notifications'),
|
|
310
|
+
notes:
|
|
311
|
+
'expo-notifications native modules — routes scheduling/badge/installation-id through engine NotificationBus; tap callbacks fan out via the bus event emitters',
|
|
312
|
+
},
|
|
313
|
+
]
|