@axonpack/preview 0.0.0-stage → 0.1.0

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.
Files changed (182) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +118 -2
  4. package/android/build.gradle +21 -0
  5. package/android/consumer-rules.pro +3 -0
  6. package/android/src/main/java/expo/modules/axonpackpreview/AxonpackPreviewModule.kt +72 -0
  7. package/android/src/main/java/expo/modules/axonpackpreview/BundleLoaderOverride.kt +41 -0
  8. package/android/src/main/java/expo/modules/axonpackpreview/HermesHeader.kt +24 -0
  9. package/android/src/main/java/expo/modules/axonpackpreview/PreviewPackage.kt +76 -0
  10. package/android/src/main/java/expo/modules/axonpackpreview/PreviewState.kt +295 -0
  11. package/app.plugin.js +112 -0
  12. package/bin/preview.js +2 -0
  13. package/build/cli.cjs +1465 -0
  14. package/build/cli.d.ts +3 -0
  15. package/build/cli.d.ts.map +1 -0
  16. package/build/cli.js +164 -0
  17. package/build/cli.js.map +1 -0
  18. package/build/components/preview-list/preview-list.component.d.ts +13 -0
  19. package/build/components/preview-list/preview-list.component.d.ts.map +1 -0
  20. package/build/components/preview-list/preview-list.component.js +316 -0
  21. package/build/components/preview-list/preview-list.component.js.map +1 -0
  22. package/build/components/preview-list/preview-list.types.d.ts +59 -0
  23. package/build/components/preview-list/preview-list.types.d.ts.map +1 -0
  24. package/build/components/preview-list/preview-list.types.js +2 -0
  25. package/build/components/preview-list/preview-list.types.js.map +1 -0
  26. package/build/components/preview-provider/preview-provider.component.d.ts +12 -0
  27. package/build/components/preview-provider/preview-provider.component.d.ts.map +1 -0
  28. package/build/components/preview-provider/preview-provider.component.js +19 -0
  29. package/build/components/preview-provider/preview-provider.component.js.map +1 -0
  30. package/build/constants/dev-preview-servers/dev-preview-servers.const.d.ts +26 -0
  31. package/build/constants/dev-preview-servers/dev-preview-servers.const.d.ts.map +1 -0
  32. package/build/constants/dev-preview-servers/dev-preview-servers.const.js +9 -0
  33. package/build/constants/dev-preview-servers/dev-preview-servers.const.js.map +1 -0
  34. package/build/constants/preview-list/theme.const.d.ts +5 -0
  35. package/build/constants/preview-list/theme.const.d.ts.map +1 -0
  36. package/build/constants/preview-list/theme.const.js +65 -0
  37. package/build/constants/preview-list/theme.const.js.map +1 -0
  38. package/build/index.d.ts +24 -0
  39. package/build/index.d.ts.map +1 -0
  40. package/build/index.js +16 -0
  41. package/build/index.js.map +1 -0
  42. package/build/services/cli/config.service.d.ts +13 -0
  43. package/build/services/cli/config.service.d.ts.map +1 -0
  44. package/build/services/cli/config.service.js +39 -0
  45. package/build/services/cli/config.service.js.map +1 -0
  46. package/build/services/cli/project.service.d.ts +25 -0
  47. package/build/services/cli/project.service.d.ts.map +1 -0
  48. package/build/services/cli/project.service.js +81 -0
  49. package/build/services/cli/project.service.js.map +1 -0
  50. package/build/services/cli/title.service.d.ts +15 -0
  51. package/build/services/cli/title.service.d.ts.map +1 -0
  52. package/build/services/cli/title.service.js +24 -0
  53. package/build/services/cli/title.service.js.map +1 -0
  54. package/build/services/dev-preview-servers/discover.service.d.ts +14 -0
  55. package/build/services/dev-preview-servers/discover.service.d.ts.map +1 -0
  56. package/build/services/dev-preview-servers/discover.service.js +106 -0
  57. package/build/services/dev-preview-servers/discover.service.js.map +1 -0
  58. package/build/services/native/build-info.service.d.ts +11 -0
  59. package/build/services/native/build-info.service.d.ts.map +1 -0
  60. package/build/services/native/build-info.service.js +18 -0
  61. package/build/services/native/build-info.service.js.map +1 -0
  62. package/build/services/native/native.service.d.ts +24 -0
  63. package/build/services/native/native.service.d.ts.map +1 -0
  64. package/build/services/native/native.service.js +13 -0
  65. package/build/services/native/native.service.js.map +1 -0
  66. package/build/services/previews/download.service.d.ts +14 -0
  67. package/build/services/previews/download.service.d.ts.map +1 -0
  68. package/build/services/previews/download.service.js +66 -0
  69. package/build/services/previews/download.service.js.map +1 -0
  70. package/build/services/previews/local-previews.service.d.ts +25 -0
  71. package/build/services/previews/local-previews.service.d.ts.map +1 -0
  72. package/build/services/previews/local-previews.service.js +50 -0
  73. package/build/services/previews/local-previews.service.js.map +1 -0
  74. package/build/services/previews/reload.service.d.ts +6 -0
  75. package/build/services/previews/reload.service.d.ts.map +1 -0
  76. package/build/services/previews/reload.service.js +13 -0
  77. package/build/services/previews/reload.service.js.map +1 -0
  78. package/build/services/previews/remote.service.d.ts +11 -0
  79. package/build/services/previews/remote.service.d.ts.map +1 -0
  80. package/build/services/previews/remote.service.js +34 -0
  81. package/build/services/previews/remote.service.js.map +1 -0
  82. package/build/services/previews/select.service.d.ts +11 -0
  83. package/build/services/previews/select.service.d.ts.map +1 -0
  84. package/build/services/previews/select.service.js +25 -0
  85. package/build/services/previews/select.service.js.map +1 -0
  86. package/build/services/previews/use-preview.service.d.ts +21 -0
  87. package/build/services/previews/use-preview.service.d.ts.map +1 -0
  88. package/build/services/previews/use-preview.service.js +24 -0
  89. package/build/services/previews/use-preview.service.js.map +1 -0
  90. package/build/services/previews/use-running.service.d.ts +4 -0
  91. package/build/services/previews/use-running.service.d.ts.map +1 -0
  92. package/build/services/previews/use-running.service.js +21 -0
  93. package/build/services/previews/use-running.service.js.map +1 -0
  94. package/build/services/publish/bundle.service.d.ts +11 -0
  95. package/build/services/publish/bundle.service.d.ts.map +1 -0
  96. package/build/services/publish/bundle.service.js +46 -0
  97. package/build/services/publish/bundle.service.js.map +1 -0
  98. package/build/services/publish/commands.service.d.ts +23 -0
  99. package/build/services/publish/commands.service.d.ts.map +1 -0
  100. package/build/services/publish/commands.service.js +130 -0
  101. package/build/services/publish/commands.service.js.map +1 -0
  102. package/build/services/publish/eas-env.service.d.ts +9 -0
  103. package/build/services/publish/eas-env.service.d.ts.map +1 -0
  104. package/build/services/publish/eas-env.service.js +49 -0
  105. package/build/services/publish/eas-env.service.js.map +1 -0
  106. package/build/services/registry/registry.service.d.ts +27 -0
  107. package/build/services/registry/registry.service.d.ts.map +1 -0
  108. package/build/services/registry/registry.service.js +89 -0
  109. package/build/services/registry/registry.service.js.map +1 -0
  110. package/build/services/s3/s3.service.d.ts +59 -0
  111. package/build/services/s3/s3.service.d.ts.map +1 -0
  112. package/build/services/s3/s3.service.js +154 -0
  113. package/build/services/s3/s3.service.js.map +1 -0
  114. package/build/services/start/start.service.d.ts +48 -0
  115. package/build/services/start/start.service.d.ts.map +1 -0
  116. package/build/services/start/start.service.js +172 -0
  117. package/build/services/start/start.service.js.map +1 -0
  118. package/build/stores/dev-preview-servers/dev-preview-servers.store.d.ts +21 -0
  119. package/build/stores/dev-preview-servers/dev-preview-servers.store.d.ts.map +1 -0
  120. package/build/stores/dev-preview-servers/dev-preview-servers.store.js +91 -0
  121. package/build/stores/dev-preview-servers/dev-preview-servers.store.js.map +1 -0
  122. package/build/stores/previews/previews.store.d.ts +36 -0
  123. package/build/stores/previews/previews.store.d.ts.map +1 -0
  124. package/build/stores/previews/previews.store.js +134 -0
  125. package/build/stores/previews/previews.store.js.map +1 -0
  126. package/build/utils/config/config.util.d.ts +39 -0
  127. package/build/utils/config/config.util.d.ts.map +1 -0
  128. package/build/utils/config/config.util.js +24 -0
  129. package/build/utils/config/config.util.js.map +1 -0
  130. package/build/utils/config/expo-config.util.d.ts +30 -0
  131. package/build/utils/config/expo-config.util.d.ts.map +1 -0
  132. package/build/utils/config/expo-config.util.js +43 -0
  133. package/build/utils/config/expo-config.util.js.map +1 -0
  134. package/build/utils/dev-preview-servers/merge-servers.util.d.ts +47 -0
  135. package/build/utils/dev-preview-servers/merge-servers.util.d.ts.map +1 -0
  136. package/build/utils/dev-preview-servers/merge-servers.util.js +37 -0
  137. package/build/utils/dev-preview-servers/merge-servers.util.js.map +1 -0
  138. package/build/utils/preview-list/theme.util.d.ts +5 -0
  139. package/build/utils/preview-list/theme.util.d.ts.map +1 -0
  140. package/build/utils/preview-list/theme.util.js +12 -0
  141. package/build/utils/preview-list/theme.util.js.map +1 -0
  142. package/build/utils/previews/layout.util.d.ts +89 -0
  143. package/build/utils/previews/layout.util.d.ts.map +1 -0
  144. package/build/utils/previews/layout.util.js +30 -0
  145. package/build/utils/previews/layout.util.js.map +1 -0
  146. package/build/utils/previews/preview-items.util.d.ts +23 -0
  147. package/build/utils/previews/preview-items.util.d.ts.map +1 -0
  148. package/build/utils/previews/preview-items.util.js +39 -0
  149. package/build/utils/previews/preview-items.util.js.map +1 -0
  150. package/build/utils/previews/preview-title.util.d.ts +2 -0
  151. package/build/utils/previews/preview-title.util.d.ts.map +1 -0
  152. package/build/utils/previews/preview-title.util.js +6 -0
  153. package/build/utils/previews/preview-title.util.js.map +1 -0
  154. package/build/utils/previews/running.util.d.ts +23 -0
  155. package/build/utils/previews/running.util.d.ts.map +1 -0
  156. package/build/utils/previews/running.util.js +23 -0
  157. package/build/utils/previews/running.util.js.map +1 -0
  158. package/build/utils/publish/changelog.util.d.ts +5 -0
  159. package/build/utils/publish/changelog.util.d.ts.map +1 -0
  160. package/build/utils/publish/changelog.util.js +19 -0
  161. package/build/utils/publish/changelog.util.js.map +1 -0
  162. package/build/utils/publish/indexes.util.d.ts +12 -0
  163. package/build/utils/publish/indexes.util.d.ts.map +1 -0
  164. package/build/utils/publish/indexes.util.js +52 -0
  165. package/build/utils/publish/indexes.util.js.map +1 -0
  166. package/build/utils/s3/sigv4.util.d.ts +24 -0
  167. package/build/utils/s3/sigv4.util.d.ts.map +1 -0
  168. package/build/utils/s3/sigv4.util.js +67 -0
  169. package/build/utils/s3/sigv4.util.js.map +1 -0
  170. package/expo-module.config.json +10 -0
  171. package/ios/AxonpackPreview.podspec +30 -0
  172. package/ios/AxonpackPreviewModule.swift +55 -0
  173. package/ios/PreviewReactDelegateHandler.swift +147 -0
  174. package/ios/PreviewState.swift +236 -0
  175. package/notes/README.md +36 -0
  176. package/notes/bundles.md +35 -0
  177. package/notes/dev-preview-servers.md +67 -0
  178. package/notes/distribution.md +138 -0
  179. package/notes/native-loader.md +56 -0
  180. package/notes/storage.md +145 -0
  181. package/notes/testing.md +97 -0
  182. package/package.json +107 -4
