@ceraph/react-native-mcp 0.2.2 → 0.3.2

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 (124) hide show
  1. package/LICENSE +116 -15
  2. package/README.md +79 -77
  3. package/assets/default.png +0 -0
  4. package/dist/app-lifecycle.d.ts +50 -0
  5. package/dist/app-lifecycle.js +487 -0
  6. package/dist/camera-image-writer.d.ts +43 -0
  7. package/dist/camera-image-writer.js +280 -0
  8. package/dist/camera-registry-sync.d.ts +18 -0
  9. package/dist/camera-registry-sync.js +117 -0
  10. package/dist/cli.d.ts +0 -7
  11. package/dist/cli.js +41 -9
  12. package/dist/device-autonomy.d.ts +30 -0
  13. package/dist/device-autonomy.js +117 -0
  14. package/dist/error-parser.d.ts +6 -26
  15. package/dist/error-parser.js +4 -74
  16. package/dist/expo-manager.d.ts +2 -74
  17. package/dist/expo-manager.js +11 -125
  18. package/dist/index.d.ts +0 -7
  19. package/dist/index.js +1266 -56
  20. package/dist/init/ast-camera.d.ts +29 -0
  21. package/dist/init/ast-camera.js +267 -0
  22. package/dist/init/ast-layout.d.ts +15 -0
  23. package/dist/init/ast-layout.js +167 -0
  24. package/dist/init/claude-hook-constants.d.ts +9 -0
  25. package/dist/init/claude-hook-constants.js +91 -0
  26. package/dist/init/lan-ip.d.ts +11 -0
  27. package/dist/init/lan-ip.js +51 -0
  28. package/dist/init/monorepo.d.ts +13 -0
  29. package/dist/init/monorepo.js +185 -0
  30. package/dist/init/oauth.d.ts +52 -0
  31. package/dist/init/oauth.js +220 -0
  32. package/dist/init/package-manager.d.ts +11 -0
  33. package/dist/init/package-manager.js +60 -0
  34. package/dist/init/prompt.d.ts +12 -0
  35. package/dist/init/prompt.js +68 -0
  36. package/dist/init/shell-profile.d.ts +22 -0
  37. package/dist/init/shell-profile.js +85 -0
  38. package/dist/init/steps.d.ts +135 -0
  39. package/dist/init/steps.js +399 -0
  40. package/dist/init/url-scheme.d.ts +42 -0
  41. package/dist/init/url-scheme.js +187 -0
  42. package/dist/init/walkthrough.d.ts +76 -0
  43. package/dist/init/walkthrough.js +340 -0
  44. package/dist/init.d.ts +7 -7
  45. package/dist/init.js +280 -120
  46. package/dist/iproxy-manager.d.ts +32 -0
  47. package/dist/iproxy-manager.js +216 -0
  48. package/dist/mac-caffeinate.d.ts +10 -0
  49. package/dist/mac-caffeinate.js +56 -0
  50. package/dist/permission-interceptor.d.ts +29 -0
  51. package/dist/permission-interceptor.js +185 -0
  52. package/dist/prebuild-detector.d.ts +0 -30
  53. package/dist/prebuild-detector.js +1 -42
  54. package/dist/preflight.d.ts +34 -0
  55. package/dist/preflight.js +847 -0
  56. package/dist/screen.d.ts +132 -43
  57. package/dist/screen.js +668 -94
  58. package/dist/shim/boot.d.ts +41 -0
  59. package/dist/shim/boot.js +141 -0
  60. package/dist/shim/camera.d.ts +22 -0
  61. package/dist/shim/camera.js +62 -0
  62. package/dist/shim/config.d.ts +6 -0
  63. package/dist/shim/config.js +56 -0
  64. package/dist/shim/deep-link.d.ts +1 -0
  65. package/dist/shim/deep-link.js +25 -0
  66. package/dist/shim/dev-guard.d.ts +1 -0
  67. package/dist/shim/dev-guard.js +3 -0
  68. package/dist/shim/error-handler.d.ts +20 -0
  69. package/dist/shim/error-handler.js +66 -0
  70. package/dist/shim/fetch-interceptor.d.ts +13 -0
  71. package/dist/shim/fetch-interceptor.js +93 -0
  72. package/dist/shim/index.d.ts +6 -0
  73. package/dist/shim/index.js +6 -0
  74. package/dist/shim/keep-awake.d.ts +13 -0
  75. package/dist/shim/keep-awake.js +118 -0
  76. package/dist/shim/reload.d.ts +23 -0
  77. package/dist/shim/reload.js +76 -0
  78. package/dist/shim/signal-capture.d.ts +11 -0
  79. package/dist/shim/signal-capture.js +15 -0
  80. package/dist/shim/signal-transport.d.ts +17 -0
  81. package/dist/shim/signal-transport.js +43 -0
  82. package/dist/signal-listener.d.ts +27 -0
  83. package/dist/signal-listener.js +135 -0
  84. package/dist/simulator-boot.d.ts +52 -0
  85. package/dist/simulator-boot.js +227 -0
  86. package/dist/target.d.ts +48 -0
  87. package/dist/target.js +267 -0
  88. package/dist/uninstall/cli-runner.d.ts +32 -0
  89. package/dist/uninstall/cli-runner.js +223 -0
  90. package/dist/uninstall/footprint.d.ts +40 -0
  91. package/dist/uninstall/footprint.js +288 -0
  92. package/dist/uninstall/mcp-tools.d.ts +14 -0
  93. package/dist/uninstall/mcp-tools.js +175 -0
  94. package/dist/uninstall/revert-auth.d.ts +22 -0
  95. package/dist/uninstall/revert-auth.js +31 -0
  96. package/dist/uninstall/revert-boot.d.ts +24 -0
  97. package/dist/uninstall/revert-boot.js +242 -0
  98. package/dist/uninstall/revert-camera.d.ts +12 -0
  99. package/dist/uninstall/revert-camera.js +199 -0
  100. package/dist/uninstall/revert-ceraph-dir.d.ts +27 -0
  101. package/dist/uninstall/revert-ceraph-dir.js +38 -0
  102. package/dist/uninstall/revert-claude-hooks.d.ts +19 -0
  103. package/dist/uninstall/revert-claude-hooks.js +191 -0
  104. package/dist/uninstall/revert-gitignore.d.ts +17 -0
  105. package/dist/uninstall/revert-gitignore.js +43 -0
  106. package/dist/uninstall/revert-mcp-clients.d.ts +57 -0
  107. package/dist/uninstall/revert-mcp-clients.js +194 -0
  108. package/dist/uninstall/revert-package.d.ts +34 -0
  109. package/dist/uninstall/revert-package.js +98 -0
  110. package/dist/uninstall/revert-scheme.d.ts +36 -0
  111. package/dist/uninstall/revert-scheme.js +139 -0
  112. package/dist/uninstall/revert-signal-host-env.d.ts +31 -0
  113. package/dist/uninstall/revert-signal-host-env.js +61 -0
  114. package/dist/uninstall/walkthrough.d.ts +80 -0
  115. package/dist/uninstall/walkthrough.js +1244 -0
  116. package/dist/utils/atomic-write.d.ts +1 -0
  117. package/dist/utils/atomic-write.js +30 -0
  118. package/dist/wait-for-device.d.ts +68 -0
  119. package/dist/wait-for-device.js +368 -0
  120. package/dist/wda-manager.d.ts +38 -0
  121. package/dist/wda-manager.js +186 -0
  122. package/dist/wda-simulator.d.ts +28 -0
  123. package/dist/wda-simulator.js +257 -0
  124. package/package.json +59 -5
