@tamagui/native-ci 2.0.0-rc.3 → 2.0.0-rc.30

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/src/ios.ts CHANGED
@@ -9,6 +9,187 @@ import { $ } from 'bun'
9
9
  import { isCI } from './runner'
10
10
  import { generateFingerprint } from './fingerprint'
11
11
 
12
+ /**
13
+ * Check if any iOS simulator is booted and available for testing.
14
+ * Returns true if at least one simulator is booted.
15
+ */
16
+ export function hasBootedSimulator(): boolean {
17
+ return !!getBootedSimulatorUDID()
18
+ }
19
+
20
+ /**
21
+ * Get the UDID of the first booted iOS simulator, or null if none.
22
+ */
23
+ export function getBootedSimulatorUDID(): string | null {
24
+ try {
25
+ const output = execSync('xcrun simctl list devices booted', {
26
+ encoding: 'utf-8',
27
+ stdio: ['pipe', 'pipe', 'pipe'],
28
+ })
29
+ const match = output.match(/\(([A-F0-9-]{36})\)/i)
30
+ return match ? match[1] : null
31
+ } catch {
32
+ return null
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Boot an iOS simulator. Picks the first available iPhone device.
38
+ */
39
+ export function ensureBootedSimulator(): void {
40
+ if (hasBootedSimulator()) return
41
+
42
+ console.info('No booted iOS simulator found, booting one...')
43
+ try {
44
+ const output = execSync('xcrun simctl list devices available', {
45
+ encoding: 'utf-8',
46
+ stdio: ['pipe', 'pipe', 'pipe'],
47
+ })
48
+ // find first available iPhone
49
+ const match = output.match(/iPhone[^\n]*\(([A-F0-9-]{36})\)/i)
50
+ if (!match) {
51
+ throw new Error('No available iPhone simulator found. Install one via Xcode.')
52
+ }
53
+ const udid = match[1]
54
+ console.info(`Booting simulator ${udid}...`)
55
+ execSync(`xcrun simctl boot ${udid}`, { stdio: 'inherit' })
56
+ console.info('Simulator booted.')
57
+ } catch (err) {
58
+ throw new Error(
59
+ `Failed to boot iOS simulator: ${err instanceof Error ? err.message : err}`
60
+ )
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Check if an app is installed on the booted simulator.
66
+ */
67
+ function isAppInstalled(bundleId: string, udid: string): boolean {
68
+ try {
69
+ execSync(`xcrun simctl get_app_container "${udid}" "${bundleId}"`, {
70
+ stdio: ['pipe', 'pipe', 'pipe'],
71
+ })
72
+ return true
73
+ } catch {
74
+ return false
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Ensure the app is installed on a specific simulator.
80
+ * For dev client apps, builds if needed then installs.
81
+ * For Expo Go apps, ensures Expo Go is present.
82
+ */
83
+ export async function ensureAppInstalled(opts: {
84
+ projectRoot: string
85
+ bundleId: string
86
+ udid?: string
87
+ }): Promise<void> {
88
+ const { projectRoot, bundleId } = opts
89
+ const udid = opts.udid || getBootedSimulatorUDID() || 'booted'
90
+
91
+ // check if app is already installed
92
+ if (isAppInstalled(bundleId, udid)) {
93
+ console.info(`App ${bundleId} already installed on simulator ${udid}`)
94
+ return
95
+ }
96
+
97
+ if (bundleId === 'host.exp.Exponent') {
98
+ await installExpoGo(udid)
99
+ return
100
+ }
101
+
102
+ // custom dev client - build and install
103
+ console.info(`App ${bundleId} not installed, building...`)
104
+ await ensureIOSFolder()
105
+
106
+ const appPath =
107
+ process.env.DETOX_IOS_APP_PATH ||
108
+ 'ios/build/Build/Products/Debug-iphonesimulator/tamaguikitchensink.app'
109
+ const fullAppPath = join(projectRoot, appPath)
110
+
111
+ if (!existsSync(fullAppPath)) {
112
+ await ensureIOSApp('ios.sim.debug')
113
+ }
114
+
115
+ console.info(`Installing app on simulator ${udid}...`)
116
+ execSync(`xcrun simctl install "${udid}" "${fullAppPath}"`, { stdio: 'inherit' })
117
+ console.info('App installed.')
118
+ }
119
+
120
+ /**
121
+ * Get the bundle ID needed for maestro tests.
122
+ * Checks flow files first (they declare appId), falls back to app.json.
123
+ */
124
+ export function getMaestroBundleId(projectRoot: string): string {
125
+ // check flow files for appId
126
+ const flowsDir = join(projectRoot, 'flows')
127
+ if (existsSync(flowsDir)) {
128
+ try {
129
+ const files = require('fs').readdirSync(flowsDir) as string[]
130
+ for (const f of files) {
131
+ if (!f.endsWith('.yaml')) continue
132
+ const content = readFileSync(join(flowsDir, f), 'utf-8')
133
+ const match = content.match(/^appId:\s*(.+)$/m)
134
+ if (match) return match[1].trim()
135
+ }
136
+ } catch {}
137
+ }
138
+
139
+ // fall back to app.json
140
+ try {
141
+ const appJson = JSON.parse(readFileSync(join(projectRoot, 'app.json'), 'utf-8'))
142
+ return appJson.expo?.ios?.bundleIdentifier || 'host.exp.Exponent'
143
+ } catch {
144
+ return 'host.exp.Exponent'
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Download and install Expo Go on the booted simulator.
150
+ */
151
+ async function installExpoGo(udid: string): Promise<void> {
152
+ const tmpDir = join(require('os').tmpdir(), 'expo-go-install')
153
+ const appPath = join(tmpDir, 'Expo Go.app')
154
+
155
+ // skip download if already cached
156
+ if (existsSync(appPath)) {
157
+ console.info(`Installing cached Expo Go on simulator ${udid}...`)
158
+ execSync(`xcrun simctl install "${udid}" "${appPath}"`, { stdio: 'inherit' })
159
+ console.info('Expo Go installed.')
160
+ return
161
+ }
162
+
163
+ console.info('Downloading Expo Go...')
164
+ mkdirSync(tmpDir, { recursive: true })
165
+
166
+ // get the download URL from expo's version API
167
+ const { getVersionsAsync } =
168
+ // @ts-ignore - no type declarations for internal expo module
169
+ require('@expo/cli/build/src/api/getVersions') as {
170
+ getVersionsAsync: () => Promise<any>
171
+ }
172
+ const versions = await getVersionsAsync()
173
+
174
+ // find the latest SDK version that has an iOS client URL
175
+ const sdkVersions = Object.entries(versions.sdkVersions || {})
176
+ .filter(([, v]: [string, any]) => v.iosClientUrl)
177
+ .sort(([a], [b]) => b.localeCompare(a, undefined, { numeric: true }))
178
+ const clientUrl = (sdkVersions[0]?.[1] as any)?.iosClientUrl
179
+
180
+ if (!clientUrl) {
181
+ throw new Error('Could not find Expo Go download URL')
182
+ }
183
+
184
+ execSync(`curl -fsSL "${clientUrl}" -o "${tmpDir}/ExpoGo.tar.gz"`, { stdio: 'inherit' })
185
+ // archive contains .app contents directly, extract into .app bundle
186
+ mkdirSync(appPath, { recursive: true })
187
+ execSync(`tar -xzf "${tmpDir}/ExpoGo.tar.gz" -C "${appPath}"`, { stdio: 'inherit' })
188
+
189
+ execSync(`xcrun simctl install "${udid}" "${appPath}"`, { stdio: 'inherit' })
190
+ console.info('Expo Go installed.')
191
+ }
192
+
12
193
  /**
13
194
  * Shutdown all simulators and clean up zombie simulator processes.
14
195
  * macOS doesn't properly clean up simulators between test runs, leading to
@@ -107,6 +288,7 @@ function saveFingerprintCache(projectRoot: string, cache: FingerprintCache): voi
107
288
  *
108
289
  * IMPORTANT: Fingerprint only changes when NATIVE dependencies change
109
290
  * (Podfile, native modules, etc). JS-only changes don't require rebuild.
291
+ * Set SKIP_IOS_REBUILD=1 to skip rebuild even when fingerprint changes.
110
292
  */
111
293
  export async function ensureIOSApp(config: string = 'ios.sim.debug'): Promise<void> {
112
294
  // On CI, the app is built separately - don't build here
@@ -153,29 +335,24 @@ export async function ensureIOSApp(config: string = 'ios.sim.debug'): Promise<vo
153
335
  return
154
336
  }
155
337
 
156
- // Fingerprint changed - but let user decide if they want to rebuild
157
- // Many fingerprint changes are false positives (timestamp changes, etc)
338
+ // fingerprint changed - rebuild by default since native deps likely changed
158
339
  if (cache?.fingerprint) {
159
340
  console.info(`\n--- iOS fingerprint changed ---`)
160
341
  console.info(`Previous: ${cache.fingerprint.slice(0, 16)}...`)
161
342
  console.info(`Current: ${currentFingerprint.slice(0, 16)}...`)
162
- console.info(`App exists at ${appPath}`)
163
343
 
164
- // Check if FORCE_IOS_REBUILD is set
165
- if (process.env.FORCE_IOS_REBUILD) {
166
- console.info('FORCE_IOS_REBUILD set, rebuilding...')
167
- await buildIOSApp(config, projectRoot, appPath, currentFingerprint)
344
+ if (process.env.SKIP_IOS_REBUILD) {
345
+ console.info('SKIP_IOS_REBUILD set, using existing app')
346
+ saveFingerprintCache(projectRoot, {
347
+ fingerprint: currentFingerprint,
348
+ timestamp: new Date().toISOString(),
349
+ appPath,
350
+ })
168
351
  return
169
352
  }
170
353
 
171
- // Otherwise use existing app but update fingerprint cache
172
- // This avoids unnecessary rebuilds from timestamp/metadata changes
173
- console.info('Using existing app (set FORCE_IOS_REBUILD=1 to force rebuild)')
174
- saveFingerprintCache(projectRoot, {
175
- fingerprint: currentFingerprint,
176
- timestamp: new Date().toISOString(),
177
- appPath,
178
- })
354
+ console.info('Native dependencies changed, rebuilding...')
355
+ await buildIOSApp(config, projectRoot, appPath, currentFingerprint)
179
356
  return
180
357
  }
181
358
 
package/src/metro.ts CHANGED
@@ -6,8 +6,10 @@
6
6
  */
7
7
 
8
8
  import type { Subprocess } from 'bun'
9
+ import { execSync } from 'node:child_process'
9
10
  import {
10
11
  METRO_URL,
12
+ METRO_PORT,
11
13
  DEFAULT_METRO_WAIT_ATTEMPTS,
12
14
  DEFAULT_METRO_WAIT_INTERVAL_MS,
13
15
  type Platform,
@@ -93,6 +95,26 @@ export async function prewarmBundle(platform: Platform): Promise<void> {
93
95
  }
94
96
  }
95
97
 
98
+ /**
99
+ * Detect if the current project uses expo-dev-client by checking package.json.
100
+ */
101
+ function projectUsesDevClient(): boolean {
102
+ try {
103
+ const pkg = JSON.parse(require('fs').readFileSync('package.json', 'utf-8'))
104
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies }
105
+ // check for expo-dev-client dep, or --dev-client in the start script
106
+ if (deps['expo-dev-client']) return true
107
+ if (
108
+ typeof pkg.scripts?.start === 'string' &&
109
+ pkg.scripts.start.includes('--dev-client')
110
+ )
111
+ return true
112
+ return false
113
+ } catch {
114
+ return false
115
+ }
116
+ }
117
+
96
118
  /**
97
119
  * Start Metro bundler as a background process.
98
120
  *
@@ -103,7 +125,12 @@ export function startMetro(): MetroProcess {
103
125
 
104
126
  // Only clear cache in CI - locally we want fast startup using cached transforms
105
127
  const isCI = !!process.env.CI
106
- const args = ['bun', 'expo', 'start', '--dev-client', '--offline']
128
+ const useDevClient = projectUsesDevClient()
129
+ const args = ['bun', 'expo', 'start', '--offline']
130
+ if (useDevClient) {
131
+ args.splice(3, 0, '--dev-client')
132
+ console.info('Dev client detected')
133
+ }
107
134
  if (isCI) {
108
135
  args.push('--clear')
109
136
  console.info('CI detected: clearing Metro cache')
@@ -167,6 +194,24 @@ async function isMetroRunning(platform: Platform): Promise<boolean> {
167
194
  }
168
195
  }
169
196
 
197
+ /**
198
+ * Kill whatever process is listening on the Metro port.
199
+ * Prevents conflicts with other projects' Metro instances (or anything else on 8081).
200
+ */
201
+ function killPortProcess(): void {
202
+ try {
203
+ const pid = execSync(`lsof -ti tcp:${METRO_PORT} -sTCP:LISTEN`, {
204
+ encoding: 'utf-8',
205
+ }).trim()
206
+ if (pid) {
207
+ console.info(`Killing process ${pid} on port ${METRO_PORT}...`)
208
+ process.kill(Number(pid), 'SIGTERM')
209
+ }
210
+ } catch {
211
+ // nothing listening, or lsof not available
212
+ }
213
+ }
214
+
170
215
  /**
171
216
  * Run a function with Metro bundler, ensuring proper cleanup.
172
217
  * This is a convenience wrapper that handles starting Metro, waiting for it,
@@ -185,7 +230,9 @@ export async function withMetro<T>(platform: Platform, fn: () => Promise<T>): Pr
185
230
  return await fn()
186
231
  }
187
232
 
188
- // Start Metro ourselves
233
+ // kill anything on the port before starting (e.g. another project's Metro)
234
+ killPortProcess()
235
+
189
236
  const metro = startMetro()
190
237
  setupSignalHandlers(metro)
191
238
 
@@ -43,6 +43,7 @@ const exitCode = await withMetro('android', async () => {
43
43
  recordLogs: options.recordLogs,
44
44
  retries: options.retries,
45
45
  headless: options.headless,
46
+ testFiles: options.testFiles,
46
47
  })
47
48
  })
48
49
 
@@ -38,6 +38,7 @@ const exitCode = await withMetro('ios', async () => {
38
38
  recordLogs: options.recordLogs,
39
39
  retries: options.retries,
40
40
  workers: options.workers,
41
+ testFiles: options.testFiles,
41
42
  })
42
43
  })
43
44
 
package/types/detox.d.ts CHANGED
@@ -17,6 +17,8 @@ export interface DetoxRunnerOptions {
17
17
  headless?: boolean;
18
18
  /** Number of parallel workers (default: 1) */
19
19
  workers?: number;
20
+ /** Specific test files to run (passed as positional args to detox) */
21
+ testFiles?: string[];
20
22
  }
21
23
  /**
22
24
  * Parse common CLI arguments for Detox runners
@@ -28,6 +30,7 @@ export declare function parseDetoxArgs(platform: Platform): {
28
30
  recordLogs: string;
29
31
  retries: number;
30
32
  workers: number;
33
+ testFiles: string[] | undefined;
31
34
  };
32
35
  /**
33
36
  * Build Detox CLI command arguments
@@ -1 +1 @@
1
- {"version":3,"file":"detox.d.ts","sourceRoot":"","sources":["../src/detox.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ;;;;;;;EAoChD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAwBpE;AAKD;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOxD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwChF"}
1
+ {"version":3,"file":"detox.d.ts","sourceRoot":"","sources":["../src/detox.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ;;;;;;;;EAsChD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,EAAE,CA6BpE;AAKD;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOxD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwChF"}
package/types/ios.d.ts CHANGED
@@ -1,6 +1,34 @@
1
1
  /**
2
2
  * iOS-specific utilities for Detox test runners
3
3
  */
4
+ /**
5
+ * Check if any iOS simulator is booted and available for testing.
6
+ * Returns true if at least one simulator is booted.
7
+ */
8
+ export declare function hasBootedSimulator(): boolean;
9
+ /**
10
+ * Get the UDID of the first booted iOS simulator, or null if none.
11
+ */
12
+ export declare function getBootedSimulatorUDID(): string | null;
13
+ /**
14
+ * Boot an iOS simulator. Picks the first available iPhone device.
15
+ */
16
+ export declare function ensureBootedSimulator(): void;
17
+ /**
18
+ * Ensure the app is installed on a specific simulator.
19
+ * For dev client apps, builds if needed then installs.
20
+ * For Expo Go apps, ensures Expo Go is present.
21
+ */
22
+ export declare function ensureAppInstalled(opts: {
23
+ projectRoot: string;
24
+ bundleId: string;
25
+ udid?: string;
26
+ }): Promise<void>;
27
+ /**
28
+ * Get the bundle ID needed for maestro tests.
29
+ * Checks flow files first (they declare appId), falls back to app.json.
30
+ */
31
+ export declare function getMaestroBundleId(projectRoot: string): string;
4
32
  /**
5
33
  * Shutdown all simulators and clean up zombie simulator processes.
6
34
  * macOS doesn't properly clean up simulators between test runs, leading to
@@ -29,6 +57,7 @@ export declare function ensureIOSFolder(): Promise<void>;
29
57
  *
30
58
  * IMPORTANT: Fingerprint only changes when NATIVE dependencies change
31
59
  * (Podfile, native modules, etc). JS-only changes don't require rebuild.
60
+ * Set SKIP_IOS_REBUILD=1 to skip rebuild even when fingerprint changes.
32
61
  */
33
62
  export declare function ensureIOSApp(config?: string): Promise<void>;
34
63
  //# sourceMappingURL=ios.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ios.d.ts","sourceRoot":"","sources":["../src/ios.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBrD;AAkCD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,MAAM,GAAE,MAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8ElF"}
1
+ {"version":3,"file":"ios.d.ts","sourceRoot":"","sources":["../src/ios.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAWtD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAuB5C;AAgBD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BhB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAsB9D;AA+CD;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBrD;AAkCD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,MAAM,GAAE,MAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyElF"}
@@ -1 +1 @@
1
- {"version":3,"file":"metro.d.ts","sourceRoot":"","sources":["../src/metro.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AACrC,OAAO,EAIL,KAAK,QAAQ,EAEd,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,QAAQ,EAAE,QAAQ,CAAA;IAClB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,IAAI,EAAE,UAAU,CAAA;IAChB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CA0B1E;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,YAAY,CAsCzC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAS7D;AAgBD;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA0BvF"}
1
+ {"version":3,"file":"metro.d.ts","sourceRoot":"","sources":["../src/metro.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAErC,OAAO,EAKL,KAAK,QAAQ,EAEd,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,QAAQ,EAAE,QAAQ,CAAA;IAClB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,IAAI,EAAE,UAAU,CAAA;IAChB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CA0B1E;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrE;AAsBD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,YAAY,CA2CzC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAS7D;AAkCD;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA4BvF"}
package/dist/cache.js DELETED
@@ -1,71 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { DEFAULT_KV_TTL_SECONDS } from "./constants";
4
- function createCacheKey(options) {
5
- const { platform, fingerprint, prefix = "native-build" } = options;
6
- return `${prefix}-${platform}-${fingerprint}`;
7
- }
8
- async function saveFingerprintToKV(kv, key, fingerprint, ttlSeconds = DEFAULT_KV_TTL_SECONDS) {
9
- try {
10
- const response = await fetch(`${kv.url}/SETEX/${key}/${ttlSeconds}/${fingerprint}`, {
11
- method: "POST",
12
- headers: {
13
- Authorization: `Bearer ${kv.token}`
14
- }
15
- });
16
- if (!response.ok)
17
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
18
- } catch (error) {
19
- throw error instanceof TypeError ? new Error(`Network error connecting to KV store: ${error.message}`) : new Error(`Failed to save fingerprint to KV: ${error.message}`);
20
- }
21
- }
22
- async function getFingerprintFromKV(kv, key) {
23
- try {
24
- const response = await fetch(`${kv.url}/get/${key}`, {
25
- headers: {
26
- Authorization: `Bearer ${kv.token}`
27
- }
28
- });
29
- if (!response.ok)
30
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
31
- const data = await response.json();
32
- return data.result === "null" ? null : data.result;
33
- } catch (error) {
34
- throw error instanceof TypeError ? new Error(`Network error connecting to KV store: ${error.message}`) : new Error(`Failed to get fingerprint from KV: ${error.message}`);
35
- }
36
- }
37
- async function extendKVTTL(kv, key, ttlSeconds = DEFAULT_KV_TTL_SECONDS) {
38
- try {
39
- await fetch(`${kv.url}/EXPIRE/${key}/${ttlSeconds}`, {
40
- method: "POST",
41
- headers: {
42
- Authorization: `Bearer ${kv.token}`
43
- }
44
- });
45
- } catch (error) {
46
- console.warn(`Failed to extend KV TTL: ${error.message}`);
47
- }
48
- }
49
- function saveCache(filePath, data, options = {}) {
50
- const { cacheDir } = options, cachePath = cacheDir ? join(process.cwd(), cacheDir, filePath) : join(process.cwd(), filePath);
51
- mkdirSync(dirname(cachePath), { recursive: !0 }), writeFileSync(cachePath, JSON.stringify(data, null, 2));
52
- }
53
- function loadCache(filePath, options = {}) {
54
- const { cacheDir } = options, cachePath = cacheDir ? join(process.cwd(), cacheDir, filePath) : join(process.cwd(), filePath);
55
- if (!existsSync(cachePath))
56
- return null;
57
- try {
58
- return JSON.parse(readFileSync(cachePath, "utf-8"));
59
- } catch {
60
- return null;
61
- }
62
- }
63
- export {
64
- createCacheKey,
65
- extendKVTTL,
66
- getFingerprintFromKV,
67
- loadCache,
68
- saveCache,
69
- saveFingerprintToKV
70
- };
71
- //# sourceMappingURL=cache.js.map
package/dist/cache.js.map DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/cache.ts"],
4
- "mappings": "AAAA,SAAS,YAAY,cAAc,eAAe,iBAAiB;AACnE,SAAS,SAAS,YAAY;AAC9B,SAAS,8BAA6C;AAgB/C,SAAS,eAAe,SAA+B;AAC5D,QAAM,EAAE,UAAU,aAAa,SAAS,eAAe,IAAI;AAC3D,SAAO,GAAG,MAAM,IAAI,QAAQ,IAAI,WAAW;AAC7C;AAMA,eAAsB,oBACpB,IACA,KACA,aACA,aAAa,wBACE;AACf,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,GAAG,GAAG,UAAU,GAAG,IAAI,UAAU,IAAI,WAAW,IAAI;AAAA,MAClF,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,GAAG,KAAK;AAAA,MACnC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,EAErE,SAAS,OAAO;AACd,UAAI,iBAAiB,YACb,IAAI,MAAM,yCAA0C,MAAgB,OAAO,EAAE,IAE/E,IAAI,MAAM,qCAAsC,MAAgB,OAAO,EAAE;AAAA,EACjF;AACF;AAKA,eAAsB,qBACpB,IACA,KACwB;AACxB,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI;AAAA,MACnD,SAAS;AAAA,QACP,eAAe,UAAU,GAAG,KAAK;AAAA,MACnC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAGnE,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO,KAAK,WAAW,SAAS,OAAO,KAAK;AAAA,EAC9C,SAAS,OAAO;AACd,UAAI,iBAAiB,YACb,IAAI,MAAM,yCAA0C,MAAgB,OAAO,EAAE,IAE/E,IAAI,MAAM,sCAAuC,MAAgB,OAAO,EAAE;AAAA,EAClF;AACF;AAKA,eAAsB,YACpB,IACA,KACA,aAAa,wBACE;AACf,MAAI;AACF,UAAM,MAAM,GAAG,GAAG,GAAG,WAAW,GAAG,IAAI,UAAU,IAAI;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,GAAG,KAAK;AAAA,MACnC;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AAEd,YAAQ,KAAK,4BAA6B,MAAgB,OAAO,EAAE;AAAA,EACrE;AACF;AAYO,SAAS,UACd,UACA,MACA,UAA6B,CAAC,GACxB;AACN,QAAM,EAAE,SAAS,IAAI,SACf,YAAY,WACd,KAAK,QAAQ,IAAI,GAAG,UAAU,QAAQ,IACtC,KAAK,QAAQ,IAAI,GAAG,QAAQ;AAEhC,YAAU,QAAQ,SAAS,GAAG,EAAE,WAAW,GAAK,CAAC,GACjD,cAAc,WAAW,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AACxD;AAMO,SAAS,UACd,UACA,UAA6B,CAAC,GACpB;AACV,QAAM,EAAE,SAAS,IAAI,SACf,YAAY,WACd,KAAK,QAAQ,IAAI,GAAG,UAAU,QAAQ,IACtC,KAAK,QAAQ,IAAI,GAAG,QAAQ;AAEhC,MAAI,CAAC,WAAW,SAAS;AACvB,WAAO;AAGT,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,WAAW,OAAO,CAAC;AAAA,EACpD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
5
- "names": []
6
- }