miaoda-expo-devkit 0.1.1-beta.64 → 0.1.1-beta.69

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/dist/metro.d.mts CHANGED
@@ -111,7 +111,7 @@ declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOp
111
111
  * withDevkit — 一站式 Metro 配置入口
112
112
  *
113
113
  * 按固定顺序依次应用:
114
- * withPersistentCache — 将 Metro transform cache 固定到项目目录(.metro-cache/),重启不丢失
114
+ * withPersistentCache — 将 Metro transform cache 固定到持久目录(优先读取 METRO_CACHE_DIR 环境变量),重启不丢失
115
115
  * withWorkspaceNodeModules — 修复沙箱中 node_modules 位于祖先目录时的模块解析问题
116
116
  * withWasmSupport — 将 .wasm 加入 assetExts,修复 expo-sqlite web worker 打包失败
117
117
  * withCssInterop — 为 expo-image / expo-camera 等注入 NativeWind cssInterop
@@ -339,6 +339,18 @@ declare function withExpoFileSystemStub(config: MetroConfig): MetroConfig;
339
339
 
340
340
  declare function withExpoImagePickerStub(config: MetroConfig): MetroConfig;
341
341
 
342
+ /**
343
+ * withExpoCameraRecordStub — Web 平台为 expo-camera 注入 recordAsync 支持
344
+ *
345
+ * expo-camera 的 recordAsync / stopRecording 在 Web 端未实现。
346
+ * 此 wrapper 仅在 web 平台拦截 expo-camera,注入使用 MediaRecorder API 的 stub,
347
+ * 输出 video/mp4 格式,返回 blob: URI,与原生侧返回值结构一致。
348
+ *
349
+ * Native 端不拦截,原生实现完全正常。
350
+ */
351
+
352
+ declare function withExpoCameraRecordStub(config: MetroConfig): MetroConfig;
353
+
342
354
  /**
343
355
  * withExpoHapticsStub — Web 平台将 expo-haptics 替换为 stub
344
356
  *
@@ -435,11 +447,16 @@ declare function withWasmSupport(config: MetroConfig): MetroConfig;
435
447
  declare function withTransformLogger(config: MetroConfig): MetroConfig;
436
448
 
437
449
  /**
438
- * withPersistentCache — 将 Metro transform cache 固定到项目目录
450
+ * withPersistentCache — 将 Metro transform cache 固定到可持久化目录
439
451
  *
440
452
  * Metro 默认将 transform cache 写入系统临时目录(os.tmpdir()/metro-cache),
441
453
  * 系统随时可以清理,导致每次重启都是冷启动。
442
- * 此 wrapper 将 cacheStores 替换为项目根目录下的 .metro-cache/,持久保留。
454
+ * 此 wrapper 将 cacheStores 替换为指定目录,持久保留。
455
+ *
456
+ * 缓存路径解析优先级(高到低):
457
+ * 1. 环境变量 METRO_CACHE_DIR(绝对路径,适用于容器/CI 挂载外部持久目录)
458
+ * 2. options.cacheDir(绝对路径直接使用;相对路径拼接到 projectRoot)
459
+ * 3. 默认值:projectRoot/.metro-cache
443
460
  *
444
461
  * cache key 由文件内容 sha1 + 相对路径 + Babel/Metro 版本共同决定,
445
462
  * 与项目绝对路径无关,换目录 clone 后缓存同样有效。
@@ -447,10 +464,13 @@ declare function withTransformLogger(config: MetroConfig): MetroConfig;
447
464
 
448
465
  interface PersistentCacheOptions {
449
466
  /**
450
- * cache 目录,相对于 projectRoot。默认:'.metro-cache'
467
+ * cache 目录。
468
+ * - 绝对路径:直接使用(适合挂载外部持久目录)
469
+ * - 相对路径:拼接到 projectRoot
470
+ * - 省略:使用环境变量 METRO_CACHE_DIR,否则默认 '.metro-cache'(相对 projectRoot)
451
471
  */
452
472
  cacheDir?: string;
453
473
  }
