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,989 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { homedir } from 'node:os'
|
|
3
|
+
import { dirname, join, resolve } from 'node:path'
|
|
4
|
+
import type { SootSimConfig } from '../src/config.ts'
|
|
5
|
+
|
|
6
|
+
export interface DemoApp {
|
|
7
|
+
name: string
|
|
8
|
+
label: string
|
|
9
|
+
dir: string
|
|
10
|
+
preferredPort: number
|
|
11
|
+
framework: 'expo' | 'one' | 'rock'
|
|
12
|
+
runtimeConfig?: SootSimConfig
|
|
13
|
+
sidecars?: DemoSidecar[]
|
|
14
|
+
prepare?: () => void | Promise<void>
|
|
15
|
+
command: (port: number) => { cmd: string; env?: Record<string, string> }
|
|
16
|
+
disabled?: boolean
|
|
17
|
+
note?: string
|
|
18
|
+
// override the dev-server readiness timeout (default 90s). use for stacks
|
|
19
|
+
// like takeout's `bun lite` that bring up postgres + zero + minio + One
|
|
20
|
+
// and need longer to settle on a cold start.
|
|
21
|
+
readyTimeoutMs?: number
|
|
22
|
+
// env vars this demo can consume for credentials/sign-in. the demo launcher
|
|
23
|
+
// prints their presence/absence in its summary so you know whether an
|
|
24
|
+
// app can auto-login. format: { HANDLE: 'natew.bsky.social' } to show a
|
|
25
|
+
// known handle even when stored elsewhere.
|
|
26
|
+
credentials?: {
|
|
27
|
+
envVars?: string[]
|
|
28
|
+
known?: Record<string, string>
|
|
29
|
+
note?: string
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface DemoSidecar {
|
|
34
|
+
name: string
|
|
35
|
+
port: number
|
|
36
|
+
readyPath?: string
|
|
37
|
+
command: () => { cmd: string; env?: Record<string, string> }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const HOME = homedir()
|
|
41
|
+
|
|
42
|
+
function findWorkspaceRoot(startDir: string): string | null {
|
|
43
|
+
let dir = startDir
|
|
44
|
+
while (true) {
|
|
45
|
+
if (
|
|
46
|
+
existsSync(join(dir, 'pnpm-workspace.yaml')) ||
|
|
47
|
+
existsSync(join(dir, 'turbo.json')) ||
|
|
48
|
+
existsSync(join(dir, 'nx.json')) ||
|
|
49
|
+
existsSync(join(dir, 'lerna.json'))
|
|
50
|
+
) {
|
|
51
|
+
return dir
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const packageJsonPath = join(dir, 'package.json')
|
|
55
|
+
if (existsSync(packageJsonPath)) {
|
|
56
|
+
try {
|
|
57
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as {
|
|
58
|
+
workspaces?: unknown
|
|
59
|
+
}
|
|
60
|
+
if (pkg.workspaces) return dir
|
|
61
|
+
} catch {}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const parent = dirname(dir)
|
|
65
|
+
if (parent === dir) return null
|
|
66
|
+
dir = parent
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function resolveWorkspaceScriptPath(
|
|
71
|
+
workspaceRelativePath: string,
|
|
72
|
+
packageRelativePath: string,
|
|
73
|
+
): string {
|
|
74
|
+
const workspaceRoot = findWorkspaceRoot(process.cwd())
|
|
75
|
+
const candidates = [
|
|
76
|
+
workspaceRoot ? resolve(workspaceRoot, workspaceRelativePath) : null,
|
|
77
|
+
resolve(process.cwd(), workspaceRelativePath),
|
|
78
|
+
resolve(process.cwd(), packageRelativePath),
|
|
79
|
+
].filter((candidate): candidate is string => Boolean(candidate))
|
|
80
|
+
|
|
81
|
+
for (const candidate of candidates) {
|
|
82
|
+
if (existsSync(candidate)) return candidate
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return candidates[0] ?? resolve(process.cwd(), workspaceRelativePath)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const getExpensifyProxyScript = () =>
|
|
89
|
+
resolveWorkspaceScriptPath(
|
|
90
|
+
'packages/sootsim-engine/scripts/expensify-web-proxy.ts',
|
|
91
|
+
'scripts/expensify-web-proxy.ts',
|
|
92
|
+
)
|
|
93
|
+
const getRainbowMetadataProxyScript = () =>
|
|
94
|
+
resolveWorkspaceScriptPath(
|
|
95
|
+
'packages/sootsim-engine/scripts/rainbow-metadata-proxy.ts',
|
|
96
|
+
'scripts/rainbow-metadata-proxy.ts',
|
|
97
|
+
)
|
|
98
|
+
const getMattermostRNUtilsNativeModule = () =>
|
|
99
|
+
resolveWorkspaceScriptPath(
|
|
100
|
+
'packages/compat/src/stubs/mattermost-rnutils-native.ts',
|
|
101
|
+
'../compat/src/stubs/mattermost-rnutils-native.ts',
|
|
102
|
+
)
|
|
103
|
+
const getMattermostKeychainNativeModule = () =>
|
|
104
|
+
resolveWorkspaceScriptPath(
|
|
105
|
+
'packages/compat/src/stubs/native-seams/react-native-keychain-manager.ts',
|
|
106
|
+
'../compat/src/stubs/native-seams/react-native-keychain-manager.ts',
|
|
107
|
+
)
|
|
108
|
+
const getMattermostNetworkClientNativeModule = () =>
|
|
109
|
+
resolveWorkspaceScriptPath(
|
|
110
|
+
'packages/compat/src/stubs/mattermost-network-client-native.ts',
|
|
111
|
+
'../compat/src/stubs/mattermost-network-client-native.ts',
|
|
112
|
+
)
|
|
113
|
+
const getMattermostPreviewServerScript = () =>
|
|
114
|
+
resolveWorkspaceScriptPath(
|
|
115
|
+
'packages/sootsim-engine/scripts/mattermost-preview-server.ts',
|
|
116
|
+
'scripts/mattermost-preview-server.ts',
|
|
117
|
+
)
|
|
118
|
+
const EXPENSIFY_NATIVE_PROXY_ENV = {
|
|
119
|
+
USE_NGROK: 'true',
|
|
120
|
+
NGROK_URL: 'http://localhost:9000/',
|
|
121
|
+
SECURE_NGROK_URL: 'http://localhost:9000/',
|
|
122
|
+
}
|
|
123
|
+
const MATTERMOST_DIR = join(HOME, 'github/mattermost-mobile')
|
|
124
|
+
const UNISWAP_REPO_DIR = join(HOME, 'github/uniswap-interface')
|
|
125
|
+
const UNISWAP_APP_DIR = join(UNISWAP_REPO_DIR, 'apps/mobile')
|
|
126
|
+
const UNISWAP_ENV_LOCAL_FILE = join(UNISWAP_REPO_DIR, '.env.defaults.local')
|
|
127
|
+
const UNISWAP_PLACEHOLDER = 'stored-in-.env.local'
|
|
128
|
+
const UNISWAP_DEMO_ENV_MARKER = '# sootsim demo env overrides'
|
|
129
|
+
const UNISWAP_FORCE_UPGRADE_HOOK_FILE = join(
|
|
130
|
+
UNISWAP_REPO_DIR,
|
|
131
|
+
'packages/uniswap/src/features/forceUpgrade/hooks/useForceUpgradeStatus.ts',
|
|
132
|
+
)
|
|
133
|
+
const UNISWAP_FORCE_UPGRADE_NOTIFICATION_FILE = join(
|
|
134
|
+
UNISWAP_REPO_DIR,
|
|
135
|
+
'apps/mobile/src/notification-service/data-sources/createForceUpgradeNotificationDataSource.ts',
|
|
136
|
+
)
|
|
137
|
+
const UNISWAP_FORCE_UPGRADE_PATCH_MARKER = 'SOOTSIM_DEMO_DISABLE_FORCE_UPGRADE'
|
|
138
|
+
|
|
139
|
+
function parseEnvFile(filePath: string): Record<string, string> {
|
|
140
|
+
if (!existsSync(filePath)) return {}
|
|
141
|
+
|
|
142
|
+
const env: Record<string, string> = {}
|
|
143
|
+
const source = readFileSync(filePath, 'utf8')
|
|
144
|
+
for (const rawLine of source.split(/\r?\n/)) {
|
|
145
|
+
const line = rawLine.trim()
|
|
146
|
+
if (!line || line.startsWith('#')) continue
|
|
147
|
+
|
|
148
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/)
|
|
149
|
+
if (!match) continue
|
|
150
|
+
|
|
151
|
+
let value = match[2].trim()
|
|
152
|
+
if (
|
|
153
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
154
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
155
|
+
) {
|
|
156
|
+
value = value.slice(1, -1)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
env[match[1]] = value
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return env
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function isUsableUniswapEnvValue(value: string | undefined): value is string {
|
|
166
|
+
if (!value) return false
|
|
167
|
+
const trimmed = value.trim()
|
|
168
|
+
if (!trimmed) return false
|
|
169
|
+
if (trimmed.includes(UNISWAP_PLACEHOLDER)) return false
|
|
170
|
+
if (trimmed === 'TRADING_API_KEY' || trimmed === 'UNISWAP_API_KEY') return false
|
|
171
|
+
return true
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function pickEnvValue(
|
|
175
|
+
sources: Array<Record<string, string | undefined>>,
|
|
176
|
+
keys: string[],
|
|
177
|
+
): string | undefined {
|
|
178
|
+
for (const source of sources) {
|
|
179
|
+
for (const key of keys) {
|
|
180
|
+
const value = source[key]
|
|
181
|
+
if (isUsableUniswapEnvValue(value)) return value.trim()
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return undefined
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function resolveUniswapDemoEnv(): Record<string, string> {
|
|
188
|
+
const localEnv = parseEnvFile(UNISWAP_ENV_LOCAL_FILE)
|
|
189
|
+
const webEnv = parseEnvFile(join(UNISWAP_REPO_DIR, 'apps/web/.env'))
|
|
190
|
+
const sources: Array<Record<string, string | undefined>> = [
|
|
191
|
+
process.env as Record<string, string | undefined>,
|
|
192
|
+
localEnv,
|
|
193
|
+
webEnv,
|
|
194
|
+
]
|
|
195
|
+
|
|
196
|
+
const env: Record<string, string> = {}
|
|
197
|
+
const bindings: Array<[target: string, aliases: string[]]> = [
|
|
198
|
+
['AMPLITUDE_PROXY_URL_OVERRIDE', ['REACT_APP_AMPLITUDE_PROXY_URL']],
|
|
199
|
+
['QUICKNODE_ENDPOINT_NAME', ['REACT_APP_QUICKNODE_ENDPOINT_NAME']],
|
|
200
|
+
['QUICKNODE_ENDPOINT_TOKEN', ['REACT_APP_QUICKNODE_ENDPOINT_TOKEN']],
|
|
201
|
+
['INFURA_KEY', ['REACT_APP_INFURA_KEY']],
|
|
202
|
+
['STATSIG_API_KEY', ['REACT_APP_STATSIG_API_KEY']],
|
|
203
|
+
['STATSIG_PROXY_URL_OVERRIDE', ['REACT_APP_STATSIG_PROXY_URL']],
|
|
204
|
+
['WALLETCONNECT_PROJECT_ID', ['REACT_APP_WALLET_CONNECT_PROJECT_ID']],
|
|
205
|
+
['WALLETCONNECT_PROJECT_ID_BETA', ['REACT_APP_WALLET_CONNECT_PROJECT_ID']],
|
|
206
|
+
['WALLETCONNECT_PROJECT_ID_DEV', ['REACT_APP_WALLET_CONNECT_PROJECT_ID']],
|
|
207
|
+
['TRADING_API_KEY', ['REACT_APP_TRADING_API_KEY']],
|
|
208
|
+
['UNISWAP_API_KEY', []],
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
for (const [target, aliases] of bindings) {
|
|
212
|
+
const value = pickEnvValue(sources, [target, ...aliases])
|
|
213
|
+
if (!value) continue
|
|
214
|
+
env[target] = value
|
|
215
|
+
for (const alias of aliases) {
|
|
216
|
+
env[alias] = value
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const hasPrivateGatewayKeys =
|
|
221
|
+
isUsableUniswapEnvValue(env.TRADING_API_KEY) &&
|
|
222
|
+
isUsableUniswapEnvValue(env.UNISWAP_API_KEY)
|
|
223
|
+
|
|
224
|
+
if (!hasPrivateGatewayKeys) {
|
|
225
|
+
// fall back to the public web gateway family when private mobile gateway
|
|
226
|
+
// keys are unavailable. this won't unlock every endpoint, but it avoids
|
|
227
|
+
// the worst ios.wallet-specific failures in local sootsim demos.
|
|
228
|
+
const publicGraphqlUrl =
|
|
229
|
+
pickEnvValue(sources, ['GRAPHQL_URL_OVERRIDE', 'REACT_APP_AWS_API_ENDPOINT']) ||
|
|
230
|
+
'https://interface.gateway.uniswap.org/v1/graphql'
|
|
231
|
+
|
|
232
|
+
env.API_BASE_URL_OVERRIDE = 'https://interface.gateway.uniswap.org'
|
|
233
|
+
env.API_BASE_URL_V2_OVERRIDE = 'https://interface.gateway.uniswap.org/v2'
|
|
234
|
+
env.GRAPHQL_URL_OVERRIDE = publicGraphqlUrl
|
|
235
|
+
env.TRADING_API_URL_OVERRIDE =
|
|
236
|
+
'https://trading-api-labs.interface.gateway.uniswap.org'
|
|
237
|
+
env.FOR_API_URL_OVERRIDE =
|
|
238
|
+
'https://for.interface.gateway.uniswap.org/v2/FOR.v1.FORService'
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return env
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function ensureUniswapDemoEnvLocal(): void {
|
|
245
|
+
const existingSource = existsSync(UNISWAP_ENV_LOCAL_FILE)
|
|
246
|
+
? readFileSync(UNISWAP_ENV_LOCAL_FILE, 'utf8')
|
|
247
|
+
: ''
|
|
248
|
+
|
|
249
|
+
if (existingSource && !existingSource.includes(UNISWAP_DEMO_ENV_MARKER)) {
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const env = resolveUniswapDemoEnv()
|
|
254
|
+
const lines = [UNISWAP_DEMO_ENV_MARKER]
|
|
255
|
+
for (const [key, value] of Object.entries(env).sort(([a], [b]) => a.localeCompare(b))) {
|
|
256
|
+
lines.push(`${key}=${JSON.stringify(value)}`)
|
|
257
|
+
}
|
|
258
|
+
lines.push('')
|
|
259
|
+
writeFileSync(UNISWAP_ENV_LOCAL_FILE, `${lines.join('\n')}\n`)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function ensureUniswapForceUpgradePatched(): void {
|
|
263
|
+
const hookNeedle = `export function useForceUpgradeStatus(): ForceUpgradeStatus {\n`
|
|
264
|
+
const hookPatch =
|
|
265
|
+
` // sootsim demo: bypass the force-upgrade gate during local engine demos.\n` +
|
|
266
|
+
` return 'not-required'\n\n`
|
|
267
|
+
const hookLegacyPatch =
|
|
268
|
+
` // sootsim demo: bypass the force-upgrade gate during local engine demos.\n` +
|
|
269
|
+
` if (process.env.${UNISWAP_FORCE_UPGRADE_PATCH_MARKER} === 'true') {\n` +
|
|
270
|
+
` return 'not-required'\n` +
|
|
271
|
+
` }\n\n`
|
|
272
|
+
|
|
273
|
+
const notificationNeedle = ` const getForceUpgradeStatus = (): ForceUpgradeStatus => {\n`
|
|
274
|
+
const notificationPatch =
|
|
275
|
+
` // sootsim demo: bypass the force-upgrade gate during local engine demos.\n` +
|
|
276
|
+
` return 'not-required'\n\n`
|
|
277
|
+
const notificationLegacyPatch =
|
|
278
|
+
` // sootsim demo: bypass the force-upgrade gate during local engine demos.\n` +
|
|
279
|
+
` if (process.env.${UNISWAP_FORCE_UPGRADE_PATCH_MARKER} === 'true') {\n` +
|
|
280
|
+
` return 'not-required'\n` +
|
|
281
|
+
` }\n\n`
|
|
282
|
+
|
|
283
|
+
const patchWithMigration = (
|
|
284
|
+
filePath: string,
|
|
285
|
+
needle: string,
|
|
286
|
+
patch: string,
|
|
287
|
+
legacyPatch: string,
|
|
288
|
+
) => {
|
|
289
|
+
const source = readFileSync(filePath, 'utf8')
|
|
290
|
+
if (source.includes(patch)) return
|
|
291
|
+
if (source.includes(legacyPatch)) {
|
|
292
|
+
writeFileSync(filePath, source.replace(legacyPatch, patch))
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
if (!source.includes(needle)) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
`uniswap demo patch failed: expected snippet not found in ${filePath}`,
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
writeFileSync(filePath, source.replace(needle, `${needle}${patch}`))
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
patchWithMigration(
|
|
304
|
+
UNISWAP_FORCE_UPGRADE_HOOK_FILE,
|
|
305
|
+
hookNeedle,
|
|
306
|
+
hookPatch,
|
|
307
|
+
hookLegacyPatch,
|
|
308
|
+
)
|
|
309
|
+
patchWithMigration(
|
|
310
|
+
UNISWAP_FORCE_UPGRADE_NOTIFICATION_FILE,
|
|
311
|
+
notificationNeedle,
|
|
312
|
+
notificationPatch,
|
|
313
|
+
notificationLegacyPatch,
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const JOPLIN_DIR = join(HOME, 'github/joplin')
|
|
318
|
+
const JOPLIN_APP_DIR = join(JOPLIN_DIR, 'packages/app-mobile')
|
|
319
|
+
// joplin's metro.config.js adds every @joplin/* source dir as a metro
|
|
320
|
+
// `watchFolders` entry. on machines where watchman has
|
|
321
|
+
// `enforce_root_files: true` set globally (soot's setup), each watched
|
|
322
|
+
// root must contain a `.watchmanconfig` or metro crash-exits before
|
|
323
|
+
// serving its first bundle. upstream joplin only ships the file in
|
|
324
|
+
// `app-mobile` and `whisper-voice-typing`; the other watched packages
|
|
325
|
+
// don't have one, so we touch them ourselves. idempotent.
|
|
326
|
+
const JOPLIN_WATCH_ROOTS = [
|
|
327
|
+
'packages/lib',
|
|
328
|
+
'packages/renderer',
|
|
329
|
+
'packages/turndown',
|
|
330
|
+
'packages/turndown-plugin-gfm',
|
|
331
|
+
'packages/editor',
|
|
332
|
+
'packages/tools',
|
|
333
|
+
'packages/utils',
|
|
334
|
+
'packages/fork-htmlparser2',
|
|
335
|
+
'packages/fork-uslug',
|
|
336
|
+
'packages/fork-sax',
|
|
337
|
+
'packages/htmlpack',
|
|
338
|
+
'packages/react-native-saf-x',
|
|
339
|
+
'packages/react-native-alarm-notification',
|
|
340
|
+
]
|
|
341
|
+
|
|
342
|
+
function ensureJoplinWatchmanConfigs(): void {
|
|
343
|
+
if (!existsSync(JOPLIN_DIR)) return
|
|
344
|
+
for (const rel of JOPLIN_WATCH_ROOTS) {
|
|
345
|
+
const dir = join(JOPLIN_DIR, rel)
|
|
346
|
+
if (!existsSync(dir)) continue
|
|
347
|
+
const cfg = join(dir, '.watchmanconfig')
|
|
348
|
+
if (!existsSync(cfg)) writeFileSync(cfg, '{}\n')
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// joplin's metro consumes per-package tsc emit (.js next to .ts), rollup
|
|
353
|
+
// output for `@joplin/turndown(-plugin-gfm)`, and gulp-generated
|
|
354
|
+
// `pluginAssets/index.js` for KaTeX/Mermaid bundles. yarn's root postinstall
|
|
355
|
+
// runs `gulp build` which is supposed to produce all of these, but it fails
|
|
356
|
+
// silently when run on a fresh clone before workspace builds have completed
|
|
357
|
+
// (turndown's `prepare` script doesn't fire in foreach mode). detect the
|
|
358
|
+
// three sentinels and run `yarn buildParallel` if any are missing. one-time
|
|
359
|
+
// cost (~2 minutes), idempotent thereafter.
|
|
360
|
+
const JOPLIN_BUILD_SENTINELS = [
|
|
361
|
+
'packages/lib/models/Setting.js',
|
|
362
|
+
'packages/turndown/lib/turndown.cjs.js',
|
|
363
|
+
'packages/app-mobile/pluginAssets/index.js',
|
|
364
|
+
]
|
|
365
|
+
|
|
366
|
+
function ensureJoplinBuilt(): void {
|
|
367
|
+
if (!existsSync(JOPLIN_DIR)) return
|
|
368
|
+
const missing = JOPLIN_BUILD_SENTINELS.filter(
|
|
369
|
+
(rel) => !existsSync(join(JOPLIN_DIR, rel)),
|
|
370
|
+
)
|
|
371
|
+
if (missing.length === 0) return
|
|
372
|
+
|
|
373
|
+
const { execSync } =
|
|
374
|
+
require('node:child_process') as typeof import('node:child_process')
|
|
375
|
+
// buildParallel walks the workspace topologically and runs `build` in each
|
|
376
|
+
// package, then `yarn tsc`. NO_FLIPPER=1 matches joplin's documented
|
|
377
|
+
// mobile build flag. unset CI so yarn workspaces foreach doesn't reduce
|
|
378
|
+
// parallelism to 1.
|
|
379
|
+
execSync('yarn buildParallel', {
|
|
380
|
+
cwd: JOPLIN_DIR,
|
|
381
|
+
stdio: 'inherit',
|
|
382
|
+
env: { ...process.env, NO_FLIPPER: '1', CI: '' },
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
const stillMissing = JOPLIN_BUILD_SENTINELS.filter(
|
|
386
|
+
(rel) => !existsSync(join(JOPLIN_DIR, rel)),
|
|
387
|
+
)
|
|
388
|
+
if (stillMissing.length > 0) {
|
|
389
|
+
throw new Error(
|
|
390
|
+
`joplin demo: yarn buildParallel did not produce: ${stillMissing.join(', ')}`,
|
|
391
|
+
)
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const RAINBOW_DIR = join(HOME, 'github/rainbow')
|
|
396
|
+
const RAINBOW_GRAPHQL_DIR = join(RAINBOW_DIR, 'src/graphql')
|
|
397
|
+
const RAINBOW_GRAPHQL_CONFIG_FILE = join(RAINBOW_GRAPHQL_DIR, 'config.js')
|
|
398
|
+
const RAINBOW_NETWORKS_FILE = join(RAINBOW_DIR, 'src/references/networks.json')
|
|
399
|
+
const RAINBOW_METADATA_BASE_URL = 'https://metadata.p.rainbow.me'
|
|
400
|
+
const RAINBOW_METADATA_PROXY_PORT = 9011
|
|
401
|
+
const RAINBOW_DEMO_METADATA_BASE_URL = `http://127.0.0.1:${RAINBOW_METADATA_PROXY_PORT}`
|
|
402
|
+
const RAINBOW_PUBLIC_ENS_GRAPHQL_URL =
|
|
403
|
+
'https://api.thegraph.com/subgraphs/name/ensdomains/ens'
|
|
404
|
+
const RAINBOW_DEMO_QUOTE_SIGNER = '0x0000000000000000000000000000000000000000'
|
|
405
|
+
const RAINBOW_DEMO_RELAY_URL = 'https://relay.rainbow.me'
|
|
406
|
+
const RAINBOW_DEMO_MASTER_KEY =
|
|
407
|
+
'sootsim-rainbow-demo-master-key-do-not-use-for-real-wallets'
|
|
408
|
+
const RAINBOW_DEMO_RPC_PROXY_BASE_URL = 'https://rpc.rainbow.me/v1'
|
|
409
|
+
const RAINBOW_DEMO_RPC_API_KEY = ''
|
|
410
|
+
const RAINBOW_DEMO_PUBLIC_RPC_URLS: Record<string, string> = {
|
|
411
|
+
'1': 'https://ethereum-rpc.publicnode.com',
|
|
412
|
+
}
|
|
413
|
+
const RAINBOW_DEMO_SERVICE_API_KEY = 'sootsim-rainbow-demo-api-key'
|
|
414
|
+
const RAINBOW_DEMO_SECURE_WALLET_HASH_KEY =
|
|
415
|
+
'0x736f6f7473696d2d7261696e626f772d64656d6f2d686173682d6b6579000000'
|
|
416
|
+
const RAINBOW_GRAPHQL_SENTINELS = [
|
|
417
|
+
'src/graphql/__generated__/ens.ts',
|
|
418
|
+
'src/graphql/__generated__/metadata.ts',
|
|
419
|
+
'src/graphql/__generated__/metadataPOST.ts',
|
|
420
|
+
]
|
|
421
|
+
|
|
422
|
+
function runRainbowSetupCommand(command: string, cwd: string): void {
|
|
423
|
+
const { execSync } =
|
|
424
|
+
require('node:child_process') as typeof import('node:child_process')
|
|
425
|
+
execSync(command, {
|
|
426
|
+
cwd,
|
|
427
|
+
stdio: 'inherit',
|
|
428
|
+
env: {
|
|
429
|
+
...process.env,
|
|
430
|
+
METADATA_BASE_URL: RAINBOW_METADATA_BASE_URL,
|
|
431
|
+
RAINBOW_RELAY_QUOTE_SIGNER:
|
|
432
|
+
process.env.RAINBOW_RELAY_QUOTE_SIGNER ?? RAINBOW_DEMO_QUOTE_SIGNER,
|
|
433
|
+
},
|
|
434
|
+
})
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function ensureRainbowGraphqlConfig(): void {
|
|
438
|
+
if (!existsSync(RAINBOW_GRAPHQL_DIR)) return
|
|
439
|
+
|
|
440
|
+
const source = existsSync(RAINBOW_GRAPHQL_CONFIG_FILE)
|
|
441
|
+
? readFileSync(RAINBOW_GRAPHQL_CONFIG_FILE, 'utf8')
|
|
442
|
+
: ''
|
|
443
|
+
if (
|
|
444
|
+
source.includes(RAINBOW_PUBLIC_ENS_GRAPHQL_URL) &&
|
|
445
|
+
source.includes(RAINBOW_METADATA_BASE_URL)
|
|
446
|
+
) {
|
|
447
|
+
return
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
writeFileSync(
|
|
451
|
+
RAINBOW_GRAPHQL_CONFIG_FILE,
|
|
452
|
+
`exports.config = {
|
|
453
|
+
ens: {
|
|
454
|
+
__name: 'ens',
|
|
455
|
+
document: './queries/ens.graphql',
|
|
456
|
+
schema: {
|
|
457
|
+
method: 'POST',
|
|
458
|
+
url: '${RAINBOW_PUBLIC_ENS_GRAPHQL_URL}',
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
metadata: {
|
|
462
|
+
__name: 'metadata',
|
|
463
|
+
document: './queries/metadata.graphql',
|
|
464
|
+
schema: { method: 'GET', url: '${RAINBOW_METADATA_BASE_URL}/v1/graph' },
|
|
465
|
+
},
|
|
466
|
+
metadataPOST: {
|
|
467
|
+
__name: 'metadataPOST',
|
|
468
|
+
document: './queries/metadata.graphql',
|
|
469
|
+
schema: { method: 'POST', url: '${RAINBOW_METADATA_BASE_URL}/v1/graph' },
|
|
470
|
+
},
|
|
471
|
+
arc: {
|
|
472
|
+
__name: 'arc',
|
|
473
|
+
document: './queries/arc.graphql',
|
|
474
|
+
schema: {
|
|
475
|
+
method: 'GET',
|
|
476
|
+
url: 'https://arc-graphql.rainbow.me/graphql',
|
|
477
|
+
headers: {
|
|
478
|
+
'x-api-key': 'ARC_GRAPHQL_API_KEY',
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
arcDev: {
|
|
483
|
+
__name: 'arcDev',
|
|
484
|
+
document: './queries/arc.graphql',
|
|
485
|
+
schema: {
|
|
486
|
+
method: 'GET',
|
|
487
|
+
url: 'https://arc-graphql.rainbowdotme.workers.dev/graphql',
|
|
488
|
+
headers: {},
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
`,
|
|
493
|
+
)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function resolveRainbowDemoEnv(): Record<string, string> {
|
|
497
|
+
const env: Record<string, string> = {
|
|
498
|
+
ENABLE_DEV_MODE: '1',
|
|
499
|
+
IS_TESTING: 'false',
|
|
500
|
+
METADATA_BASE_URL:
|
|
501
|
+
process.env.RAINBOW_METADATA_BASE_URL ?? RAINBOW_DEMO_METADATA_BASE_URL,
|
|
502
|
+
ADDYS_API_KEY: process.env.ADDYS_API_KEY ?? RAINBOW_DEMO_SERVICE_API_KEY,
|
|
503
|
+
ADDYS_BASE_URL: process.env.ADDYS_BASE_URL ?? RAINBOW_DEMO_METADATA_BASE_URL,
|
|
504
|
+
PLATFORM_API_KEY: process.env.PLATFORM_API_KEY ?? RAINBOW_DEMO_SERVICE_API_KEY,
|
|
505
|
+
PLATFORM_BASE_URL: process.env.PLATFORM_BASE_URL ?? RAINBOW_DEMO_METADATA_BASE_URL,
|
|
506
|
+
RAINBOW_MASTER_KEY: process.env.RAINBOW_MASTER_KEY ?? RAINBOW_DEMO_MASTER_KEY,
|
|
507
|
+
RAINBOW_RELAY_QUOTE_SIGNER:
|
|
508
|
+
process.env.RAINBOW_RELAY_QUOTE_SIGNER ?? RAINBOW_DEMO_QUOTE_SIGNER,
|
|
509
|
+
RAINBOW_RELAY_URL: process.env.RAINBOW_RELAY_URL ?? RAINBOW_DEMO_RELAY_URL,
|
|
510
|
+
RPC_PROXY_API_KEY_PROD: RAINBOW_DEMO_RPC_API_KEY,
|
|
511
|
+
RPC_PROXY_BASE_URL_PROD:
|
|
512
|
+
process.env.RAINBOW_RPC_PROXY_BASE_URL ??
|
|
513
|
+
process.env.RPC_PROXY_BASE_URL_PROD ??
|
|
514
|
+
RAINBOW_DEMO_RPC_PROXY_BASE_URL,
|
|
515
|
+
SECURE_WALLET_HASH_KEY:
|
|
516
|
+
process.env.SECURE_WALLET_HASH_KEY ?? RAINBOW_DEMO_SECURE_WALLET_HASH_KEY,
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const optionalEnvVars = [
|
|
520
|
+
'ADDYS_API_KEY',
|
|
521
|
+
'ADDYS_BASE_URL',
|
|
522
|
+
'IMGIX_DOMAIN',
|
|
523
|
+
'IMGIX_TOKEN',
|
|
524
|
+
'PLATFORM_API_KEY',
|
|
525
|
+
'PLATFORM_BASE_URL',
|
|
526
|
+
'RAINBOW_TEST_WALLET',
|
|
527
|
+
'RAINBOW_RELAY_API_KEY',
|
|
528
|
+
'RAINBOW_RELAY_URL',
|
|
529
|
+
'SECURE_WALLET_HASH_KEY',
|
|
530
|
+
'TOKEN_SEARCH_URL',
|
|
531
|
+
'WC_PROJECT_ID',
|
|
532
|
+
]
|
|
533
|
+
|
|
534
|
+
for (const key of optionalEnvVars) {
|
|
535
|
+
const value = process.env[key]
|
|
536
|
+
if (value) env[key] = value
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (!env.WC_PROJECT_ID && process.env.RAINBOW_WALLETCONNECT_PROJECT_ID) {
|
|
540
|
+
env.WC_PROJECT_ID = process.env.RAINBOW_WALLETCONNECT_PROJECT_ID
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return env
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function ensureRainbowDemoNetworks(): void {
|
|
547
|
+
if (!existsSync(RAINBOW_NETWORKS_FILE)) return
|
|
548
|
+
|
|
549
|
+
const payload = JSON.parse(readFileSync(RAINBOW_NETWORKS_FILE, 'utf8')) as {
|
|
550
|
+
networks?: Array<{
|
|
551
|
+
id?: string
|
|
552
|
+
defaultRPC?: {
|
|
553
|
+
url?: string
|
|
554
|
+
}
|
|
555
|
+
}>
|
|
556
|
+
}
|
|
557
|
+
if (!Array.isArray(payload.networks)) return
|
|
558
|
+
|
|
559
|
+
let changed = false
|
|
560
|
+
for (const network of payload.networks) {
|
|
561
|
+
const url = network.id ? RAINBOW_DEMO_PUBLIC_RPC_URLS[network.id] : undefined
|
|
562
|
+
if (!url || !network.defaultRPC) continue
|
|
563
|
+
if (network.defaultRPC.url === url) continue
|
|
564
|
+
|
|
565
|
+
network.defaultRPC.url = url
|
|
566
|
+
changed = true
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (changed) {
|
|
570
|
+
writeFileSync(RAINBOW_NETWORKS_FILE, `${JSON.stringify(payload)}\n`)
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function ensureRainbowSetup(): void {
|
|
575
|
+
if (!existsSync(RAINBOW_DIR)) return
|
|
576
|
+
|
|
577
|
+
ensureRainbowGraphqlConfig()
|
|
578
|
+
|
|
579
|
+
if (!existsSync(join(RAINBOW_GRAPHQL_DIR, 'node_modules/.bin/graphql-codegen'))) {
|
|
580
|
+
runRainbowSetupCommand('fnm exec --using=22 yarn install', RAINBOW_GRAPHQL_DIR)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const missingGraphql = RAINBOW_GRAPHQL_SENTINELS.some(
|
|
584
|
+
(rel) => !existsSync(join(RAINBOW_DIR, rel)),
|
|
585
|
+
)
|
|
586
|
+
if (missingGraphql) {
|
|
587
|
+
runRainbowSetupCommand('fnm exec --using=22 yarn codegen', RAINBOW_GRAPHQL_DIR)
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (!existsSync(RAINBOW_NETWORKS_FILE)) {
|
|
591
|
+
runRainbowSetupCommand('fnm exec --using=22 yarn fetch:networks', RAINBOW_DIR)
|
|
592
|
+
}
|
|
593
|
+
ensureRainbowDemoNetworks()
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const ARTSY_DIR = join(HOME, 'github/eigen')
|
|
597
|
+
const ARTSY_KEYS_FILE = join(ARTSY_DIR, 'keys.shared.json')
|
|
598
|
+
const ARTSY_METAFLAGS_FILE = join(ARTSY_DIR, 'metaflags.json')
|
|
599
|
+
const ARTSY_RELAY_SENTINEL = join(ARTSY_DIR, 'src/__generated__/.relay-complete')
|
|
600
|
+
|
|
601
|
+
function readArtsyKeysPayload():
|
|
602
|
+
| { secure?: Record<string, string>; public?: Record<string, unknown> }
|
|
603
|
+
| undefined {
|
|
604
|
+
if (!existsSync(ARTSY_KEYS_FILE)) return undefined
|
|
605
|
+
|
|
606
|
+
try {
|
|
607
|
+
const parsed = JSON.parse(readFileSync(ARTSY_KEYS_FILE, 'utf8')) as {
|
|
608
|
+
secure?: Record<string, string>
|
|
609
|
+
public?: Record<string, unknown>
|
|
610
|
+
}
|
|
611
|
+
if (!parsed || typeof parsed !== 'object') return undefined
|
|
612
|
+
|
|
613
|
+
const secure =
|
|
614
|
+
parsed.secure && typeof parsed.secure === 'object' ? parsed.secure : undefined
|
|
615
|
+
const publicKeys =
|
|
616
|
+
parsed.public && typeof parsed.public === 'object' ? parsed.public : undefined
|
|
617
|
+
|
|
618
|
+
if (!secure && !publicKeys) return undefined
|
|
619
|
+
return { secure, public: publicKeys }
|
|
620
|
+
} catch {
|
|
621
|
+
return undefined
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
function resolveArtsyRuntimeConfig(): SootSimConfig | undefined {
|
|
626
|
+
const email = process.env.SOOTSIM_ARTSY_EMAIL ?? process.env.MAESTRO_TEST_EMAIL
|
|
627
|
+
const password = process.env.SOOTSIM_ARTSY_PASSWORD ?? process.env.MAESTRO_TEST_PASSWORD
|
|
628
|
+
const keys = readArtsyKeysPayload()
|
|
629
|
+
|
|
630
|
+
const env: Record<string, string> = {}
|
|
631
|
+
if (email && password) {
|
|
632
|
+
env.SOOTSIM_LAUNCH_ARGUMENTS = JSON.stringify({
|
|
633
|
+
email,
|
|
634
|
+
password,
|
|
635
|
+
useMaestroInit: true,
|
|
636
|
+
})
|
|
637
|
+
}
|
|
638
|
+
if (keys) {
|
|
639
|
+
env.SOOTSIM_REACT_NATIVE_KEYS_JSON = JSON.stringify(keys)
|
|
640
|
+
}
|
|
641
|
+
if (Object.keys(env).length === 0) return undefined
|
|
642
|
+
|
|
643
|
+
return {
|
|
644
|
+
env,
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function ensureArtsySetup(): void {
|
|
649
|
+
if (!existsSync(ARTSY_DIR)) return
|
|
650
|
+
const { execSync } =
|
|
651
|
+
require('node:child_process') as typeof import('node:child_process')
|
|
652
|
+
|
|
653
|
+
// yarn 4.10.3's bundled git cloner passes `-c core.autocrlf=false` as a
|
|
654
|
+
// single argv token, which git 2.53+ rejects with `invalid key: core.autocrlf`
|
|
655
|
+
// (note the leading space git sees after stripping `-c`). older gits
|
|
656
|
+
// silently tolerated the space. patch the release binary in-place to split
|
|
657
|
+
// the token. idempotent: replacement is a no-op after the first run.
|
|
658
|
+
const yarnRelease = join(ARTSY_DIR, '.yarn/releases/yarn-4.10.3.cjs')
|
|
659
|
+
if (existsSync(yarnRelease)) {
|
|
660
|
+
const src = readFileSync(yarnRelease, 'utf8')
|
|
661
|
+
const needle = '["clone","-c core.autocrlf=false",'
|
|
662
|
+
if (src.includes(needle)) {
|
|
663
|
+
writeFileSync(
|
|
664
|
+
yarnRelease,
|
|
665
|
+
src.replace(needle, '["clone","-c","core.autocrlf=false",'),
|
|
666
|
+
)
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// install deps if the yarn state file is missing. use
|
|
671
|
+
// YARN_CHECKSUM_BEHAVIOR=update because the lockfile's hash for the
|
|
672
|
+
// `react-native-launch-arguments` git dep won't match archives produced
|
|
673
|
+
// after the clone-fix above (yarn recomputes tree hashes per fresh fetch).
|
|
674
|
+
if (!existsSync(join(ARTSY_DIR, 'node_modules/.yarn-state.yml'))) {
|
|
675
|
+
execSync('yarn install', {
|
|
676
|
+
cwd: ARTSY_DIR,
|
|
677
|
+
stdio: 'inherit',
|
|
678
|
+
env: { ...process.env, YARN_CHECKSUM_BEHAVIOR: 'update' },
|
|
679
|
+
})
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// setup:oss creates keys.shared.json, metaflags.json, a phony
|
|
683
|
+
// GoogleService-Info.plist, and pulls OSS fonts. the aws font fetch fails
|
|
684
|
+
// without aws cli — harmless for a metro-only demo, fonts fall back.
|
|
685
|
+
if (!existsSync(ARTSY_KEYS_FILE) || !existsSync(ARTSY_METAFLAGS_FILE)) {
|
|
686
|
+
try {
|
|
687
|
+
execSync('yarn setup:oss', { cwd: ARTSY_DIR, stdio: 'inherit' })
|
|
688
|
+
} catch {
|
|
689
|
+
// setup-oss-fonts exits non-zero when `aws` is missing. ensure the
|
|
690
|
+
// two critical sentinel files exist before giving up.
|
|
691
|
+
if (!existsSync(ARTSY_KEYS_FILE) || !existsSync(ARTSY_METAFLAGS_FILE)) {
|
|
692
|
+
throw new Error('artsy demo: setup:oss did not create keys/metaflags')
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// eigen pulls react-native-launch-arguments as a git dep. its package.json
|
|
698
|
+
// points `main` at `dist/index.js`, which is produced by the package's
|
|
699
|
+
// `prepare` tsc build — skipped because `.yarnrc.yml` sets
|
|
700
|
+
// `enableScripts: false`. there's no shipped tsconfig either, so running
|
|
701
|
+
// tsc post-hoc fails. simplest fix: point `main` at the TS source; metro
|
|
702
|
+
// resolves `.ts` natively. idempotent.
|
|
703
|
+
const rnlaPkgJson = join(
|
|
704
|
+
ARTSY_DIR,
|
|
705
|
+
'node_modules/react-native-launch-arguments/package.json',
|
|
706
|
+
)
|
|
707
|
+
if (existsSync(rnlaPkgJson)) {
|
|
708
|
+
const raw = readFileSync(rnlaPkgJson, 'utf8')
|
|
709
|
+
if (raw.includes('"dist/index.js"')) {
|
|
710
|
+
writeFileSync(rnlaPkgJson, raw.replace('"dist/index.js"', '"src/index.ts"'))
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// relay compiler generates src/__generated__/**. eigen's `yarn start`
|
|
715
|
+
// script runs `relay-compiler --watch` via concurrently, but for the
|
|
716
|
+
// demo we just need a one-shot generation before metro boots.
|
|
717
|
+
if (!existsSync(ARTSY_RELAY_SENTINEL)) {
|
|
718
|
+
execSync('yarn relay', { cwd: ARTSY_DIR, stdio: 'inherit' })
|
|
719
|
+
writeFileSync(ARTSY_RELAY_SENTINEL, '')
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
export const APPS: DemoApp[] = [
|
|
724
|
+
{
|
|
725
|
+
name: 'bluesky',
|
|
726
|
+
label: 'Bluesky',
|
|
727
|
+
dir: join(HOME, 'github/bluesky'),
|
|
728
|
+
preferredPort: 8082,
|
|
729
|
+
framework: 'expo',
|
|
730
|
+
command: (p) => ({ cmd: `npx expo start --port ${p}` }),
|
|
731
|
+
credentials: {
|
|
732
|
+
envVars: ['SOOTSIM_BLUESKY_PASSWORD'],
|
|
733
|
+
known: { HANDLE: 'natew.bsky.social' },
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
name: '3pc',
|
|
738
|
+
label: '3PunchConvo',
|
|
739
|
+
dir: join(HOME, 'lightstrike-labs/three-punch-convo-app/apps/one'),
|
|
740
|
+
preferredPort: 8081,
|
|
741
|
+
framework: 'one',
|
|
742
|
+
command: (p) => ({ cmd: 'npx one dev', env: { ONE_PORT: String(p) } }),
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
name: 'uniswap',
|
|
746
|
+
label: 'Uniswap',
|
|
747
|
+
dir: UNISWAP_APP_DIR,
|
|
748
|
+
preferredPort: 8085,
|
|
749
|
+
framework: 'expo',
|
|
750
|
+
prepare: () => {
|
|
751
|
+
ensureUniswapDemoEnvLocal()
|
|
752
|
+
ensureUniswapForceUpgradePatched()
|
|
753
|
+
},
|
|
754
|
+
command: (p) => ({
|
|
755
|
+
cmd: `npx expo start --clear --port ${p}`,
|
|
756
|
+
// prefer the real local mobile env when present, otherwise fall back
|
|
757
|
+
// to Uniswap's checked-in public web RPC settings so demo boots cleanly.
|
|
758
|
+
env: resolveUniswapDemoEnv(),
|
|
759
|
+
}),
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
name: 'takeout',
|
|
763
|
+
label: 'Takeout',
|
|
764
|
+
dir: join(HOME, 'takeout'),
|
|
765
|
+
preferredPort: 8086,
|
|
766
|
+
framework: 'one',
|
|
767
|
+
// takeout needs more than Metro for the demo to actually work: better-auth
|
|
768
|
+
// (login), zero-cache (sync), and a postgres for both. `bun lite` brings
|
|
769
|
+
// up the orez-backed stack (PG + zero + s3 in one binary) plus the One
|
|
770
|
+
// dev server. takeout's env system shifts every port (web, pg, zero,
|
|
771
|
+
// minio) uniformly by PORT_OFFSET, so we derive offset = port - 8081
|
|
772
|
+
// (the base web port) to keep all backend ports clear of the default
|
|
773
|
+
// dev stack while pinning One to the demo slot. OREZ_DATA_DIR is isolated
|
|
774
|
+
// to a per-demo path so we don't fight a soot dev orez that may already
|
|
775
|
+
// be holding pglite locks on ~/takeout/.orez (soot can attach takeout as
|
|
776
|
+
// a project and spin up its own orez against the same data dir).
|
|
777
|
+
readyTimeoutMs: 240_000,
|
|
778
|
+
command: (p) => ({
|
|
779
|
+
cmd: 'bun lite',
|
|
780
|
+
env: {
|
|
781
|
+
PORT_OFFSET: String(p - 8081),
|
|
782
|
+
OREZ_DATA_DIR: `${HOME}/.cache/sootsim-demo/takeout-orez`,
|
|
783
|
+
},
|
|
784
|
+
}),
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
name: 'expensify',
|
|
788
|
+
label: 'Expensify',
|
|
789
|
+
dir: join(HOME, 'github/expensify'),
|
|
790
|
+
preferredPort: 8087,
|
|
791
|
+
framework: 'rock',
|
|
792
|
+
runtimeConfig: {
|
|
793
|
+
env: EXPENSIFY_NATIVE_PROXY_ENV,
|
|
794
|
+
},
|
|
795
|
+
sidecars: [
|
|
796
|
+
{
|
|
797
|
+
name: 'web-proxy',
|
|
798
|
+
port: 9000,
|
|
799
|
+
readyPath: '/api/Ping',
|
|
800
|
+
command: () => ({
|
|
801
|
+
cmd: `bun ${JSON.stringify(getExpensifyProxyScript())}`,
|
|
802
|
+
env: EXPENSIFY_NATIVE_PROXY_ENV,
|
|
803
|
+
}),
|
|
804
|
+
},
|
|
805
|
+
],
|
|
806
|
+
command: (p) => ({
|
|
807
|
+
cmd: `fnm exec --using=20.20.0 npx rock start --port ${p} --no-interactive`,
|
|
808
|
+
env: EXPENSIFY_NATIVE_PROXY_ENV,
|
|
809
|
+
}),
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
name: 'artsy',
|
|
813
|
+
label: 'Artsy',
|
|
814
|
+
dir: ARTSY_DIR,
|
|
815
|
+
preferredPort: 8088,
|
|
816
|
+
framework: 'expo',
|
|
817
|
+
runtimeConfig: resolveArtsyRuntimeConfig(),
|
|
818
|
+
prepare: () => {
|
|
819
|
+
ensureArtsySetup()
|
|
820
|
+
},
|
|
821
|
+
command: (p) => ({
|
|
822
|
+
// eigen's `yarn start` wraps `react-native start` with a relay watcher
|
|
823
|
+
// via concurrently; for the demo we run relay once in prepare and
|
|
824
|
+
// invoke the metro server directly so --port is respected.
|
|
825
|
+
cmd: `npx react-native start --port ${p}`,
|
|
826
|
+
}),
|
|
827
|
+
credentials: {
|
|
828
|
+
envVars: ['SOOTSIM_ARTSY_EMAIL', 'SOOTSIM_ARTSY_PASSWORD'],
|
|
829
|
+
note: 'auto-login reuses Artsy’s built-in Maestro launch-arguments hook',
|
|
830
|
+
},
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
name: 'rainbow',
|
|
834
|
+
label: 'Rainbow',
|
|
835
|
+
dir: RAINBOW_DIR,
|
|
836
|
+
preferredPort: 8089,
|
|
837
|
+
framework: 'rock',
|
|
838
|
+
sidecars: [
|
|
839
|
+
{
|
|
840
|
+
name: 'metadata-proxy',
|
|
841
|
+
port: RAINBOW_METADATA_PROXY_PORT,
|
|
842
|
+
readyPath: '/health',
|
|
843
|
+
command: () => ({
|
|
844
|
+
cmd: `bun ${JSON.stringify(getRainbowMetadataProxyScript())}`,
|
|
845
|
+
env: {
|
|
846
|
+
PORT: String(RAINBOW_METADATA_PROXY_PORT),
|
|
847
|
+
RAINBOW_PUBLIC_RPC_URLS: JSON.stringify(RAINBOW_DEMO_PUBLIC_RPC_URLS),
|
|
848
|
+
RAINBOW_UPSTREAM_METADATA_BASE_URL: RAINBOW_METADATA_BASE_URL,
|
|
849
|
+
},
|
|
850
|
+
}),
|
|
851
|
+
},
|
|
852
|
+
],
|
|
853
|
+
prepare: () => {
|
|
854
|
+
ensureRainbowSetup()
|
|
855
|
+
},
|
|
856
|
+
command: (p) => ({
|
|
857
|
+
cmd: `fnm exec --using=22 yarn start --port ${p} --reset-cache`,
|
|
858
|
+
env: resolveRainbowDemoEnv(),
|
|
859
|
+
}),
|
|
860
|
+
credentials: {
|
|
861
|
+
envVars: [
|
|
862
|
+
'RAINBOW_TEST_WALLET',
|
|
863
|
+
'RAINBOW_WALLETCONNECT_PROJECT_ID',
|
|
864
|
+
'WC_PROJECT_ID',
|
|
865
|
+
'IMGIX_DOMAIN',
|
|
866
|
+
'IMGIX_TOKEN',
|
|
867
|
+
],
|
|
868
|
+
note: 'launcher supplies a demo encryption key and public mainnet RPC; use only a public throwaway mnemonic for RAINBOW_TEST_WALLET',
|
|
869
|
+
},
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
name: 'rocket-chat',
|
|
873
|
+
label: 'Rocket.Chat',
|
|
874
|
+
dir: join(HOME, 'github/Rocket.Chat.ReactNative'),
|
|
875
|
+
preferredPort: 8093,
|
|
876
|
+
framework: 'expo',
|
|
877
|
+
command: (p) => ({
|
|
878
|
+
cmd: `npx react-native start --port ${p}`,
|
|
879
|
+
env: { RUNNING_E2E_TESTS: 'true' },
|
|
880
|
+
}),
|
|
881
|
+
credentials: {
|
|
882
|
+
envVars: [
|
|
883
|
+
'ROCKET_CHAT_DEMO_SERVER',
|
|
884
|
+
'ROCKET_CHAT_DEMO_USERNAME',
|
|
885
|
+
'ROCKET_CHAT_DEMO_PASSWORD',
|
|
886
|
+
],
|
|
887
|
+
known: { SERVER: 'https://mobile.qa.rocket.chat' },
|
|
888
|
+
note: 'use packages/sootsim-engine/scripts/rocket-chat-demo-auth.ts to create/login a disposable QA user and print the rocketchat://auth deep link',
|
|
889
|
+
},
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
name: 'mattermost',
|
|
893
|
+
label: 'Mattermost',
|
|
894
|
+
dir: MATTERMOST_DIR,
|
|
895
|
+
preferredPort: 8090,
|
|
896
|
+
framework: 'expo',
|
|
897
|
+
sidecars: [
|
|
898
|
+
{
|
|
899
|
+
name: 'preview-server',
|
|
900
|
+
port: 8065,
|
|
901
|
+
readyPath: '/api/v4/system/ping',
|
|
902
|
+
command: () => ({
|
|
903
|
+
cmd: `bun ${JSON.stringify(getMattermostPreviewServerScript())}`,
|
|
904
|
+
}),
|
|
905
|
+
},
|
|
906
|
+
],
|
|
907
|
+
runtimeConfig: {
|
|
908
|
+
modules: {
|
|
909
|
+
// mattermost patches react-native-keychain's JS entry in its own
|
|
910
|
+
// repo; run that package and provide only the native manager seam.
|
|
911
|
+
'react-native-keychain': false,
|
|
912
|
+
'dist/assets/config.json': {
|
|
913
|
+
inline: {
|
|
914
|
+
AuthUrlScheme: 'mmauth://',
|
|
915
|
+
AuthUrlSchemeDev: 'mmauthbeta://',
|
|
916
|
+
DefaultServerUrl: 'http://localhost:8065',
|
|
917
|
+
DefaultServerName: 'Mattermost Demo',
|
|
918
|
+
TestServerUrl: 'http://localhost:8065',
|
|
919
|
+
AutoSelectServerUrl: true,
|
|
920
|
+
WebsiteURL: 'https://mattermost.com',
|
|
921
|
+
ServerNoticeURL:
|
|
922
|
+
'https://github.com/mattermost/mattermost-server/blob/master/NOTICE.txt',
|
|
923
|
+
MobileNoticeURL:
|
|
924
|
+
'https://github.com/mattermost/mattermost-mobile/blob/master/NOTICE.txt',
|
|
925
|
+
RudderApiKey: '',
|
|
926
|
+
SentryEnabled: false,
|
|
927
|
+
SentryDsnIos: '',
|
|
928
|
+
SentryDsnAndroid: '',
|
|
929
|
+
SentryOptions: {
|
|
930
|
+
deactivateStacktraceMerging: true,
|
|
931
|
+
autoBreadcrumbs: {
|
|
932
|
+
xhr: false,
|
|
933
|
+
console: true,
|
|
934
|
+
},
|
|
935
|
+
severityLevelFilter: ['fatal'],
|
|
936
|
+
},
|
|
937
|
+
ShowReview: false,
|
|
938
|
+
ShowOnboarding: false,
|
|
939
|
+
ExperimentalNormalizeMarkdownLinks: false,
|
|
940
|
+
CustomRequestHeaders: {},
|
|
941
|
+
CollectNetworkMetrics: false,
|
|
942
|
+
},
|
|
943
|
+
},
|
|
944
|
+
},
|
|
945
|
+
nativeModules: {
|
|
946
|
+
RNKeychainManager: { file: getMattermostKeychainNativeModule() },
|
|
947
|
+
RNUtils: { file: getMattermostRNUtilsNativeModule() },
|
|
948
|
+
GenericClient: { file: getMattermostNetworkClientNativeModule() },
|
|
949
|
+
ApiClient: { file: getMattermostNetworkClientNativeModule() },
|
|
950
|
+
WebSocketClient: { file: getMattermostNetworkClientNativeModule() },
|
|
951
|
+
},
|
|
952
|
+
},
|
|
953
|
+
command: (p) => ({
|
|
954
|
+
cmd: `npx react-native start --host 127.0.0.1 --port ${p}`,
|
|
955
|
+
}),
|
|
956
|
+
credentials: {
|
|
957
|
+
known: {
|
|
958
|
+
SERVER: 'http://localhost:8065',
|
|
959
|
+
USERNAME: 'demo',
|
|
960
|
+
PASSWORD: 'DemoPassword1!',
|
|
961
|
+
},
|
|
962
|
+
note: 'local mattermost-preview seeded through the real REST API; no signup or OTP needed',
|
|
963
|
+
},
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
name: 'joplin',
|
|
967
|
+
label: 'Joplin',
|
|
968
|
+
dir: JOPLIN_APP_DIR,
|
|
969
|
+
preferredPort: 8084,
|
|
970
|
+
framework: 'expo',
|
|
971
|
+
// joplin is local-first: sync.target defaults to 0 ("None") and the
|
|
972
|
+
// mobile startup runs WelcomeUtils.install() on first launch, which
|
|
973
|
+
// seeds a "Welcome!" folder + welcome notes. no login or external
|
|
974
|
+
// credentials are needed for a usable demo — just boot it. tenant
|
|
975
|
+
// bedrock SQLite (via react-native-sqlite-storage stub) carries the
|
|
976
|
+
// seeded notes across reloads.
|
|
977
|
+
prepare: () => {
|
|
978
|
+
ensureJoplinWatchmanConfigs()
|
|
979
|
+
ensureJoplinBuilt()
|
|
980
|
+
},
|
|
981
|
+
command: (p) => ({
|
|
982
|
+
cmd: `npx expo start --port ${p}`,
|
|
983
|
+
env: { BROWSERSLIST_IGNORE_OLD_DATA: 'true' },
|
|
984
|
+
}),
|
|
985
|
+
credentials: {
|
|
986
|
+
note: 'no login required — sync.target=0 (None), seed via WelcomeUtils',
|
|
987
|
+
},
|
|
988
|
+
},
|
|
989
|
+
]
|