@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
package/build/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/build/cli.js ADDED
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ import { PLATFORMS } from "./utils/previews/layout.util";
6
+ import { prune, publish, unpublish } from "./services/publish/commands.service";
7
+ import { applyEasEnv } from "./services/publish/eas-env.service";
8
+ import { DEFAULT_PORT_RANGE, DEFAULT_REGISTRY_PORT, } from "./constants/dev-preview-servers/dev-preview-servers.const";
9
+ import { readConfig } from "./services/cli/config.service";
10
+ import { createRegistry } from "./services/registry/registry.service";
11
+ import { start } from "./services/start/start.service";
12
+ import { askTitle } from "./services/cli/title.service";
13
+ import { previewTitle } from "./utils/previews/preview-title.util";
14
+ import { compatibilityOf, resolveCompatibility, } from "./utils/config/expo-config.util";
15
+ import { appConfig, changelogSince, defaultBase, gitInfo, gitTopLevel, } from "./services/cli/project.service";
16
+ const HELP = `preview <command> [options]
17
+
18
+ publish build this app's JS bundle and upload it as a preview
19
+ --id <id> preview id (default: the git branch)
20
+ --title <title> name QA sees; without it a terminal asks, prefilled with a readable
21
+ form of the id (Enter keeps it). No prompt without a terminal (CI)
22
+ --platform <p> android, ios or all (default: all)
23
+ --base <branch> branch the changelog counts from (default: the repo's default branch)
24
+ --changelog=<text> changelog text instead of the commit subjects (use = when it starts
25
+ with a dash, as a "- item" list does)
26
+ --changelog-file <path>
27
+ --entry-file <path>
28
+ --compatibility <c> appVersion or fingerprint; overrides the app config's plugin option
29
+ --environment <name> build with this EAS environment's variables, like eas update
30
+ (needs eas-cli and a project linked to EAS; shell variables win)
31
+ unpublish <id> remove a preview from every build's list
32
+ prune delete files no preview uses any more
33
+ start [-- <expo start args>]
34
+ run Metro on a free port and announce it to the app's Dev preview servers
35
+ --title <title> name the app's list shows; asked like publish, prefilled with a
36
+ readable form of the branch
37
+ --ports <from>-<to> ports to pick from (default 8081-8099)
38
+
39
+ --project <dir> the app's root (default: the current folder)
40
+
41
+ Where to publish comes from the environment (the shell, or CI secrets). For local use they can
42
+ also go in the app's .env.local, or any env file Expo loads for a release build; the environment
43
+ wins over them. Keep the write key out of a committed .env:
44
+ PREVIEW_S3_URL <endpoint>/<bucket>[/<folder>], e.g. http://localhost:9000/previews-public
45
+ PREVIEW_S3_ACCESS_KEY_ID the write key
46
+ PREVIEW_S3_SECRET_ACCESS_KEY
47
+ PREVIEW_S3_REGION optional, default us-east-1`;
48
+ async function main() {
49
+ // Everything after `--` goes to `expo start` untouched.
50
+ const argv = process.argv.slice(2);
51
+ const dash = argv.indexOf("--");
52
+ const passThrough = dash >= 0 ? argv.slice(dash + 1) : [];
53
+ const { values, positionals } = parseArgs({
54
+ args: dash >= 0 ? argv.slice(0, dash) : argv,
55
+ allowPositionals: true,
56
+ options: {
57
+ id: { type: "string" },
58
+ title: { type: "string" },
59
+ platform: { type: "string", default: "all" },
60
+ base: { type: "string" },
61
+ changelog: { type: "string" },
62
+ "changelog-file": { type: "string" },
63
+ "entry-file": { type: "string" },
64
+ compatibility: { type: "string" },
65
+ environment: { type: "string" },
66
+ project: { type: "string" },
67
+ port: { type: "string" },
68
+ ports: { type: "string" },
69
+ help: { type: "boolean", short: "h" },
70
+ },
71
+ });
72
+ const [command, arg] = positionals;
73
+ if (values.help || !command) {
74
+ process.stdout.write(`${HELP}\n`);
75
+ return;
76
+ }
77
+ const projectRoot = resolve(values.project ?? process.cwd());
78
+ // Only the bucket commands need the publish settings.
79
+ const s3 = () => readConfig(projectRoot);
80
+ if (command === "publish") {
81
+ // Before anything reads the app config: the config, fingerprint and export must all see the
82
+ // same variables a build in that environment saw, or the key would not match.
83
+ if (values.environment)
84
+ applyEasEnv(projectRoot, values.environment);
85
+ const git = gitInfo(projectRoot, { id: values.id });
86
+ const id = values.id ?? git.branch;
87
+ if (!id)
88
+ throw new Error("No git branch to name the preview after; pass --id.");
89
+ const platforms = values.platform === "all" ? PLATFORMS : [values.platform];
90
+ if (!platforms.every((p) => PLATFORMS.includes(p))) {
91
+ throw new Error(`--platform must be android, ios or all`);
92
+ }
93
+ const changelog = values.changelog ??
94
+ (values["changelog-file"]
95
+ ? readFileSync(resolve(values["changelog-file"]), "utf8").trim()
96
+ : changelogSince(projectRoot, values.base ?? defaultBase(projectRoot)));
97
+ const config = appConfig(projectRoot);
98
+ const { compatibility, warnings } = resolveCompatibility(compatibilityOf(config), values.compatibility);
99
+ for (const warning of warnings)
100
+ process.stderr.write(`warning: ${warning}\n`);
101
+ await publish({
102
+ projectRoot,
103
+ config,
104
+ compatibility,
105
+ s3: s3(),
106
+ platforms,
107
+ id,
108
+ title: await askTitle({
109
+ given: values.title,
110
+ fallback: previewTitle(id),
111
+ }),
112
+ ...git,
113
+ changelog,
114
+ entryFile: values["entry-file"],
115
+ });
116
+ }
117
+ else if (command === "unpublish") {
118
+ if (!arg)
119
+ throw new Error("Which preview? preview unpublish <id>");
120
+ await unpublish(s3(), arg);
121
+ }
122
+ else if (command === "prune") {
123
+ await prune(s3());
124
+ }
125
+ else if (command === "start") {
126
+ const [from, to] = (values.ports ?? `${DEFAULT_PORT_RANGE[0]}-${DEFAULT_PORT_RANGE[1]}`)
127
+ .split("-")
128
+ .map(Number);
129
+ if (!from || !to || from > to)
130
+ throw new Error("--ports must look like 8081-8099");
131
+ const config = appConfig(projectRoot);
132
+ const branch = gitInfo(projectRoot).branch;
133
+ const title = await askTitle({
134
+ given: values.title,
135
+ // Empty lets the announcement fall back to the app's name.
136
+ fallback: branch ? previewTitle(branch) : "",
137
+ });
138
+ await start({
139
+ projectRoot,
140
+ config,
141
+ branch,
142
+ title,
143
+ worktree: gitTopLevel(projectRoot) ?? projectRoot,
144
+ ports: [from, to],
145
+ registryPort: DEFAULT_REGISTRY_PORT,
146
+ expoArgs: passThrough,
147
+ bin: process.argv[1],
148
+ });
149
+ }
150
+ else if (command === "registry") {
151
+ // Started by `preview start` when none is running; exits once no server is left.
152
+ const port = Number(values.port ?? DEFAULT_REGISTRY_PORT);
153
+ const { server } = createRegistry({ onIdle: () => process.exit(0) });
154
+ server.listen(port);
155
+ }
156
+ else {
157
+ throw new Error(`Unknown command ${command}.\n\n${HELP}`);
158
+ }
159
+ }
160
+ main().catch((error) => {
161
+ process.stderr.write(`preview: ${error instanceof Error ? error.message : String(error)}\n`);
162
+ process.exit(1);
163
+ });
164
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\n\nimport { PLATFORMS, Platform } from \"./utils/previews/layout.util\";\nimport { prune, publish, unpublish } from \"./services/publish/commands.service\";\nimport { applyEasEnv } from \"./services/publish/eas-env.service\";\nimport {\n DEFAULT_PORT_RANGE,\n DEFAULT_REGISTRY_PORT,\n} from \"./constants/dev-preview-servers/dev-preview-servers.const\";\nimport { readConfig } from \"./services/cli/config.service\";\nimport { createRegistry } from \"./services/registry/registry.service\";\nimport { start } from \"./services/start/start.service\";\nimport { askTitle } from \"./services/cli/title.service\";\nimport { previewTitle } from \"./utils/previews/preview-title.util\";\nimport {\n compatibilityOf,\n resolveCompatibility,\n} from \"./utils/config/expo-config.util\";\nimport {\n appConfig,\n changelogSince,\n defaultBase,\n gitInfo,\n gitTopLevel,\n} from \"./services/cli/project.service\";\n\nconst HELP = `preview <command> [options]\n\n publish build this app's JS bundle and upload it as a preview\n --id <id> preview id (default: the git branch)\n --title <title> name QA sees; without it a terminal asks, prefilled with a readable\n form of the id (Enter keeps it). No prompt without a terminal (CI)\n --platform <p> android, ios or all (default: all)\n --base <branch> branch the changelog counts from (default: the repo's default branch)\n --changelog=<text> changelog text instead of the commit subjects (use = when it starts\n with a dash, as a \"- item\" list does)\n --changelog-file <path>\n --entry-file <path>\n --compatibility <c> appVersion or fingerprint; overrides the app config's plugin option\n --environment <name> build with this EAS environment's variables, like eas update\n (needs eas-cli and a project linked to EAS; shell variables win)\n unpublish <id> remove a preview from every build's list\n prune delete files no preview uses any more\n start [-- <expo start args>]\n run Metro on a free port and announce it to the app's Dev preview servers\n --title <title> name the app's list shows; asked like publish, prefilled with a\n readable form of the branch\n --ports <from>-<to> ports to pick from (default 8081-8099)\n\n --project <dir> the app's root (default: the current folder)\n\nWhere to publish comes from the environment (the shell, or CI secrets). For local use they can\nalso go in the app's .env.local, or any env file Expo loads for a release build; the environment\nwins over them. Keep the write key out of a committed .env:\n PREVIEW_S3_URL <endpoint>/<bucket>[/<folder>], e.g. http://localhost:9000/previews-public\n PREVIEW_S3_ACCESS_KEY_ID the write key\n PREVIEW_S3_SECRET_ACCESS_KEY\n PREVIEW_S3_REGION optional, default us-east-1`;\n\nasync function main() {\n // Everything after `--` goes to `expo start` untouched.\n const argv = process.argv.slice(2);\n const dash = argv.indexOf(\"--\");\n const passThrough = dash >= 0 ? argv.slice(dash + 1) : [];\n const { values, positionals } = parseArgs({\n args: dash >= 0 ? argv.slice(0, dash) : argv,\n allowPositionals: true,\n options: {\n id: { type: \"string\" },\n title: { type: \"string\" },\n platform: { type: \"string\", default: \"all\" },\n base: { type: \"string\" },\n changelog: { type: \"string\" },\n \"changelog-file\": { type: \"string\" },\n \"entry-file\": { type: \"string\" },\n compatibility: { type: \"string\" },\n environment: { type: \"string\" },\n project: { type: \"string\" },\n port: { type: \"string\" },\n ports: { type: \"string\" },\n help: { type: \"boolean\", short: \"h\" },\n },\n });\n const [command, arg] = positionals;\n if (values.help || !command) {\n process.stdout.write(`${HELP}\\n`);\n return;\n }\n const projectRoot = resolve(values.project ?? process.cwd());\n // Only the bucket commands need the publish settings.\n const s3 = () => readConfig(projectRoot);\n\n if (command === \"publish\") {\n // Before anything reads the app config: the config, fingerprint and export must all see the\n // same variables a build in that environment saw, or the key would not match.\n if (values.environment) applyEasEnv(projectRoot, values.environment);\n const git = gitInfo(projectRoot, { id: values.id });\n const id = values.id ?? git.branch;\n if (!id)\n throw new Error(\"No git branch to name the preview after; pass --id.\");\n const platforms =\n values.platform === \"all\" ? PLATFORMS : [values.platform as Platform];\n if (!platforms.every((p) => PLATFORMS.includes(p))) {\n throw new Error(`--platform must be android, ios or all`);\n }\n const changelog =\n values.changelog ??\n (values[\"changelog-file\"]\n ? readFileSync(resolve(values[\"changelog-file\"]), \"utf8\").trim()\n : changelogSince(projectRoot, values.base ?? defaultBase(projectRoot)));\n const config = appConfig(projectRoot);\n const { compatibility, warnings } = resolveCompatibility(\n compatibilityOf(config),\n values.compatibility,\n );\n for (const warning of warnings)\n process.stderr.write(`warning: ${warning}\\n`);\n await publish({\n projectRoot,\n config,\n compatibility,\n s3: s3(),\n platforms,\n id,\n title: await askTitle({\n given: values.title,\n fallback: previewTitle(id),\n }),\n ...git,\n changelog,\n entryFile: values[\"entry-file\"],\n });\n } else if (command === \"unpublish\") {\n if (!arg) throw new Error(\"Which preview? preview unpublish <id>\");\n await unpublish(s3(), arg);\n } else if (command === \"prune\") {\n await prune(s3());\n } else if (command === \"start\") {\n const [from, to] = (\n values.ports ?? `${DEFAULT_PORT_RANGE[0]}-${DEFAULT_PORT_RANGE[1]}`\n )\n .split(\"-\")\n .map(Number);\n if (!from || !to || from > to)\n throw new Error(\"--ports must look like 8081-8099\");\n const config = appConfig(projectRoot);\n const branch = gitInfo(projectRoot).branch;\n const title = await askTitle({\n given: values.title,\n // Empty lets the announcement fall back to the app's name.\n fallback: branch ? previewTitle(branch) : \"\",\n });\n await start({\n projectRoot,\n config,\n branch,\n title,\n worktree: gitTopLevel(projectRoot) ?? projectRoot,\n ports: [from, to],\n registryPort: DEFAULT_REGISTRY_PORT,\n expoArgs: passThrough,\n bin: process.argv[1],\n });\n } else if (command === \"registry\") {\n // Started by `preview start` when none is running; exits once no server is left.\n const port = Number(values.port ?? DEFAULT_REGISTRY_PORT);\n const { server } = createRegistry({ onIdle: () => process.exit(0) });\n server.listen(port);\n } else {\n throw new Error(`Unknown command ${command}.\\n\\n${HELP}`);\n }\n}\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `preview: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exit(1);\n});\n"]}
@@ -0,0 +1,13 @@
1
+ import { ScrollView, type StyleProp, type ViewStyle } from "react-native";
2
+ import type { PreviewListLabels, PreviewListTheme } from "./preview-list.types";
3
+ export type PreviewListProps = {
4
+ theme?: Partial<PreviewListTheme>;
5
+ labels?: Partial<PreviewListLabels>;
6
+ style?: StyleProp<ViewStyle>;
7
+ };
8
+ /**
9
+ * The previews published for this build, with what is running now, and the downloads made for
10
+ * another build in a section of their own. Needs a `<PreviewProvider>` above it.
11
+ */
12
+ export declare function PreviewList(props: PreviewListProps): import("react").CElement<import("react-native").ScrollViewProps, ScrollView>;
13
+ //# sourceMappingURL=preview-list.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-list.component.d.ts","sourceRoot":"","sources":["../../../src/components/preview-list/preview-list.component.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,UAAU,EAIV,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAgBtB,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,gFA+elD"}
@@ -0,0 +1,316 @@
1
+ import { createElement as h, useEffect } from "react";
2
+ import { ActivityIndicator, Pressable, ScrollView, Text, View, useColorScheme, } from "react-native";
3
+ import { devPreviewServersStore, useDevPreviewServersState, } from "../../stores/dev-preview-servers/dev-preview-servers.store";
4
+ import { buildSlug } from "../../services/native/build-info.service";
5
+ import { usePreview } from "../../services/previews/use-preview.service";
6
+ import { useRunning } from "../../services/previews/use-running.service";
7
+ import { DEFAULT_LABELS } from "../../constants/preview-list/theme.const";
8
+ import { formatSize, resolveTheme } from "../../utils/preview-list/theme.util";
9
+ /**
10
+ * The previews published for this build, with what is running now, and the downloads made for
11
+ * another build in a section of their own. Needs a `<PreviewProvider>` above it.
12
+ */
13
+ export function PreviewList(props) {
14
+ const preview = usePreview();
15
+ const local = useDevPreviewServersState();
16
+ const now = useRunning();
17
+ const showLocal = __DEV__ && preview.devPreviewServers;
18
+ // Without the slug the plugin bakes in, other apps' servers can't be told apart, so none are listed.
19
+ const appSlug = buildSlug();
20
+ // Look for servers only while the list is on screen.
21
+ useEffect(() => (showLocal && appSlug ? devPreviewServersStore.watch() : undefined), [showLocal, appSlug]);
22
+ const theme = resolveTheme(props.theme, useColorScheme());
23
+ const labels = {
24
+ ...DEFAULT_LABELS,
25
+ ...props.labels,
26
+ status: { ...DEFAULT_LABELS.status, ...props.labels?.status },
27
+ };
28
+ const { radius, fonts } = theme;
29
+ // A custom font family replaces the weight, since most families ship one file per weight.
30
+ const font = (weight, size) => {
31
+ const family = fonts[weight];
32
+ return {
33
+ fontSize: size,
34
+ ...(family
35
+ ? { fontFamily: family }
36
+ : {
37
+ fontWeight: (weight === "bold"
38
+ ? "700"
39
+ : weight === "medium"
40
+ ? "600"
41
+ : "400"),
42
+ }),
43
+ };
44
+ };
45
+ const button = (title, onPress, kind = "primary") => h(Pressable, {
46
+ key: title,
47
+ onPress,
48
+ accessibilityRole: "button",
49
+ style: ({ pressed }) => ({
50
+ minHeight: 44,
51
+ paddingHorizontal: 16,
52
+ justifyContent: "center",
53
+ borderRadius: radius / 1.5,
54
+ opacity: pressed ? 0.7 : 1,
55
+ backgroundColor: kind === "primary" ? theme.primary : "transparent",
56
+ borderWidth: kind === "primary" ? 0 : 1,
57
+ borderColor: kind === "danger" ? theme.danger : theme.border,
58
+ }),
59
+ }, h(Text, {
60
+ style: {
61
+ ...font("medium", 15),
62
+ color: kind === "primary"
63
+ ? theme.primaryText
64
+ : kind === "danger"
65
+ ? theme.danger
66
+ : theme.text,
67
+ },
68
+ }, title));
69
+ const statusColor = (status) => status === "broken"
70
+ ? theme.danger
71
+ : status === "update-available" || status === "unpublished"
72
+ ? theme.warning
73
+ : status === "downloaded"
74
+ ? theme.success
75
+ : theme.muted;
76
+ const card = (key, children) => h(View, {
77
+ key,
78
+ style: {
79
+ backgroundColor: theme.card,
80
+ borderRadius: radius,
81
+ borderWidth: 1,
82
+ borderColor: theme.border,
83
+ padding: 16,
84
+ gap: 10,
85
+ },
86
+ }, ...children);
87
+ const row = (item) => {
88
+ const { entry } = item;
89
+ const date = entry.publishedAt
90
+ ? new Date(entry.publishedAt).toLocaleString()
91
+ : "";
92
+ const meta = [
93
+ entry.appVersion ? `v${entry.appVersion}` : "",
94
+ entry.branch,
95
+ entry.author,
96
+ date,
97
+ formatSize(entry.size),
98
+ ]
99
+ .filter(Boolean)
100
+ .join(" · ");
101
+ const actions = [];
102
+ if (item.status === "available")
103
+ actions.push(button(labels.download, () => preview.download(item.id), "plain"));
104
+ if (item.status === "update-available")
105
+ actions.push(button(labels.update, () => preview.download(item.id), "plain"));
106
+ if (!item.active && item.status !== "downloading") {
107
+ actions.push(button(labels.switchTo, () => preview.switchTo(item.id)));
108
+ }
109
+ if (item.local && item.status !== "downloading") {
110
+ actions.push(button(labels.delete, () => preview.remove(item.id), "danger"));
111
+ }
112
+ return card(item.id, [
113
+ h(View, {
114
+ key: "head",
115
+ style: {
116
+ flexDirection: "row",
117
+ justifyContent: "space-between",
118
+ gap: 8,
119
+ },
120
+ }, h(Text, {
121
+ style: { ...font("bold", 17), color: theme.title, flexShrink: 1 },
122
+ }, entry.title), h(Text, {
123
+ style: {
124
+ ...font("medium", 13),
125
+ color: item.active ? theme.success : statusColor(item.status),
126
+ },
127
+ }, item.active ? labels.running : labels.status[item.status])),
128
+ h(Text, {
129
+ key: "meta",
130
+ style: { ...font("regular", 13), color: theme.muted },
131
+ }, meta),
132
+ entry.changelog
133
+ ? h(Text, {
134
+ key: "changelog",
135
+ style: {
136
+ ...font("regular", 14),
137
+ color: theme.text,
138
+ backgroundColor: theme.surface,
139
+ borderRadius: radius / 2,
140
+ padding: 10,
141
+ },
142
+ }, entry.changelog)
143
+ : null,
144
+ item.progress !== null
145
+ ? h(View, {
146
+ key: "progress",
147
+ accessibilityRole: "progressbar",
148
+ accessibilityValue: {
149
+ min: 0,
150
+ max: 100,
151
+ now: Math.round(item.progress * 100),
152
+ },
153
+ style: {
154
+ height: 6,
155
+ borderRadius: 3,
156
+ backgroundColor: theme.surface,
157
+ overflow: "hidden",
158
+ },
159
+ }, h(View, {
160
+ style: {
161
+ width: `${Math.round(item.progress * 100)}%`,
162
+ height: 6,
163
+ backgroundColor: theme.primary,
164
+ },
165
+ }))
166
+ : null,
167
+ actions.length > 0
168
+ ? h(View, {
169
+ key: "actions",
170
+ style: { flexDirection: "row", flexWrap: "wrap", gap: 8 },
171
+ }, ...actions)
172
+ : null,
173
+ ].filter(Boolean));
174
+ };
175
+ const localRow = (server) => {
176
+ const running = server.url === local.activeUrl;
177
+ const meta = [
178
+ server.branch,
179
+ server.hostPort,
180
+ server.version ? `v${server.version}` : "",
181
+ ]
182
+ .filter(Boolean)
183
+ .join(" · ");
184
+ const badge = server.compatible === false
185
+ ? { text: labels.localIncompatible, color: theme.warning }
186
+ : server.compatible === null
187
+ ? { text: labels.localUnknownBuild, color: theme.muted }
188
+ : null;
189
+ return h(View, {
190
+ key: server.hostPort,
191
+ style: {
192
+ gap: 6,
193
+ paddingTop: 8,
194
+ borderTopWidth: 1,
195
+ borderColor: theme.border,
196
+ },
197
+ }, h(View, {
198
+ style: {
199
+ flexDirection: "row",
200
+ justifyContent: "space-between",
201
+ gap: 8,
202
+ },
203
+ }, h(Text, { style: { ...font("bold", 16), color: theme.title, flexShrink: 1 } }, server.title), running
204
+ ? h(Text, { style: { ...font("medium", 13), color: theme.success } }, labels.running)
205
+ : null), h(Text, { style: { ...font("regular", 13), color: theme.muted } }, meta), badge
206
+ ? h(Text, { style: { ...font("medium", 13), color: badge.color } }, badge.text)
207
+ : null, h(View, { style: { flexDirection: "row", flexWrap: "wrap", gap: 8 } }, running
208
+ ? button(labels.stopDevPreviewServer, () => devPreviewServersStore.switchTo(null), "plain")
209
+ : button(labels.switchTo, () => devPreviewServersStore.switchTo(server))));
210
+ };
211
+ const localSection = showLocal
212
+ ? card("local", [
213
+ h(Text, {
214
+ key: "title",
215
+ style: { ...font("bold", 17), color: theme.title },
216
+ }, labels.devPreviewServersTitle),
217
+ h(Text, {
218
+ key: "hint",
219
+ style: { ...font("regular", 13), color: theme.muted },
220
+ }, labels.devPreviewServersHint),
221
+ local.error
222
+ ? h(Text, {
223
+ key: "error",
224
+ style: { ...font("regular", 13), color: theme.danger },
225
+ }, local.error)
226
+ : null,
227
+ ...(!appSlug
228
+ ? [
229
+ h(Text, {
230
+ key: "noslug",
231
+ style: { ...font("regular", 15), color: theme.danger },
232
+ }, labels.noBuildSlug),
233
+ ]
234
+ : local.servers.length > 0
235
+ ? local.servers.map(localRow)
236
+ : [
237
+ h(Text, {
238
+ key: "none",
239
+ style: { ...font("regular", 15), color: theme.muted },
240
+ }, labels.noDevPreviewServers),
241
+ ]),
242
+ ].filter(Boolean))
243
+ : null;
244
+ const header = card("header", [
245
+ h(Text, { key: "title", style: { ...font("bold", 22), color: theme.title } }, labels.title),
246
+ h(Text, {
247
+ key: "running",
248
+ style: { ...font("regular", 15), color: theme.text },
249
+ }, `${labels.running}: ${now.kind === "local"
250
+ ? now.server
251
+ ? `${now.server.title} (${labels.localSuffix}, ${now.hostPort})`
252
+ : `${now.hostPort} (${labels.localSuffix})`
253
+ : now.kind === "preview"
254
+ ? now.title
255
+ : labels.base}`),
256
+ // A dev preview server wins over a picked preview, so Metro is in use and the note would be wrong.
257
+ __DEV__ && now.kind === "preview"
258
+ ? h(Text, {
259
+ key: "metro",
260
+ style: { ...font("medium", 13), color: theme.warning },
261
+ }, labels.metroBypassed)
262
+ : null,
263
+ preview.error
264
+ ? h(Text, {
265
+ key: "error",
266
+ style: { ...font("regular", 13), color: theme.danger },
267
+ }, preview.error)
268
+ : null,
269
+ h(View, {
270
+ key: "actions",
271
+ style: {
272
+ flexDirection: "row",
273
+ flexWrap: "wrap",
274
+ gap: 8,
275
+ alignItems: "center",
276
+ },
277
+ }, preview.activeId || (showLocal && local.activeUrl)
278
+ ? button(labels.backToBase, () => preview.switchTo(null))
279
+ : null, button(labels.refresh, () => preview.refresh(), "plain"), preview.loading
280
+ ? h(ActivityIndicator, { key: "spinner", color: theme.primary })
281
+ : null),
282
+ ].filter(Boolean));
283
+ const empty = !preview.loading && preview.items.length === 0
284
+ ? h(Text, {
285
+ key: "empty",
286
+ style: {
287
+ ...font("regular", 15),
288
+ color: theme.muted,
289
+ textAlign: "center",
290
+ padding: 16,
291
+ },
292
+ }, preview.buildKey ? labels.empty : labels.noBuildKey)
293
+ : null;
294
+ const incompatible = preview.incompatible.length > 0
295
+ ? card("incompatible", [
296
+ h(Text, {
297
+ key: "title",
298
+ style: { ...font("bold", 17), color: theme.title },
299
+ }, labels.incompatibleTitle),
300
+ h(Text, {
301
+ key: "hint",
302
+ style: { ...font("regular", 13), color: theme.muted },
303
+ }, labels.incompatibleHint),
304
+ ...preview.incompatible.map((p) => h(Text, {
305
+ key: p.id,
306
+ style: { ...font("regular", 15), color: theme.text },
307
+ }, `${p.entry.title} · ${formatSize(p.entry.size)}`)),
308
+ h(View, { key: "actions", style: { flexDirection: "row" } }, button(labels.deleteAll, () => preview.removeIncompatible(), "danger")),
309
+ ])
310
+ : null;
311
+ return h(ScrollView, {
312
+ style: [{ backgroundColor: theme.background }, props.style],
313
+ contentContainerStyle: { padding: 16, gap: 12 },
314
+ }, header, localSection, ...preview.items.map(row), empty, incompatible);
315
+ }
316
+ //# sourceMappingURL=preview-list.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-list.component.js","sourceRoot":"","sources":["../../../src/components/preview-list/preview-list.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { createElement as h, type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n ScrollView,\n Text,\n View,\n useColorScheme,\n type StyleProp,\n type ViewStyle,\n} from \"react-native\";\n\nimport type { DevPreviewServer } from \"../../utils/dev-preview-servers/merge-servers.util\";\nimport {\n devPreviewServersStore,\n useDevPreviewServersState,\n} from \"../../stores/dev-preview-servers/dev-preview-servers.store\";\nimport type {\n PreviewItem,\n PreviewStatus,\n} from \"../../utils/previews/preview-items.util\";\nimport { buildSlug } from \"../../services/native/build-info.service\";\nimport { usePreview } from \"../../services/previews/use-preview.service\";\nimport { useRunning } from \"../../services/previews/use-running.service\";\nimport { DEFAULT_LABELS } from \"../../constants/preview-list/theme.const\";\nimport { formatSize, resolveTheme } from \"../../utils/preview-list/theme.util\";\nimport type { PreviewListLabels, PreviewListTheme } from \"./preview-list.types\";\n\nexport type PreviewListProps = {\n theme?: Partial<PreviewListTheme>;\n labels?: Partial<PreviewListLabels>;\n style?: StyleProp<ViewStyle>;\n};\n\n/**\n * The previews published for this build, with what is running now, and the downloads made for\n * another build in a section of their own. Needs a `<PreviewProvider>` above it.\n */\nexport function PreviewList(props: PreviewListProps) {\n const preview = usePreview();\n const local = useDevPreviewServersState();\n const now = useRunning();\n const showLocal = __DEV__ && preview.devPreviewServers;\n // Without the slug the plugin bakes in, other apps' servers can't be told apart, so none are listed.\n const appSlug = buildSlug();\n // Look for servers only while the list is on screen.\n useEffect(\n () => (showLocal && appSlug ? devPreviewServersStore.watch() : undefined),\n [showLocal, appSlug],\n );\n const theme = resolveTheme(props.theme, useColorScheme());\n const labels = {\n ...DEFAULT_LABELS,\n ...props.labels,\n status: { ...DEFAULT_LABELS.status, ...props.labels?.status },\n };\n const { radius, fonts } = theme;\n\n // A custom font family replaces the weight, since most families ship one file per weight.\n const font = (weight: \"regular\" | \"medium\" | \"bold\", size: number) => {\n const family = fonts[weight];\n return {\n fontSize: size,\n ...(family\n ? { fontFamily: family }\n : {\n fontWeight: (weight === \"bold\"\n ? \"700\"\n : weight === \"medium\"\n ? \"600\"\n : \"400\") as \"700\" | \"600\" | \"400\",\n }),\n };\n };\n\n const button = (\n title: string,\n onPress: () => void,\n kind: \"primary\" | \"plain\" | \"danger\" = \"primary\",\n ): ReactNode =>\n h(\n Pressable,\n {\n key: title,\n onPress,\n accessibilityRole: \"button\",\n style: ({ pressed }: { pressed: boolean }): ViewStyle => ({\n minHeight: 44,\n paddingHorizontal: 16,\n justifyContent: \"center\",\n borderRadius: radius / 1.5,\n opacity: pressed ? 0.7 : 1,\n backgroundColor: kind === \"primary\" ? theme.primary : \"transparent\",\n borderWidth: kind === \"primary\" ? 0 : 1,\n borderColor: kind === \"danger\" ? theme.danger : theme.border,\n }),\n },\n h(\n Text,\n {\n style: {\n ...font(\"medium\", 15),\n color:\n kind === \"primary\"\n ? theme.primaryText\n : kind === \"danger\"\n ? theme.danger\n : theme.text,\n },\n },\n title,\n ),\n );\n\n const statusColor = (status: PreviewStatus) =>\n status === \"broken\"\n ? theme.danger\n : status === \"update-available\" || status === \"unpublished\"\n ? theme.warning\n : status === \"downloaded\"\n ? theme.success\n : theme.muted;\n\n const card = (key: string, children: ReactNode[]) =>\n h(\n View,\n {\n key,\n style: {\n backgroundColor: theme.card,\n borderRadius: radius,\n borderWidth: 1,\n borderColor: theme.border,\n padding: 16,\n gap: 10,\n },\n },\n ...children,\n );\n\n const row = (item: PreviewItem) => {\n const { entry } = item;\n const date = entry.publishedAt\n ? new Date(entry.publishedAt).toLocaleString()\n : \"\";\n const meta = [\n entry.appVersion ? `v${entry.appVersion}` : \"\",\n entry.branch,\n entry.author,\n date,\n formatSize(entry.size),\n ]\n .filter(Boolean)\n .join(\" · \");\n const actions: ReactNode[] = [];\n if (item.status === \"available\")\n actions.push(\n button(labels.download, () => preview.download(item.id), \"plain\"),\n );\n if (item.status === \"update-available\")\n actions.push(\n button(labels.update, () => preview.download(item.id), \"plain\"),\n );\n if (!item.active && item.status !== \"downloading\") {\n actions.push(button(labels.switchTo, () => preview.switchTo(item.id)));\n }\n if (item.local && item.status !== \"downloading\") {\n actions.push(\n button(labels.delete, () => preview.remove(item.id), \"danger\"),\n );\n }\n return card(\n item.id,\n [\n h(\n View,\n {\n key: \"head\",\n style: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n gap: 8,\n },\n },\n h(\n Text,\n {\n style: { ...font(\"bold\", 17), color: theme.title, flexShrink: 1 },\n },\n entry.title,\n ),\n h(\n Text,\n {\n style: {\n ...font(\"medium\", 13),\n color: item.active ? theme.success : statusColor(item.status),\n },\n },\n item.active ? labels.running : labels.status[item.status],\n ),\n ),\n h(\n Text,\n {\n key: \"meta\",\n style: { ...font(\"regular\", 13), color: theme.muted },\n },\n meta,\n ),\n entry.changelog\n ? h(\n Text,\n {\n key: \"changelog\",\n style: {\n ...font(\"regular\", 14),\n color: theme.text,\n backgroundColor: theme.surface,\n borderRadius: radius / 2,\n padding: 10,\n },\n },\n entry.changelog,\n )\n : null,\n item.progress !== null\n ? h(\n View,\n {\n key: \"progress\",\n accessibilityRole: \"progressbar\",\n accessibilityValue: {\n min: 0,\n max: 100,\n now: Math.round(item.progress * 100),\n },\n style: {\n height: 6,\n borderRadius: 3,\n backgroundColor: theme.surface,\n overflow: \"hidden\",\n },\n },\n h(View, {\n style: {\n width: `${Math.round(item.progress * 100)}%`,\n height: 6,\n backgroundColor: theme.primary,\n },\n }),\n )\n : null,\n actions.length > 0\n ? h(\n View,\n {\n key: \"actions\",\n style: { flexDirection: \"row\", flexWrap: \"wrap\", gap: 8 },\n },\n ...actions,\n )\n : null,\n ].filter(Boolean) as ReactNode[],\n );\n };\n\n const localRow = (server: DevPreviewServer) => {\n const running = server.url === local.activeUrl;\n const meta = [\n server.branch,\n server.hostPort,\n server.version ? `v${server.version}` : \"\",\n ]\n .filter(Boolean)\n .join(\" · \");\n const badge =\n server.compatible === false\n ? { text: labels.localIncompatible, color: theme.warning }\n : server.compatible === null\n ? { text: labels.localUnknownBuild, color: theme.muted }\n : null;\n return h(\n View,\n {\n key: server.hostPort,\n style: {\n gap: 6,\n paddingTop: 8,\n borderTopWidth: 1,\n borderColor: theme.border,\n },\n },\n h(\n View,\n {\n style: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n gap: 8,\n },\n },\n h(\n Text,\n { style: { ...font(\"bold\", 16), color: theme.title, flexShrink: 1 } },\n server.title,\n ),\n running\n ? h(\n Text,\n { style: { ...font(\"medium\", 13), color: theme.success } },\n labels.running,\n )\n : null,\n ),\n h(Text, { style: { ...font(\"regular\", 13), color: theme.muted } }, meta),\n badge\n ? h(\n Text,\n { style: { ...font(\"medium\", 13), color: badge.color } },\n badge.text,\n )\n : null,\n h(\n View,\n { style: { flexDirection: \"row\", flexWrap: \"wrap\", gap: 8 } },\n running\n ? button(\n labels.stopDevPreviewServer,\n () => devPreviewServersStore.switchTo(null),\n \"plain\",\n )\n : button(labels.switchTo, () =>\n devPreviewServersStore.switchTo(server),\n ),\n ),\n );\n };\n\n const localSection = showLocal\n ? card(\n \"local\",\n [\n h(\n Text,\n {\n key: \"title\",\n style: { ...font(\"bold\", 17), color: theme.title },\n },\n labels.devPreviewServersTitle,\n ),\n h(\n Text,\n {\n key: \"hint\",\n style: { ...font(\"regular\", 13), color: theme.muted },\n },\n labels.devPreviewServersHint,\n ),\n local.error\n ? h(\n Text,\n {\n key: \"error\",\n style: { ...font(\"regular\", 13), color: theme.danger },\n },\n local.error,\n )\n : null,\n ...(!appSlug\n ? [\n h(\n Text,\n {\n key: \"noslug\",\n style: { ...font(\"regular\", 15), color: theme.danger },\n },\n labels.noBuildSlug,\n ),\n ]\n : local.servers.length > 0\n ? local.servers.map(localRow)\n : [\n h(\n Text,\n {\n key: \"none\",\n style: { ...font(\"regular\", 15), color: theme.muted },\n },\n labels.noDevPreviewServers,\n ),\n ]),\n ].filter(Boolean) as ReactNode[],\n )\n : null;\n\n const header = card(\n \"header\",\n [\n h(\n Text,\n { key: \"title\", style: { ...font(\"bold\", 22), color: theme.title } },\n labels.title,\n ),\n h(\n Text,\n {\n key: \"running\",\n style: { ...font(\"regular\", 15), color: theme.text },\n },\n `${labels.running}: ${\n now.kind === \"local\"\n ? now.server\n ? `${now.server.title} (${labels.localSuffix}, ${now.hostPort})`\n : `${now.hostPort} (${labels.localSuffix})`\n : now.kind === \"preview\"\n ? now.title\n : labels.base\n }`,\n ),\n // A dev preview server wins over a picked preview, so Metro is in use and the note would be wrong.\n __DEV__ && now.kind === \"preview\"\n ? h(\n Text,\n {\n key: \"metro\",\n style: { ...font(\"medium\", 13), color: theme.warning },\n },\n labels.metroBypassed,\n )\n : null,\n preview.error\n ? h(\n Text,\n {\n key: \"error\",\n style: { ...font(\"regular\", 13), color: theme.danger },\n },\n preview.error,\n )\n : null,\n h(\n View,\n {\n key: \"actions\",\n style: {\n flexDirection: \"row\",\n flexWrap: \"wrap\",\n gap: 8,\n alignItems: \"center\",\n },\n },\n preview.activeId || (showLocal && local.activeUrl)\n ? button(labels.backToBase, () => preview.switchTo(null))\n : null,\n button(labels.refresh, () => preview.refresh(), \"plain\"),\n preview.loading\n ? h(ActivityIndicator, { key: \"spinner\", color: theme.primary })\n : null,\n ),\n ].filter(Boolean) as ReactNode[],\n );\n\n const empty =\n !preview.loading && preview.items.length === 0\n ? h(\n Text,\n {\n key: \"empty\",\n style: {\n ...font(\"regular\", 15),\n color: theme.muted,\n textAlign: \"center\",\n padding: 16,\n },\n },\n preview.buildKey ? labels.empty : labels.noBuildKey,\n )\n : null;\n\n const incompatible =\n preview.incompatible.length > 0\n ? card(\"incompatible\", [\n h(\n Text,\n {\n key: \"title\",\n style: { ...font(\"bold\", 17), color: theme.title },\n },\n labels.incompatibleTitle,\n ),\n h(\n Text,\n {\n key: \"hint\",\n style: { ...font(\"regular\", 13), color: theme.muted },\n },\n labels.incompatibleHint,\n ),\n ...preview.incompatible.map((p) =>\n h(\n Text,\n {\n key: p.id,\n style: { ...font(\"regular\", 15), color: theme.text },\n },\n `${p.entry.title} · ${formatSize(p.entry.size)}`,\n ),\n ),\n h(\n View,\n { key: \"actions\", style: { flexDirection: \"row\" } },\n button(\n labels.deleteAll,\n () => preview.removeIncompatible(),\n \"danger\",\n ),\n ),\n ])\n : null;\n\n return h(\n ScrollView,\n {\n style: [{ backgroundColor: theme.background }, props.style],\n contentContainerStyle: { padding: 16, gap: 12 },\n },\n header,\n localSection,\n ...preview.items.map(row),\n empty,\n incompatible,\n );\n}\n"]}