454
474
  declare function withPersistentCache(config: MetroConfig, options?: PersistentCacheOptions): MetroConfig;
455
475
 
456
- export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type PersistentCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoCalendarStub, withExpoContactsStub, withExpoFileSystemStub, withExpoHapticsStub, withExpoImagePickerStub, withExpoMediaLibraryStub, withExpoNotificationsStub, withLucideResolver, withNativeWind, withPersistentCache, withRouteEndpoint, withTransformLogger, withWasmSupport, withWorkspaceNodeModules };
476
+ export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type PersistentCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoCalendarStub, withExpoCameraRecordStub, withExpoContactsStub, withExpoFileSystemStub, withExpoHapticsStub, withExpoImagePickerStub, withExpoMediaLibraryStub, withExpoNotificationsStub, withLucideResolver, withNativeWind, withPersistentCache, withRouteEndpoint, withTransformLogger, withWasmSupport, withWorkspaceNodeModules };
package/dist/metro.d.ts CHANGED
@@ -111,7 +111,7 @@ declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOp
111
111
  * withDevkit — 一站式 Metro 配置入口
112
112
  *
113
113
  * 按固定顺序依次应用:
114
- * withPersistentCache — 将 Metro transform cache 固定到项目目录(.metro-cache/),重启不丢失
114
+ * withPersistentCache — 将 Metro transform cache 固定到持久目录(优先读取 METRO_CACHE_DIR 环境变量),重启不丢失
115
115
  * withWorkspaceNodeModules — 修复沙箱中 node_modules 位于祖先目录时的模块解析问题
116
116
  * withWasmSupport — 将 .wasm 加入 assetExts,修复 expo-sqlite web worker 打包失败
117
117
  * withCssInterop — 为 expo-image / expo-camera 等注入 NativeWind cssInterop
@@ -339,6 +339,18 @@ declare function withExpoFileSystemStub(config: MetroConfig): MetroConfig;
339
339
 
340
340
  declare function withExpoImagePickerStub(config: MetroConfig): MetroConfig;
341
341
 
342
+ /**
343
+ * withExpoCameraRecordStub — Web 平台为 expo-camera 注入 recordAsync 支持
344
+ *
345
+ * expo-camera 的 recordAsync / stopRecording 在 Web 端未实现。
346
+ * 此 wrapper 仅在 web 平台拦截 expo-camera,注入使用 MediaRecorder API 的 stub,
347
+ * 输出 video/mp4 格式,返回 blob: URI,与原生侧返回值结构一致。
348
+ *
349
+ * Native 端不拦截,原生实现完全正常。
350
+ */
351
+
352
+ declare function withExpoCameraRecordStub(config: MetroConfig): MetroConfig;
353
+
342
354
  /**
343
355
  * withExpoHapticsStub — Web 平台将 expo-haptics 替换为 stub
344
356
  *
@@ -435,11 +447,16 @@ declare function withWasmSupport(config: MetroConfig): MetroConfig;
435
447
  declare function withTransformLogger(config: MetroConfig): MetroConfig;
436
448
 
437
449
  /**
438
- * withPersistentCache — 将 Metro transform cache 固定到项目目录
450
+ * withPersistentCache — 将 Metro transform cache 固定到可持久化目录
439
451
  *
440
452
  * Metro 默认将 transform cache 写入系统临时目录(os.tmpdir()/metro-cache),
441
453
  * 系统随时可以清理,导致每次重启都是冷启动。
442
- * 此 wrapper 将 cacheStores 替换为项目根目录下的 .metro-cache/,持久保留。
454
+ * 此 wrapper 将 cacheStores 替换为指定目录,持久保留。
455
+ *
456
+ * 缓存路径解析优先级(高到低):
457
+ * 1. 环境变量 METRO_CACHE_DIR(绝对路径,适用于容器/CI 挂载外部持久目录)
458
+ * 2. options.cacheDir(绝对路径直接使用;相对路径拼接到 projectRoot)
459
+ * 3. 默认值:projectRoot/.metro-cache
443
460
  *
444
461
  * cache key 由文件内容 sha1 + 相对路径 + Babel/Metro 版本共同决定,
445
462
  * 与项目绝对路径无关,换目录 clone 后缓存同样有效。
@@ -447,10 +464,13 @@ declare function withTransformLogger(config: MetroConfig): MetroConfig;
447
464
 
448
465
  interface PersistentCacheOptions {
449
466
  /**
450
- * cache 目录,相对于 projectRoot。默认:'.metro-cache'
467
+ * cache 目录。
468
+ * - 绝对路径:直接使用(适合挂载外部持久目录)
469
+ * - 相对路径:拼接到 projectRoot
470
+ * - 省略:使用环境变量 METRO_CACHE_DIR,否则默认 '.metro-cache'(相对 projectRoot)
451
471
  */