@@ -0,0 +1,145 @@
1
+ # Storage
2
+
3
+ Where previews are kept: in the bucket they are published to, and on the device once downloaded.
4
+
5
+ - [ ] Reads previews from any S3-compatible bucket (S3, R2, MinIO and others), public or private (with a read-only key)
6
+ - [ ] Downloads a preview into the app's documents folder and checks every file
7
+ - [ ] Keeps a download until QA deletes it; nothing expires on a timer
8
+ - [ ] Shows downloads made for another native build apart, with one button to delete them all
9
+
10
+ A half-finished download is never offered, because it only becomes a preview once every file has
11
+ been checked.
12
+
13
+ ## Settings
14
+
15
+ Publishing reads its settings the way Expo reads the app's: from the environment, then the same
16
+ `.env*` files Expo loads for a release bundle. Only `EXPO_PUBLIC_*` values are built into the app,
17
+ so the write key, which has no such prefix, never ends up inside it.
18
+
19
+ | Variable | Read by | What it holds |
20
+ | -------------------------- | ----------------------------- | --------------------------------------------------------------------------------- |
21
+ | `PREVIEW_S3_*` | `preview publish` only | The bucket URL and the **write** key |
22
+ | `EXPO_PUBLIC_PREVIEW_S3_*` | Expo, when it bundles the app | The bucket URL and, for a private bucket, a **read-only** key. Built into the app |
23
+
24
+ The CLI never reads `EXPO_PUBLIC_*`. The example has `example/.env.example` (the app's settings)
25
+ and `example/.env.local.example` (the publish settings) with the local values.
26
+
27
+ ### Publish settings
28
+
29
+ CI has no settings file, so the environment comes first: the shell, or the CI job's secrets. For
30
+ publishing from your own machine they can go in an env file instead. Publish loads the files
31
+ `expo export:embed --dev false` loads (mode `production`), through the app's own `@expo/env`, so the
32
+ order and the `${VAR}` expansion are Expo's:
33
+
34
+ 1. `.env.production.local`
35
+ 2. `.env.local`
36
+ 3. `.env.production`
37
+ 4. `.env`
38
+
39
+ A variable set in the environment wins over every file, and the first file in the list wins over
40
+ the ones after it. `.env.development*` and other modes are not read. `EXPO_NO_DOTENV` turns the
41
+ files off here too.
42
+
43
+ Put the write key in `.env.local` or `.env.production.local`, which Expo's project template
44
+ gitignores (`.env*.local`), or in CI secrets. Never put it in a committed `.env`: anyone with the
45
+ repo could then write to the bucket.
46
+
47
+ | Variable | Needed | What it is |
48
+ | ------------------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
49
+ | `PREVIEW_S3_URL` | yes | `<endpoint>/<bucket>`, plus a folder inside the bucket if there are more segments: `http://localhost:9000/previews-public`, `https://<account>.r2.cloudflarestorage.com/previews/my-app` |
50
+ | `PREVIEW_S3_ACCESS_KEY_ID` | yes | Write key id. Never ship it in the app |
51
+ | `PREVIEW_S3_SECRET_ACCESS_KEY` | yes | Write key secret |
52
+ | `PREVIEW_S3_REGION` | no | Signing region. Default `us-east-1`, which MinIO and R2 accept |
53
+
54
+ The names are the package's own, not `AWS_*`, so they work the same for any S3-compatible host and
55
+ never pick up AWS keys already exported in a shell.
56
+
57
+ ## Set up local storage
58
+
59
+ For the whole run, from starting the server to switching previews in the app, see
60
+ [testing.md](./testing.md).
61
+
62
+ A local S3 server, so you can try both bucket modes without a cloud account. It is MinIO, with one
63
+ public-read bucket and one private bucket plus a read-only key. Every name, key and the port live in
64
+ `local-s3/local-s3.env`, and both setups below read that file. The keys are local test values only.
65
+
66
+ ### With Docker (main path)
67
+
68
+ Needs Docker: Docker Desktop or OrbStack on macOS, the Docker engine on Linux. Podman's Docker
69
+ socket works too. From `packages/@axonpack/preview`:
70
+
71
+ | Command | Does |
72
+ | ----------------------------- | ---------------------------------------------------------------------- |
73
+ | `bun run storage:local` | Starts MinIO, then creates the buckets and the read key. Safe to rerun |
74
+ | `bun run storage:local:stop` | Stops it. Uploaded files stay in `local-s3/data/` (gitignored) |
75
+ | `bun run storage:local:reset` | Stops it and deletes `local-s3/data/`, so the next start is empty |
76
+
77
+ MinIO stopped publishing its own images in 2025, so `local-s3/compose.yaml` uses Bitnami's frozen
78
+ copies, pinned by digest.
79
+
80
+ ### Without Docker
81
+
82
+ 1. `brew install minio/stable/minio minio/stable/mc` (not tried here: MinIO's own downloads changed
83
+ in 2025, so this tap may be gone).
84
+ 2. In one terminal, from `packages/@axonpack/preview/local-s3`:
85
+ `set -a; . ./local-s3.env; set +a; minio server ./data --address ":$LOCAL_S3_PORT"`
86
+ 3. In another, from the same folder:
87
+ `set -a; . ./local-s3.env; set +a; LOCAL_S3_URL="http://localhost:$LOCAL_S3_PORT" sh ./init.sh`
88
+
89
+ `init.sh` is the same script the Docker setup runs, so the buckets, policy and key come out the same.
90
+
91
+ ### What you get
92
+
93
+ | Value | Local test value |
94
+ | -------------- | ------------------------------------------------------------------------- |
95
+ | Endpoint | `http://localhost:9000`, region `us-east-1`, path-style URLs |
96
+ | Public bucket | `previews-public`: anyone can read, only the write key can write |
97
+ | Private bucket | `previews-private`: reads need the read key, signed with SigV4 |
98
+ | Write key | `preview-admin` / `preview-admin-secret` (MinIO's root user) |
99
+ | Read key | `preview-reader` / `preview-reader-secret` (read `previews-private` only) |
100
+
101
+ A file is at `<endpoint>/<bucket>/<path>`.
102
+
103
+ ### The example app
104
+
105
+ The example reads its bucket from `example/.env` (copy `example/.env.example`):
106
+
107
+ | Variable | Needed | What it is |
108
+ | ----------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
109
+ | `EXPO_PUBLIC_PREVIEW_S3_URL` | yes | With a read key, the same `<endpoint>/<bucket>` the previews are published to. Without one, any address they are public under: that URL, R2's `https://pub-<id>.r2.dev` or a CDN |
110
+ | `EXPO_PUBLIC_PREVIEW_S3_READ_ACCESS_KEY_ID` | no | Only for a private bucket: the read-only key (`preview-reader` locally) |
111
+ | `EXPO_PUBLIC_PREVIEW_S3_READ_SECRET_ACCESS_KEY` | no | Its secret (`preview-reader-secret` locally) |
112
+ | `EXPO_PUBLIC_PREVIEW_S3_REGION` | no | Signing region for a private bucket. Default `us-east-1`; `auto` on R2 |
113
+
114
+ With a read key the app splits the URL into endpoint, bucket and folder and signs its reads. Without
115
+ one it reads `<url>/<key>` unsigned, so the URL needs no bucket in it.
116
+
117
+ Headers for a tunnel or proxy are not env values: pass `headers` in the app's config.
118
+
119
+ Expo builds `EXPO_PUBLIC_*` values into the app, so only a read-only key may go there, never the
120
+ write key. They are read when the app is bundled, so rebuild after changing them.
121
+
122
+ The address `localhost:9000` works as it is on the iOS simulator. On the Android emulator, run
123
+ `adb reverse tcp:9000 tcp:9000` once per emulator start, so the emulator's `localhost:9000` reaches
124
+ this computer. On a phone, use the computer's LAN address instead (`http://<LAN IP>:9000/...`), in
125
+ both the publish URL and the app's URL.
126
+
127
+ A tunnel works too, for a phone on another network: forward port 9000 (a VS Code dev tunnel, for
128
+ example) and put its HTTPS address in the app's URL, while publishing stays on `localhost:9000`. The
129
+ tunnel must be public, or it answers every request with a redirect to a login page. Dev tunnels may
130
+ also put a warning page in front of the first request; pass
131
+ `headers: { "X-Tunnel-Skip-AntiPhishing-Page": "True" }` in the app's config to skip it.
132
+
133
+ ### Plain HTTP on a device
134
+
135
+ The local server has no TLS. A release build on Android refuses plain HTTP to any host unless the
136
+ app allows cleartext traffic, so downloads fail with a cleartext error, while a debug build works.
137
+ The example app turns cleartext on in its own config (`expo-build-properties`,
138
+ `android.usesCleartextTraffic`), never in the package's defaults. A real app should use HTTPS. iOS does not apply App Transport Security to IP
139
+ addresses or `localhost`, so the simulator and a phone using the LAN IP should work as they are
140
+ (to be checked on a device in the download phase).
141
+
142
+ Android 17 also asks the user before an app may reach the local network, which includes the
143
+ emulator's `10.0.2.2` and a LAN IP (the `ACCESS_LOCAL_NETWORK` permission). If it is denied, both
144
+ downloads from the local server and a debug build's connection to Metro fail. On the emulator,
145
+ `adb shell pm grant <package> android.permission.ACCESS_LOCAL_NETWORK` grants it.
@@ -0,0 +1,97 @@
1
+ # Testing
2
+
3
+ Running the example end to end on your own machine, with no cloud account.
4
+
5
+ - [x] A local S3 server (MinIO) with a public and a private bucket, started with one command
6
+ - [x] An example app (the default `create-expo-app` template, tabs) with the list on a Previews tab
7
+ - [x] A banner on every tab that says what runs: a dev preview server, a preview, or the base bundle
8
+ - [x] Links that do what the list's buttons do, so a run can be scripted from a terminal
9
+
10
+ ## Run the example end to end
11
+
12
+ From `packages/@axonpack/preview`, after `bun install` at the repo root.
13
+
14
+ 1. Start Docker, or Podman with `podman machine start`.
15
+ 2. Start the local S3 server:
16
+ ```sh
17
+ bun run storage:local
18
+ ```
19
+ 3. Copy the two settings files. `.env` holds the app's settings. `.env.local` holds the publish
20
+ settings with the write key; uncomment its lines after copying. Both are gitignored.
21
+ ```sh
22
+ cp example/.env.example example/.env
23
+ cp example/.env.local.example example/.env.local
24
+ ```
25
+ 4. Build and run the example, in a debug or a release build:
26
+ ```sh
27
+ cd example
28
+ npx expo run:ios # or: npx expo run:ios --configuration Release
29
+ npx expo run:android # or: npx expo run:android --variant release
30
+ ```
31
+ 5. Make sure the device reaches the server:
32
+ - iOS simulator: `localhost` works as it is.
33
+ - Android emulator, or a phone on USB: `adb reverse tcp:9000 tcp:9000`, once each time the device
34
+ starts.
35
+ - Phone on the same Wi-Fi: put the computer's LAN IP in `EXPO_PUBLIC_PREVIEW_S3_URL`.
36
+ - Phone on another network: a public tunnel to port 9000 (see [storage.md](./storage.md#the-example-app)).
37
+
38
+ `EXPO_PUBLIC_*` values are built into the bundle, so after changing one run
39
+ `npx expo start --clear`, or rebuild for a release build.
40
+
41
+ 6. Publish a preview from `example/`:
42
+ ```sh
43
+ bun run publish:preview --id task-1-login-fix --changelog="- Fixes the login"
44
+ ```
45
+ That publishes for Android and iOS. In a terminal it asks for the title, prefilled from the id;
46
+ Enter keeps it.
47
+ `bunx preview publish …` works too. Use `bunx` in this repo, not `npx`: `npx` can't read
48
+ bun's install, so it looks for a `preview` package on npm and fails with a 404. An app
49
+ installed with npm uses `npx`.
50
+ 7. In the app's Previews tab: Refresh, Download, Switch, then Back to base. The banner at the top
51
+ names what runs. Publish the same id again with other
52
+ changes to see "Update available", or `bunx preview unpublish <id>` to see "Unpublished".
53
+ 8. Stop everything:
54
+ ```sh
55
+ cd .. && bun run storage:local:stop
56
+ podman machine stop # if you use Podman
57
+ ```
58
+
59
+ The example also takes links, which run the same code as its buttons:
60
+ `previewexample://download/<id>`, `switch/<id>`, `switch/embedded`, `refresh`, `delete/<id>`,
61
+ `deleteincompatible`, `local/<port>` and `localstop`. Each one lands on the Previews tab
62
+ (`src/app/+native-intent.tsx`). Open them with `xcrun simctl openurl booted <link>` or
63
+ `adb shell am start -d <link>`.
64
+
65
+ ## Several tasks at once (people and AI agents)
66
+
67
+ One debug build of the example can run any of several Metro servers, one per task or worktree. The
68
+ app needs `devPreviewServers: true` (the example has it).
69
+
70
+ 1. In each worktree, start Metro with:
71
+ ```sh
72
+ bun run start:preview # picks a free port in 8081-8099 and announces it
73
+ bun run start:preview -- -- --clear # after the second --, args go to expo start (bun eats the first)
74
+ ```
75
+ In a terminal it asks for the name the app shows, prefilled from the branch; Enter keeps it.
76
+ `--title <name>` skips the question, and so does a run with no terminal.
77
+ A plain `npx expo start --port 8085` is found as well, with less detail (no branch).
78
+ 2. Open the Previews tab in the app. "Dev preview servers" shows each server for this app within about two
79
+ seconds, with its branch, port and version. Switch runs that server; "Stop using dev preview server"
80
+ goes back.
81
+ 3. Stop a server with Ctrl+C; it leaves the list on its own.
82
+
83
+ On the Android emulator nothing else is needed. A phone on USB needs `adb reverse` for each port;
84
+ `preview start` does it when `adb` is on the PATH. See [dev-preview-servers.md](./dev-preview-servers.md).
85
+
86
+ ## Troubleshooting
87
+
88
+ - **"Expected JSON from … but got text/html"**: something other than the bucket answered. The URL is
89
+ not public, or a tunnel is showing its login page. Make the tunnel public, or use `localhost` with
90
+ `adb reverse`.
91
+ - **The list is empty**: nothing is published for this build's key. With the default
92
+ `compatibility: "appVersion"` the key is the app version, so publish again after a version bump.
93
+ With `"fingerprint"`, a prebuild or any native or app config change gives a new key, so publish
94
+ again after the build you are running.
95
+ - **Android cannot connect**: the `adb reverse` was lost when the emulator or phone restarted, or the
96
+ app was refused local network access (Android 17 asks). Run `adb reverse` again, or allow the
97
+ permission in the app's settings.
package/package.json CHANGED
@@ -1,6 +1,109 @@
1
1
  {
2
2
  "name": "@axonpack/preview",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Download and switch between preview JS bundles of an Expo app without a native rebuild",
5
+ "author": "Md Asadujjaman <abappi2019@gmail.com> (https://github.com/abappi19)",
6
+ "keywords": [
7
+ "preview",
8
+ "ota",
9
+ "bundle",
10
+ "qa",
11
+ "expo",
12
+ "react-native"
13
+ ],
14
+ "bugs": {
15
+ "url": "https://github.com/axonpack/axonpack/issues"
16
+ },
17
+ "license": "MIT",
18
+ "homepage": "https://axonpack.dev/docs/preview/",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/axonpack/axonpack.git",
22
+ "directory": "packages/@axonpack/preview"
23
+ },
24
+ "publishConfig": {
25
+ "registry": "https://registry.npmjs.org/"
26
+ },
27
+ "files": [
28
+ "android",
29
+ "ios",
30
+ "bin",
31
+ "build",
32
+ "app.plugin.js",
33
+ "expo-module.config.json",
34
+ "CHANGELOG.md",
35
+ "notes"
36
+ ],
37
+ "main": "build/index.js",
38
+ "types": "build/index.d.ts",
39
+ "bin": {
40
+ "preview": "bin/preview.js"
41
+ },
42
+ "sideEffects": false,
43
+ "exports": {
44
+ ".": {
45
+ "types": {
46
+ "expo-source": "./src/index.ts",
47
+ "default": "./build/index.d.ts"
48
+ },
49
+ "expo-source": "./src/index.ts",
50
+ "default": "./build/index.js"
51
+ },
52
+ "./app.plugin.js": "./app.plugin.js",
53
+ "./package.json": "./package.json"
54
+ },
55
+ "scripts": {
56
+ "build": "rm -rf build && tsc && bun build src/cli.ts --target=node --format=cjs --outfile=build/cli.cjs",
57
+ "prepare": "bun run build",
58
+ "clean": "rm -rf build",
59
+ "lint": "oxlint src",
60
+ "format": "oxlint src --fix",
61
+ "test": "jest",
62
+ "check-types": "tsc --noEmit -p tsconfig.check.json",
63
+ "storage:local": "./local-s3/run.sh start",
64
+ "storage:local:stop": "./local-s3/run.sh stop",
65
+ "storage:local:reset": "./local-s3/run.sh reset"
66
+ },
67
+ "devDependencies": {
68
+ "@babel/runtime": "^7.28.4",
69
+ "@types/jest": "^29.2.1",
70
+ "@types/node": "^24.0.0",
71
+ "@types/react": "~19.3.0",
72
+ "@types/react-test-renderer": "^19.1.0",
73
+ "expo": "^57.0.7",
74
+ "expo-file-system": "~58.0.11",
75
+ "jest": "^29.7.0",
76
+ "jest-expo": "~57.0.2",
77
+ "linter": "*",
78
+ "oxlint": "^1.80.0",
79
+ "react": "19.3.0",
80
+ "react-native": "0.86.0",
81
+ "react-test-renderer": "19.3.0",
82
+ "typescript": "^5.9.2"
83
+ },
84
+ "peerDependencies": {
85
+ "expo": ">=53",
86
+ "react": ">=18",
87
+ "react-native": ">=0.79",
88
+ "expo-file-system": "*"
89
+ },
90
+ "jest": {
91
+ "preset": "jest-expo",
92
+ "roots": [
93
+ "<rootDir>/src"
94
+ ],
95
+ "testMatch": [
96
+ "**/*.test.ts",
97
+ "**/*.test.tsx"
98
+ ],
99
+ "transformIgnorePatterns": [
100
+ "node_modules/(?!.*(react-native|expo|@noble))"
101
+ ],
102
+ "moduleNameMapper": {
103
+ "^@babel/runtime/(.*)$": "<rootDir>/node_modules/@babel/runtime/$1"
104
+ }
105
+ },
106
+ "dependencies": {
107
+ "@noble/hashes": "^2.4.0"
108
+ }
109
+ }