@@ -0,0 +1,487 @@
1
+ import { spawn } from "node:child_process";
2
+ function runCommand(cmd, args, opts = {}) {
3
+ return new Promise((resolve) => {
4
+ let stdout = "";
5
+ let stderr = "";
6
+ let child;
7
+ try {
8
+ child = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
9
+ }
10
+ catch (err) {
11
+ resolve({
12
+ code: 127,
13
+ stdout: "",
14
+ stderr: err instanceof Error ? err.message : String(err),
15
+ });
16
+ return;
17
+ }
18
+ const timer = setTimeout(() => {
19
+ try {
20
+ child.kill("SIGKILL");
21
+ }
22
+ catch {
23
+ }
24
+ }, opts.timeoutMs ?? 15000);
25
+ child.stdout?.on("data", (d) => {
26
+ stdout += d.toString();
27
+ });
28
+ child.stderr?.on("data", (d) => {
29
+ stderr += d.toString();
30
+ });
31
+ let settled = false;
32
+ child.on("error", (err) => {
33
+ if (settled)
34
+ return;
35
+ settled = true;
36
+ clearTimeout(timer);
37
+ resolve({
38
+ code: 127,
39
+ stdout,
40
+ stderr: stderr + (err.message ?? String(err)),
41
+ });
42
+ });
43
+ child.on("exit", (code) => {
44
+ if (settled)
45
+ return;
46
+ settled = true;
47
+ clearTimeout(timer);
48
+ resolve({ code: code ?? 1, stdout, stderr });
49
+ });
50
+ });
51
+ }
52
+ async function hasBinary(bin) {
53
+ const res = await runCommand("which", [bin], { timeoutMs: 2000 });
54
+ return res.code === 0 && res.stdout.trim().length > 0;
55
+ }
56
+ export function parseSimctlListapps(stdout) {
57
+ const apps = [];
58
+ let depth = 0;
59
+ let inApp = false;
60
+ let appKey = null;
61
+ let bundleId = null;
62
+ let name = null;
63
+ let displayName = null;
64
+ let shortVersion = null;
65
+ let version = null;
66
+ const stripValue = (raw) => {
67
+ let s = raw.trim();
68
+ if (s.endsWith(";"))
69
+ s = s.slice(0, -1).trim();
70
+ if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
71
+ s = s.slice(1, -1);
72
+ }
73
+ return s;
74
+ };
75
+ for (const rawLine of stdout.split("\n")) {
76
+ const line = rawLine.trim();
77
+ if (line.length === 0)
78
+ continue;
79
+ if (depth === 1 && !inApp && line.endsWith("{")) {
80
+ const eqIdx = line.indexOf("=");
81
+ if (eqIdx > 0) {
82
+ const key = stripValue(line.slice(0, eqIdx));
83
+ appKey = key;
84
+ bundleId = key;
85
+ name = null;
86
+ displayName = null;
87
+ shortVersion = null;
88
+ version = null;
89
+ inApp = true;
90
+ }
91
+ depth += 1;
92
+ continue;
93
+ }
94
+ if (line.endsWith("{")) {
95
+ depth += 1;
96
+ continue;
97
+ }
98
+ if (line === "};" || line === "}") {
99
+ if (inApp && depth === 2) {
100
+ const finalBundleId = bundleId ?? appKey;
101
+ if (finalBundleId) {
102
+ apps.push({
103
+ bundleId: finalBundleId,
104
+ name: displayName ?? name ?? finalBundleId,
105
+ version: shortVersion ?? version ?? undefined,
106
+ });
107
+ }
108
+ inApp = false;
109
+ appKey = null;
110
+ bundleId = null;
111
+ name = null;
112
+ displayName = null;
113
+ shortVersion = null;
114
+ version = null;
115
+ }
116
+ depth = Math.max(0, depth - 1);
117
+ continue;
118
+ }
119
+ if (inApp && depth === 2) {
120
+ const eqIdx = line.indexOf("=");
121
+ if (eqIdx < 0)
122
+ continue;
123
+ const key = line.slice(0, eqIdx).trim();
124
+ const value = stripValue(line.slice(eqIdx + 1));
125
+ switch (key) {
126
+ case "CFBundleIdentifier":
127
+ bundleId = value;
128
+ break;
129
+ case "CFBundleName":
130
+ name = value;
131
+ break;
132
+ case "CFBundleDisplayName":
133
+ displayName = value;
134
+ break;
135
+ case "CFBundleShortVersionString":
136
+ shortVersion = value;
137
+ break;
138
+ case "CFBundleVersion":
139
+ version = value;
140
+ break;
141
+ default:
142
+ break;
143
+ }
144
+ }
145
+ }
146
+ return apps;
147
+ }
148
+ export class AppLifecycle {
149
+ screen;
150
+ targetResolver;
151
+ udid = null;
152
+ udidResolved = false;
153
+ udidResolvedAt = 0;
154
+ static UDID_TTL_MS = 5_000;
155
+ udidInflight = null;
156
+ devicectlAvailable = null;
157
+ idbAvailable = null;
158
+ installedAppsCache = null;
159
+ INSTALLED_CACHE_MS = 30_000;
160
+ constructor(screen, targetResolver) {
161
+ this.screen = screen;
162
+ this.targetResolver = targetResolver;
163
+ }
164
+ setTargetResolver(resolver) {
165
+ this.targetResolver = resolver;
166
+ }
167
+ async pickTransport() {
168
+ if (!this.targetResolver) {
169
+ return { preferSimulator: false, simulatorUdid: "booted" };
170
+ }
171
+ const info = await this.targetResolver.resolve();
172
+ const preferSimulator = info.target === "simulator";
173
+ const simulatorUdid = info.target === "simulator" && info.udid ? info.udid : "booted";
174
+ return { preferSimulator, simulatorUdid };
175
+ }
176
+ async getUdid() {
177
+ if (this.udidResolved &&
178
+ this.udid &&
179
+ Date.now() - this.udidResolvedAt < AppLifecycle.UDID_TTL_MS) {
180
+ return this.udid;
181
+ }
182
+ if (this.udidInflight)
183
+ return this.udidInflight;
184
+ const work = (async () => {
185
+ try {
186
+ const hasXcrun = await hasBinary("xcrun");
187
+ if (!hasXcrun)
188
+ return null;
189
+ const res = await runCommand("xcrun", ["devicectl", "list", "devices", "--json-output", "-"], { timeoutMs: 8000 });
190
+ if (res.code !== 0)
191
+ return null;
192
+ const parsed = JSON.parse(res.stdout);
193
+ const devices = parsed.result?.devices ?? [];
194
+ const real = devices.find((d) => {
195
+ const platform = d.hardwareProperties?.platform?.toLowerCase() ?? "";
196
+ const tunnel = d.connectionProperties?.tunnelState?.toLowerCase() ?? "";
197
+ return platform.includes("ios") && tunnel === "connected";
198
+ });
199
+ if (real?.identifier) {
200
+ this.udid = real.identifier;
201
+ this.udidResolved = true;
202
+ this.udidResolvedAt = Date.now();
203
+ return this.udid;
204
+ }
205
+ const anyIos = devices.find((d) => (d.hardwareProperties?.platform?.toLowerCase() ?? "").includes("ios"));
206
+ if (anyIos?.identifier) {
207
+ this.udid = anyIos.identifier;
208
+ this.udidResolved = true;
209
+ this.udidResolvedAt = Date.now();
210
+ return this.udid;
211
+ }
212
+ }
213
+ catch {
214
+ }
215
+ return null;
216
+ })();
217
+ this.udidInflight = work;
218
+ try {
219
+ return await work;
220
+ }
221
+ finally {
222
+ this.udidInflight = null;
223
+ }
224
+ }
225
+ async checkDevicectl() {
226
+ if (this.devicectlAvailable !== null)
227
+ return this.devicectlAvailable;
228
+ const hasXcrun = await hasBinary("xcrun");
229
+ if (!hasXcrun) {
230
+ this.devicectlAvailable = false;
231
+ return false;
232
+ }
233
+ const res = await runCommand("xcrun", ["devicectl", "--help"], {
234
+ timeoutMs: 4000,
235
+ });
236
+ this.devicectlAvailable = res.code === 0;
237
+ return this.devicectlAvailable;
238
+ }
239
+ async checkIdb() {
240
+ if (this.idbAvailable !== null)
241
+ return this.idbAvailable;
242
+ this.idbAvailable = await hasBinary("idb");
243
+ return this.idbAvailable;
244
+ }
245
+ async launchApp(bundleId) {
246
+ const transport = await this.pickTransport();
247
+ if (transport.preferSimulator) {
248
+ const simUdid = transport.simulatorUdid;
249
+ const res = await runCommand("xcrun", ["simctl", "launch", simUdid, bundleId], { timeoutMs: 15_000 });
250
+ if (res.code === 0) {
251
+ return { success: true, transport: "simctl", details: { udid: simUdid } };
252
+ }
253
+ return {
254
+ success: false,
255
+ transport: "simctl",
256
+ error: `simctl launch failed: ${(res.stderr || res.stdout).trim()}`,
257
+ details: { udid: simUdid },
258
+ };
259
+ }
260
+ const udid = await this.getUdid();
261
+ if (udid && (await this.checkDevicectl())) {
262
+ const res = await runCommand("xcrun", [
263
+ "devicectl",
264
+ "device",
265
+ "process",
266
+ "launch",
267
+ "--device",
268
+ udid,
269
+ "--terminate-existing",
270
+ bundleId,
271
+ ], { timeoutMs: 30_000 });
272
+ if (res.code === 0) {
273
+ return { success: true, transport: "devicectl", details: { udid } };
274
+ }
275
+ const devicectlError = res.stderr || res.stdout;
276
+ if (!(await this.checkIdb())) {
277
+ return {
278
+ success: false,
279
+ transport: "devicectl",
280
+ error: `devicectl launch failed: ${devicectlError.trim()}`,
281
+ };
282
+ }
283
+ }
284
+ if (await this.checkIdb()) {
285
+ const idbArgs = ["launch", bundleId];
286
+ if (udid)
287
+ idbArgs.push("--udid", udid);
288
+ const res = await runCommand("idb", idbArgs, { timeoutMs: 30_000 });
289
+ if (res.code === 0) {
290
+ return { success: true, transport: "idb", details: { udid } };
291
+ }
292
+ if (!udid) {
293
+ }
294
+ else {
295
+ return {
296
+ success: false,
297
+ transport: "idb",
298
+ error: `idb launch failed: ${(res.stderr || res.stdout).trim()}`,
299
+ };
300
+ }
301
+ }
302
+ if (!udid) {
303
+ const res = await runCommand("xcrun", ["simctl", "launch", "booted", bundleId], { timeoutMs: 15_000 });
304
+ if (res.code === 0) {
305
+ return { success: true, transport: "simctl" };
306
+ }
307
+ return {
308
+ success: false,
309
+ transport: "simctl",
310
+ error: `simctl launch failed: ${(res.stderr || res.stdout).trim()}`,
311
+ };
312
+ }
313
+ return {
314
+ success: false,
315
+ transport: "none",
316
+ error: "No working launch transport found. Install Xcode (for devicectl) " +
317
+ "or idb (https://fbidb.io/) to launch apps on a real device.",
318
+ };
319
+ }
320
+ async terminateApp(bundleId) {
321
+ const transport = await this.pickTransport();
322
+ if (transport.preferSimulator) {
323
+ const simUdid = transport.simulatorUdid;
324
+ const res = await runCommand("xcrun", ["simctl", "terminate", simUdid, bundleId], { timeoutMs: 10_000 });
325
+ if (res.code === 0) {
326
+ return { success: true, transport: "simctl", details: { udid: simUdid } };
327
+ }
328
+ return {
329
+ success: false,
330
+ transport: "simctl",
331
+ error: `simctl terminate failed: ${(res.stderr || res.stdout).trim()}`,
332
+ details: { udid: simUdid },
333
+ };
334
+ }
335
+ const udid = await this.getUdid();
336
+ if (udid && (await this.checkDevicectl())) {
337
+ const res = await runCommand("xcrun", [
338
+ "devicectl",
339
+ "device",
340
+ "process",
341
+ "terminate",
342
+ "--device",
343
+ udid,
344
+ "--bundle-identifier",
345
+ bundleId,
346
+ ], { timeoutMs: 15_000 });
347
+ if (res.code === 0) {
348
+ return { success: true, transport: "devicectl" };
349
+ }
350
+ }
351
+ if (await this.checkIdb()) {
352
+ const args = ["terminate", bundleId];
353
+ if (udid)
354
+ args.push("--udid", udid);
355
+ const res = await runCommand("idb", args, { timeoutMs: 15_000 });
356
+ if (res.code === 0) {
357
+ return { success: true, transport: "idb" };
358
+ }
359
+ }
360
+ if (!udid) {
361
+ const res = await runCommand("xcrun", ["simctl", "terminate", "booted", bundleId], { timeoutMs: 10_000 });
362
+ if (res.code === 0) {
363
+ return { success: true, transport: "simctl" };
364
+ }
365
+ return {
366
+ success: false,
367
+ transport: "simctl",
368
+ error: `simctl terminate failed: ${(res.stderr || res.stdout).trim()}`,
369
+ };
370
+ }
371
+ return {
372
+ success: false,
373
+ transport: "none",
374
+ error: "Failed to terminate via devicectl or idb.",
375
+ };
376
+ }
377
+ async activateApp(bundleId) {
378
+ if (this.screen) {
379
+ const reachable = await this.screen.isAvailable();
380
+ if (reachable) {
381
+ const res = await this.screen.activateApp(bundleId);
382
+ if (res.success) {
383
+ return { success: true, transport: "wda" };
384
+ }
385
+ }
386
+ }
387
+ return this.launchApp(bundleId);
388
+ }
389
+ async listInstalledApps() {
390
+ const transport = await this.pickTransport();
391
+ const deviceUdidForKey = transport.preferSimulator
392
+ ? null
393
+ : await this.getUdid();
394
+ const cacheKey = transport.preferSimulator
395
+ ? `sim:${transport.simulatorUdid}`
396
+ : `device:${deviceUdidForKey ?? "none"}`;
397
+ if (this.installedAppsCache &&
398
+ this.installedAppsCache.key === cacheKey &&
399
+ Date.now() - this.installedAppsCache.at < this.INSTALLED_CACHE_MS) {
400
+ return { success: true, apps: this.installedAppsCache.apps };
401
+ }
402
+ if (transport.preferSimulator) {
403
+ return this.listInstalledAppsSimulator(transport.simulatorUdid, cacheKey);
404
+ }
405
+ const udid = deviceUdidForKey;
406
+ if (!udid) {
407
+ return {
408
+ success: false,
409
+ apps: [],
410
+ error: "No real iOS device connected. Connect a device via USB-C and trust this Mac.",
411
+ };
412
+ }
413
+ if (!(await this.checkDevicectl())) {
414
+ return {
415
+ success: false,
416
+ apps: [],
417
+ error: "xcrun devicectl not available — install Xcode 15 or newer.",
418
+ };
419
+ }
420
+ const res = await runCommand("xcrun", [
421
+ "devicectl",
422
+ "device",
423
+ "info",
424
+ "apps",
425
+ "--device",
426
+ udid,
427
+ "--json-output",
428
+ "-",
429
+ ], { timeoutMs: 20_000 });
430
+ if (res.code !== 0) {
431
+ return {
432
+ success: false,
433
+ apps: [],
434
+ error: `devicectl info apps failed: ${(res.stderr || res.stdout).trim()}`,
435
+ };
436
+ }
437
+ try {
438
+ const parsed = JSON.parse(res.stdout);
439
+ const apps = (parsed.result?.apps ?? [])
440
+ .filter((a) => !!a.bundleIdentifier)
441
+ .map((a) => ({
442
+ bundleId: a.bundleIdentifier,
443
+ name: a.name ?? a.bundleIdentifier,
444
+ version: a.shortVersionString ?? a.version,
445
+ }));
446
+ this.installedAppsCache = { at: Date.now(), key: cacheKey, apps };
447
+ return { success: true, apps };
448
+ }
449
+ catch (err) {
450
+ return {
451
+ success: false,
452
+ apps: [],
453
+ error: `Failed to parse devicectl output: ${err instanceof Error ? err.message : String(err)}`,
454
+ };
455
+ }
456
+ }
457
+ async listInstalledAppsSimulator(simUdid, cacheKey) {
458
+ const res = await runCommand("xcrun", ["simctl", "listapps", simUdid], { timeoutMs: 15_000 });
459
+ if (res.code !== 0) {
460
+ return {
461
+ success: false,
462
+ apps: [],
463
+ error: `simctl listapps failed: ${(res.stderr || res.stdout).trim()}`,
464
+ };
465
+ }
466
+ const apps = parseSimctlListapps(res.stdout);
467
+ this.installedAppsCache = { at: Date.now(), key: cacheKey, apps };
468
+ return { success: true, apps };
469
+ }
470
+ async getActiveApp() {
471
+ if (!this.screen) {
472
+ return {
473
+ success: false,
474
+ error: "ScreenManager not provided — cannot query active app via WDA.",
475
+ };
476
+ }
477
+ return this.screen.getActiveAppInfo();
478
+ }
479
+ reset() {
480
+ this.udid = null;
481
+ this.udidResolved = false;
482
+ this.udidResolvedAt = 0;
483
+ this.devicectlAvailable = null;
484
+ this.idbAvailable = null;
485
+ this.installedAppsCache = null;
486
+ }
487
+ }
@@ -0,0 +1,43 @@
1
+ import { syncCameraRegistry, type SyncResult } from "./camera-registry-sync.js";
2
+ export declare const SUPPORTED_EXTENSIONS: readonly ["jpg", "jpeg", "png", "webp", "heic"];
3
+ export type SupportedExt = (typeof SUPPORTED_EXTENSIONS)[number];
4
+ export declare const MAX_IMAGE_BYTES: number;
5
+ export interface AddCameraImageOptions {
6
+ imageKey: string;
7
+ imageBase64: string;
8
+ contentType?: string;
9
+ overwrite?: boolean;
10
+ subDir?: string;
11
+ }
12
+ export interface AddCameraImageWarning {
13
+ code: "content-type-mismatch" | "content-type-unrecognized" | "image-larger-than-typical";
14
+ message: string;
15
+ }
16
+ export interface AddCameraImageResult {
17
+ written: string;
18
+ registry: string;
19
+ registered: string[];
20
+ detectedContentType: string;
21
+ detectedExt: SupportedExt;
22
+ replaced: boolean;
23
+ removedSiblingPath?: string;
24
+ bytes: number;
25
+ warnings: AddCameraImageWarning[];
26
+ registryState: SyncResult["writtenOrUnchanged"];
27
+ }
28
+ export declare class AddCameraImageError extends Error {
29
+ readonly code: string;
30
+ readonly remediation: string;
31
+ constructor(code: string, message: string, remediation: string);
32
+ }
33
+ export declare function validateImageKey(key: string): void;
34
+ export declare function validateSubDir(subDir: string): void;
35
+ export declare function detectImageType(bytes: Uint8Array): {
36
+ ext: SupportedExt;
37
+ mime: string;
38
+ } | null;
39
+ export declare function normalizeContentTypeHint(hint: string): SupportedExt | null;
40
+ export interface AddCameraImageDeps {
41
+ syncCameraRegistry?: typeof syncCameraRegistry;
42
+ }
43
+ export declare function addCameraImage(projectDir: string, options: AddCameraImageOptions, deps?: AddCameraImageDeps): Promise<AddCameraImageResult>;