452
472
  cacheDir?: string;
453
473
  }
454
474
  declare function withPersistentCache(config: MetroConfig, options?: PersistentCacheOptions): MetroConfig;
455
475
 
456
- export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type PersistentCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoCalendarStub, withExpoContactsStub, withExpoFileSystemStub, withExpoHapticsStub, withExpoImagePickerStub, withExpoMediaLibraryStub, withExpoNotificationsStub, withLucideResolver, withNativeWind, withPersistentCache, withRouteEndpoint, withTransformLogger, withWasmSupport, withWorkspaceNodeModules };
476
+ export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type PersistentCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoCalendarStub, withExpoCameraRecordStub, withExpoContactsStub, withExpoFileSystemStub, withExpoHapticsStub, withExpoImagePickerStub, withExpoMediaLibraryStub, withExpoNotificationsStub, withLucideResolver, withNativeWind, withPersistentCache, withRouteEndpoint, withTransformLogger, withWasmSupport, withWorkspaceNodeModules };
package/dist/metro.js CHANGED
@@ -37,6 +37,7 @@ __export(metro_exports, {
37
37
  withEntryInjection: () => withEntryInjection,
38
38
  withEsbuildMinify: () => withEsbuildMinify,
39
39
  withExpoCalendarStub: () => withExpoCalendarStub,
40
+ withExpoCameraRecordStub: () => withExpoCameraRecordStub,
40
41
  withExpoContactsStub: () => withExpoContactsStub,
41
42
  withExpoFileSystemStub: () => withExpoFileSystemStub,
42
43
  withExpoHapticsStub: () => withExpoHapticsStub,
@@ -270,6 +271,7 @@ var EXPO_IMAGE_STUB_FILENAME = "expo-image-stub.js";
270
271
  var EXPO_IMAGE_STUB_PATH = import_path6.default.resolve(__dirname, "stubs", EXPO_IMAGE_STUB_FILENAME);
271
272
  var EXPO_CAMERA_STUB_FILENAME = "expo-camera-stub.js";
272
273
  var EXPO_CAMERA_STUB_PATH = import_path6.default.resolve(__dirname, "stubs", EXPO_CAMERA_STUB_FILENAME);
274
+ var EXPO_CAMERA_RECORD_STUB_FILENAME = "expo-camera-record-stub.js";
273
275
  var EXPO_LINEAR_GRADIENT_STUB_FILENAME = "expo-linear-gradient-stub.js";
274
276
  var EXPO_LINEAR_GRADIENT_STUB_PATH = import_path6.default.resolve(__dirname, "stubs", EXPO_LINEAR_GRADIENT_STUB_FILENAME);
275
277
  var EXPO_BLUR_STUB_FILENAME = "expo-blur-stub.js";
@@ -280,7 +282,7 @@ function withCssInterop(config) {
280
282
  if (moduleName === "expo-image" && !context.originModulePath.includes(EXPO_IMAGE_STUB_FILENAME)) {
281
283
  return { filePath: EXPO_IMAGE_STUB_PATH, type: "sourceFile" };
282
284
  }
283
- if (moduleName === "expo-camera" && !context.originModulePath.includes(EXPO_CAMERA_STUB_FILENAME)) {
285
+ if (moduleName === "expo-camera" && !context.originModulePath.includes(EXPO_CAMERA_STUB_FILENAME) && !context.originModulePath.includes(EXPO_CAMERA_RECORD_STUB_FILENAME)) {
284
286
  return { filePath: EXPO_CAMERA_STUB_PATH, type: "sourceFile" };
285
287
  }
286
288
  if (moduleName === "expo-linear-gradient" && !context.originModulePath.includes(EXPO_LINEAR_GRADIENT_STUB_FILENAME)) {
@@ -304,7 +306,7 @@ function withCssInterop(config) {
304
306
  }
305
307
 
306
308
  // src/metro/withDevkit.ts
307
- var import_path14 = __toESM(require("path"));
309
+ var import_path15 = __toESM(require("path"));
308
310
 
309
311
  // src/metro/withEsbuildMinify.ts
310
312
  function withEsbuildMinify(config) {
@@ -464,6 +466,27 @@ function withExpoImagePickerStub(config) {
464
466
  return { ...config, resolver: { ...config.resolver, resolveRequest } };
465
467
  }
466
468
 
469
+ // src/metro/withExpoCameraRecordStub.ts
470
+ var import_path13 = __toESM(require("path"));
471
+ var EXPO_CAMERA_RECORD_STUB_FILENAME2 = "expo-camera-record-stub.js";
472
+ var EXPO_CAMERA_RECORD_STUB_PATH = import_path13.default.resolve(
473
+ __dirname,
474
+ "stubs",
475
+ EXPO_CAMERA_RECORD_STUB_FILENAME2
476
+ );
477
+ var EXPO_CAMERA_CSSINTEROP_STUB_FILENAME = "expo-camera-stub.js";
478
+ function withExpoCameraRecordStub(config) {
479
+ const upstream = config.resolver?.resolveRequest ?? null;
480
+ const resolveRequest = (context, moduleName, platform) => {
481
+ if (platform === "web" && moduleName === "expo-camera" && !context.originModulePath.includes(EXPO_CAMERA_RECORD_STUB_FILENAME2) && !context.originModulePath.includes(EXPO_CAMERA_CSSINTEROP_STUB_FILENAME)) {
482
+ return { filePath: EXPO_CAMERA_RECORD_STUB_PATH, type: "sourceFile" };
483
+ }
484
+ if (upstream) return upstream(context, moduleName, platform);
485
+ return context.resolveRequest(context, moduleName, platform);
486
+ };
487
+ return { ...config, resolver: { ...config.resolver, resolveRequest } };
488
+ }
489
+
467
490
  // src/metro/withWasmSupport.ts
468
491
  function withWasmSupport(config) {
469
492
  const existing = config.resolver?.assetExts ?? [];
@@ -557,12 +580,20 @@ function withTransformLogger(config) {
557
580
  }
558
581
 
559
582
  // src/metro/withPersistentCache.ts
560
- var import_path13 = __toESM(require("path"));
583
+ var import_path14 = __toESM(require("path"));
561
584
  var import_metro_cache = require("metro-cache");
562
585
  function withPersistentCache(config, options = {}) {
563
586
  const projectRoot = config.projectRoot ?? process.cwd();
564
- const { cacheDir = ".metro-cache" } = options;
565
- const cacheRoot = import_path13.default.join(projectRoot, cacheDir);
587
+ const { cacheDir } = options;
588
+ const envCacheDir = process.env["METRO_CACHE_DIR"];
589
+ let cacheRoot;
590
+ if (envCacheDir) {
591
+ cacheRoot = envCacheDir;
592
+ } else if (cacheDir) {
593
+ cacheRoot = import_path14.default.isAbsolute(cacheDir) ? cacheDir : import_path14.default.join(projectRoot, cacheDir);
594
+ } else {
595
+ cacheRoot = import_path14.default.join(projectRoot, ".metro-cache");
596
+ }
566
597
  const existingStores = config.cacheStores;
567
598
  const firstStore = Array.isArray(existingStores) ? existingStores[0] : void 0;
568
599
  const StoreClass = firstStore ? Object.getPrototypeOf(firstStore).constructor : import_metro_cache.FileStore;
@@ -588,18 +619,19 @@ function withDevkit(config, options = {}) {
588
619
  config = withExpoCalendarStub(config);
589
620
  config = withExpoFileSystemStub(config);
590
621
  config = withExpoImagePickerStub(config);
622
+ config = withExpoCameraRecordStub(config);
591
623
  if (typeof __DEV__ !== "undefined" && __DEV__) {
592
624
  config = withEntryInjection(config);
593
625
  config = withDevStubs(config);
594
- config = withRouteEndpoint(config, { appDir: import_path14.default.join(projectRoot, "src", "app") });
626
+ config = withRouteEndpoint(config, { appDir: import_path15.default.join(projectRoot, "src", "app") });
595
627
  }
596
628
  return withNativeWind(config, { input, inlineRem: 16 });
597
629
  }
598
630
 
599
631
  // src/metro/withExpoHapticsStub.ts
600
- var import_path15 = __toESM(require("path"));
632
+ var import_path16 = __toESM(require("path"));
601
633
  var EXPO_HAPTICS_STUB_FILENAME = "expo-haptics-stub.js";
602
- var EXPO_HAPTICS_STUB_PATH = import_path15.default.resolve(__dirname, "stubs", EXPO_HAPTICS_STUB_FILENAME);
634
+ var EXPO_HAPTICS_STUB_PATH = import_path16.default.resolve(__dirname, "stubs", EXPO_HAPTICS_STUB_FILENAME);
603
635
  function withExpoHapticsStub(config) {
604
636
  const upstream = config.resolver?.resolveRequest ?? null;
605
637
  const resolveRequest = (context, moduleName, platform) => {
@@ -613,9 +645,9 @@ function withExpoHapticsStub(config) {
613
645
  }
614
646
 
615
647
  // src/metro/withExpoContactsStub.ts
616
- var import_path16 = __toESM(require("path"));
648
+ var import_path17 = __toESM(require("path"));
617
649
  var EXPO_CONTACTS_STUB_FILENAME = "expo-contacts-stub.js";
618
- var EXPO_CONTACTS_STUB_PATH = import_path16.default.resolve(
650
+ var EXPO_CONTACTS_STUB_PATH = import_path17.default.resolve(
619
651
  __dirname,
620
652
  "stubs",
621
653
  EXPO_CONTACTS_STUB_FILENAME
@@ -648,6 +680,7 @@ try {
648
680
  withEntryInjection,
649
681
  withEsbuildMinify,
650
682
  withExpoCalendarStub,
683
+ withExpoCameraRecordStub,
651
684
  withExpoContactsStub,
652
685
  withExpoFileSystemStub,
653
686
  withExpoHapticsStub,
package/dist/metro.mjs CHANGED
@@ -222,6 +222,7 @@ var EXPO_IMAGE_STUB_FILENAME = "expo-image-stub.js";
222
222
  var EXPO_IMAGE_STUB_PATH = path6.resolve(__dirname, "stubs", EXPO_IMAGE_STUB_FILENAME);
223
223
  var EXPO_CAMERA_STUB_FILENAME = "expo-camera-stub.js";
224
224
  var EXPO_CAMERA_STUB_PATH = path6.resolve(__dirname, "stubs", EXPO_CAMERA_STUB_FILENAME);
225
+ var EXPO_CAMERA_RECORD_STUB_FILENAME = "expo-camera-record-stub.js";
225
226
  var EXPO_LINEAR_GRADIENT_STUB_FILENAME = "expo-linear-gradient-stub.js";
226
227
  var EXPO_LINEAR_GRADIENT_STUB_PATH = path6.resolve(__dirname, "stubs", EXPO_LINEAR_GRADIENT_STUB_FILENAME);
227
228
  var EXPO_BLUR_STUB_FILENAME = "expo-blur-stub.js";
@@ -232,7 +233,7 @@ function withCssInterop(config) {
232
233
  if (moduleName === "expo-image" && !context.originModulePath.includes(EXPO_IMAGE_STUB_FILENAME)) {
233
234
  return { filePath: EXPO_IMAGE_STUB_PATH, type: "sourceFile" };
234
235
  }
235
- if (moduleName === "expo-camera" && !context.originModulePath.includes(EXPO_CAMERA_STUB_FILENAME)) {
236
+ if (moduleName === "expo-camera" && !context.originModulePath.includes(EXPO_CAMERA_STUB_FILENAME) && !context.originModulePath.includes(EXPO_CAMERA_RECORD_STUB_FILENAME)) {
236
237
  return { filePath: EXPO_CAMERA_STUB_PATH, type: "sourceFile" };
237
238
  }
238
239
  if (moduleName === "expo-linear-gradient" && !context.originModulePath.includes(EXPO_LINEAR_GRADIENT_STUB_FILENAME)) {
@@ -256,7 +257,7 @@ function withCssInterop(config) {
256
257
  }
257
258
 
258
259
  // src/metro/withDevkit.ts
259
- import path15 from "path";
260
+ import path16 from "path";
260
261
 
261
262
  // src/metro/withEsbuildMinify.ts
262
263
  function withEsbuildMinify(config) {
@@ -416,6 +417,27 @@ function withExpoImagePickerStub(config) {
416
417
  return { ...config, resolver: { ...config.resolver, resolveRequest } };
417
418
  }
418
419
 
420
+ // src/metro/withExpoCameraRecordStub.ts
421
+ import path13 from "path";
422
+ var EXPO_CAMERA_RECORD_STUB_FILENAME2 = "expo-camera-record-stub.js";
423
+ var EXPO_CAMERA_RECORD_STUB_PATH = path13.resolve(
424
+ __dirname,
425
+ "stubs",
426
+ EXPO_CAMERA_RECORD_STUB_FILENAME2
427
+ );
428
+ var EXPO_CAMERA_CSSINTEROP_STUB_FILENAME = "expo-camera-stub.js";
429
+ function withExpoCameraRecordStub(config) {
430
+ const upstream = config.resolver?.resolveRequest ?? null;
431
+ const resolveRequest = (context, moduleName, platform) => {
432
+ if (platform === "web" && moduleName === "expo-camera" && !context.originModulePath.includes(EXPO_CAMERA_RECORD_STUB_FILENAME2) && !context.originModulePath.includes(EXPO_CAMERA_CSSINTEROP_STUB_FILENAME)) {
433
+ return { filePath: EXPO_CAMERA_RECORD_STUB_PATH, type: "sourceFile" };
434
+ }
435
+ if (upstream) return upstream(context, moduleName, platform);
436
+ return context.resolveRequest(context, moduleName, platform);
437
+ };
438
+ return { ...config, resolver: { ...config.resolver, resolveRequest } };
439
+ }
440
+
419
441
  // src/metro/withWasmSupport.ts
420
442
  function withWasmSupport(config) {
421
443
  const existing = config.resolver?.assetExts ?? [];
@@ -431,10 +453,10 @@ function withWasmSupport(config) {
431
453
 
432
454
  // src/metro/withTransformLogger.ts
433
455
  import fs4 from "fs";
434
- import path13 from "path";
456
+ import path14 from "path";
435
457
  import { Logger } from "metro-core";
436
458
  function installPerfLogger(logFile, existingFactory) {
437
- const dir = path13.dirname(logFile);
459
+ const dir = path14.dirname(logFile);
438
460
  if (!fs4.existsSync(dir)) {
439
461
  fs4.mkdirSync(dir, { recursive: true });
440
462
  }
@@ -509,12 +531,20 @@ function withTransformLogger(config) {
509
531
  }
510
532
 
511
533
  // src/metro/withPersistentCache.ts
512
- import path14 from "path";
534
+ import path15 from "path";
513
535
  import { FileStore } from "metro-cache";
514
536
  function withPersistentCache(config, options = {}) {
515
537
  const projectRoot = config.projectRoot ?? process.cwd();
516
- const { cacheDir = ".metro-cache" } = options;
517
- const cacheRoot = path14.join(projectRoot, cacheDir);
538
+ const { cacheDir } = options;
539
+ const envCacheDir = process.env["METRO_CACHE_DIR"];
540
+ let cacheRoot;
541
+ if (envCacheDir) {
542
+ cacheRoot = envCacheDir;
543
+ } else if (cacheDir) {
544
+ cacheRoot = path15.isAbsolute(cacheDir) ? cacheDir : path15.join(projectRoot, cacheDir);
545
+ } else {
546
+ cacheRoot = path15.join(projectRoot, ".metro-cache");
547
+ }
518
548
  const existingStores = config.cacheStores;
519
549
  const firstStore = Array.isArray(existingStores) ? existingStores[0] : void 0;
520
550
  const StoreClass = firstStore ? Object.getPrototypeOf(firstStore).constructor : FileStore;
@@ -540,18 +570,19 @@ function withDevkit(config, options = {}) {
540
570
  config = withExpoCalendarStub(config);
541
571
  config = withExpoFileSystemStub(config);
542
572
  config = withExpoImagePickerStub(config);
573
+ config = withExpoCameraRecordStub(config);
543
574
  if (typeof __DEV__ !== "undefined" && __DEV__) {
544
575
  config = withEntryInjection(config);
545
576
  config = withDevStubs(config);
546
- config = withRouteEndpoint(config, { appDir: path15.join(projectRoot, "src", "app") });
577
+ config = withRouteEndpoint(config, { appDir: path16.join(projectRoot, "src", "app") });
547
578
  }
548
579
  return withNativeWind(config, { input, inlineRem: 16 });
549
580
  }
550
581
 
551
582
  // src/metro/withExpoHapticsStub.ts
552
- import path16 from "path";
583
+ import path17 from "path";
553
584
  var EXPO_HAPTICS_STUB_FILENAME = "expo-haptics-stub.js";
554
- var EXPO_HAPTICS_STUB_PATH = path16.resolve(__dirname, "stubs", EXPO_HAPTICS_STUB_FILENAME);
585
+ var EXPO_HAPTICS_STUB_PATH = path17.resolve(__dirname, "stubs", EXPO_HAPTICS_STUB_FILENAME);
555
586
  function withExpoHapticsStub(config) {
556
587
  const upstream = config.resolver?.resolveRequest ?? null;
557
588
  const resolveRequest = (context, moduleName, platform) => {
@@ -565,9 +596,9 @@ function withExpoHapticsStub(config) {
565
596
  }
566
597
 
567
598
  // src/metro/withExpoContactsStub.ts
568
- import path17 from "path";
599
+ import path18 from "path";
569
600
  var EXPO_CONTACTS_STUB_FILENAME = "expo-contacts-stub.js";
570
- var EXPO_CONTACTS_STUB_PATH = path17.resolve(
601
+ var EXPO_CONTACTS_STUB_PATH = path18.resolve(
571
602
  __dirname,
572
603
  "stubs",
573
604
  EXPO_CONTACTS_STUB_FILENAME
@@ -599,6 +630,7 @@ export {
599
630
  withEntryInjection,
600
631
  withEsbuildMinify,
601
632
  withExpoCalendarStub,
633
+ withExpoCameraRecordStub,
602
634
  withExpoContactsStub,
603
635
  withExpoFileSystemStub,
604
636
  withExpoHapticsStub,
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var import_react = __toESM(require("react"));
25
+ var import_nativewind = require("nativewind");
26
+ const ExpoCamera = require("expo-camera");
27
+ const OriginalCameraView = ExpoCamera.CameraView;
28
+ const MIME_TYPE = "video/mp4;codecs=avc1";
29
+ class WebRecordableCameraView extends OriginalCameraView {
30
+ constructor() {
31
+ super(...arguments);
32
+ this._recorder = null;
33
+ this._maxDurationTimer = null;
34
+ this._audioTracks = [];
35
+ this._containerRef = null;
36
+ }
37
+ render() {
38
+ const original = super.render();
39
+ return import_react.default.createElement(
40
+ "div",
41
+ {
42
+ ref: (el) => {
43
+ this._containerRef = el;
44
+ },
45
+ style: { display: "contents" }
46
+ },
47
+ original
48
+ );
49
+ }
50
+ async recordAsync(options) {
51
+ if (this._recorder && this._recorder.state !== "inactive") {
52
+ this._recorder.stop();
53
+ }
54
+ const videoEl = this._findVideoElement();
55
+ if (!videoEl) {
56
+ throw new Error("[expo-camera-record-stub] Cannot find <video> element for recording.");
57
+ }
58
+ const stream = videoEl.srcObject;
59
+ if (!stream) {
60
+ throw new Error("[expo-camera-record-stub] No MediaStream on video element.");
61
+ }
62
+ if (!MediaRecorder.isTypeSupported(MIME_TYPE)) {
63
+ throw new Error(
64
+ "[expo-camera-record-stub] Browser does not support MediaRecorder with " + MIME_TYPE + ". This stub requires Chrome 116+ or Safari 14.1+."
65
+ );
66
+ }
67
+ let recordStream = stream;
68
+ this._audioTracks = [];
69
+ if (options?.mute !== true) {
70
+ try {
71
+ const audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
72
+ this._audioTracks = audioStream.getAudioTracks();
73
+ const combinedTracks = [...stream.getVideoTracks(), ...this._audioTracks];
74
+ recordStream = new MediaStream(combinedTracks);
75
+ } catch {
76
+ }
77
+ }
78
+ const recorder = new MediaRecorder(recordStream, { mimeType: MIME_TYPE });
79
+ this._recorder = recorder;
80
+ const localChunks = [];
81
+ recorder.ondataavailable = (e) => {
82
+ if (e.data && e.data.size > 0) {
83
+ localChunks.push(e.data);
84
+ }
85
+ };
86
+ const recordingPromise = new Promise((resolve, reject) => {
87
+ recorder.onstop = () => {
88
+ if (this._recorder === recorder) {
89
+ this._cleanupTimer();
90
+ this._recorder = null;
91
+ }
92
+ this._stopAudioTracks();
93
+ const blob = new Blob(localChunks, { type: "video/mp4" });
94
+ const uri = URL.createObjectURL(blob);
95
+ resolve({ uri });
96
+ };
97
+ recorder.onerror = (event) => {
98
+ if (this._recorder === recorder) {
99
+ this._cleanupTimer();
100
+ this._recorder = null;
101
+ }
102
+ this._stopAudioTracks();
103
+ const errorEvent = event;
104
+ reject(new Error(
105
+ "[expo-camera-record-stub] Recording failed: " + (errorEvent.message || "Unknown error")
106
+ ));
107
+ };
108
+ });
109
+ recorder.start();
110
+ if (options?.maxDuration) {
111
+ this._maxDurationTimer = setTimeout(() => {
112
+ this.stopRecording();
113
+ }, options.maxDuration * 1e3);
114
+ }
115
+ return recordingPromise;
116
+ }
117
+ stopRecording() {
118
+ if (this._recorder && this._recorder.state !== "inactive") {
119
+ this._recorder.stop();
120
+ }
121
+ }
122
+ _cleanupTimer() {
123
+ if (this._maxDurationTimer) {
124
+ clearTimeout(this._maxDurationTimer);
125
+ this._maxDurationTimer = null;
126
+ }
127
+ }
128
+ _stopAudioTracks() {
129
+ for (const track of this._audioTracks) {
130
+ track.stop();
131
+ }
132
+ this._audioTracks = [];
133
+ }
134
+ _findVideoElement() {
135
+ return this._containerRef?.querySelector("video") ?? null;
136
+ }
137
+ }
138
+ (0, import_nativewind.cssInterop)(WebRecordableCameraView, { className: "style" });
139
+ module.exports = {
140
+ ...ExpoCamera,
141
+ CameraView: WebRecordableCameraView
142
+ };
143
+ //# sourceMappingURL=expo-camera-record-stub.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-expo-devkit",
3
- "version": "0.1.1-beta.64",
3
+ "version": "0.1.1-beta.69",
4
4
  "description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",