@absolutejs/absolute 0.20.0-beta.91 → 0.20.0-beta.93

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 (38) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/changelog.json +41 -0
  3. package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
  4. package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
  5. package/dist/build/buildWorker.js +10 -1
  6. package/dist/build.js +16 -7
  7. package/dist/build.js.map +9 -8
  8. package/dist/cli/{compile-5hchbcbd.js → compile-wkfd88w7.js} +5 -5
  9. package/dist/cli/{dev-aykeaa7b.js → dev-01zcxngn.js} +83 -11
  10. package/dist/cli/{expoDevController-tr63cg78.js → expoDevController-k15hftqn.js} +25 -1
  11. package/dist/cli/expoNativeWatcher-rmc95bak.js +138 -0
  12. package/dist/cli/{expoProject-dac8fqhq.js → expoProject-mmm3s62b.js} +1 -1
  13. package/dist/cli/{index-fn44wefq.js → index-3sdvzrv2.js} +37 -28
  14. package/dist/cli/index-bw4ktfnz.js +11 -0
  15. package/dist/cli/{index-jqdt7841.js → index-kh44yx23.js} +1 -1
  16. package/dist/cli/{index-39j0dhq7.js → index-v5knwk7v.js} +1 -1
  17. package/dist/cli/{index-tame6e2c.js → index-wqhbxtyp.js} +49 -12
  18. package/dist/cli/index.js +5 -5
  19. package/dist/cli/{mobile-bg1jy34n.js → mobile-pbe1a667.js} +20 -12
  20. package/dist/cli/{remoteMacProtocol-vw931n0a.js → remoteMacProtocol-kqvkp0qd.js} +2 -1
  21. package/dist/cli/{start-7jg0csqy.js → start-dw5crgp7.js} +3 -3
  22. package/dist/dev/client/handlers/svelte.ts +11 -15
  23. package/dist/dev/serverBootstrap.js +10 -1
  24. package/dist/index.js +17 -8
  25. package/dist/index.js.map +11 -10
  26. package/dist/mobile/index.js +371 -162
  27. package/dist/mobile/index.js.map +10 -8
  28. package/dist/mobile/mobilePreviewClient.ts +1 -1
  29. package/dist/mobile/remoteMacAgentEntry.js +105 -68
  30. package/dist/src/dev/clientManager.d.ts +2 -2
  31. package/dist/src/mobile/androidConformance.d.ts +4 -1
  32. package/dist/src/mobile/expoDevController.d.ts +2 -6
  33. package/dist/src/mobile/expoNativeObservability.d.ts +1 -1
  34. package/dist/src/mobile/expoNativeWatcher.d.ts +21 -0
  35. package/dist/src/mobile/index.d.ts +1 -0
  36. package/dist/src/mobile/remoteMacProtocol.d.ts +1 -4
  37. package/dist/src/utils/unrefTimer.d.ts +5 -0
  38. package/package.json +5 -2
@@ -17,10 +17,10 @@ export type HMRState = {
17
17
  dependencyGraph: DependencyGraph;
18
18
  isRebuilding: boolean;
19
19
  rebuildQueue: Set<string>;
20
- rebuildTimeout: NodeJS.Timeout | null;
20
+ rebuildTimeout: ReturnType<typeof setTimeout> | null;
21
21
  pendingBundleRebuilds: Set<'angular' | 'svelte' | 'vue'>;
22
22
  fileChangeQueue: Map<string, string[]>;
23
- debounceTimeout: NodeJS.Timeout | null;
23
+ debounceTimeout: ReturnType<typeof setTimeout> | null;
24
24
  fileHashes: Map<string, number>;
25
25
  watchers: FSWatcher[];
26
26
  moduleVersions: ModuleVersions;
@@ -19,11 +19,13 @@ export type AbsoluteAndroidRouteCheck = {
19
19
  title: string;
20
20
  url: string;
21
21
  };
22
- export declare const absoluteAndroidDevelopmentUrl: (port: number, route: string, https?: boolean) => string;
22
+ export declare const absoluteAndroidDevelopmentUrl: (port: number, route: string, https?: boolean, target?: Extract<HMRClientTarget, `${string}-android`>) => string;
23
23
  export declare const inspectAbsoluteAndroidRoute: (session: AbsoluteAndroidWebViewSession, options: {
24
24
  https?: boolean;
25
+ navigation?: "devtools" | "in-page" | "none";
25
26
  port: number;
26
27
  route: string;
28
+ target?: Extract<HMRClientTarget, `${string}-android`>;
27
29
  timeoutMs?: number;
28
30
  }) => Promise<{
29
31
  route: string;
@@ -38,5 +40,6 @@ export declare const inspectAbsoluteAndroidRoute: (session: AbsoluteAndroidWebVi
38
40
  export declare const waitForAbsoluteAndroidHmrApply: (session: AbsoluteAndroidWebViewSession, options: {
39
41
  afterUpdateId?: number;
40
42
  kind?: HMRApplyKind;
43
+ target?: Extract<HMRClientTarget, `${string}-android`>;
41
44
  timeoutMs?: number;
42
45
  }) => Promise<AbsoluteAndroidHmrApply>;
@@ -52,6 +52,7 @@ export type AbsoluteExpoDevSession = {
52
52
  close: () => Promise<void>;
53
53
  metroPort: number;
54
54
  platforms: AbsoluteExpoDevPlatform[];
55
+ rebuild: () => Promise<AbsoluteExpoDevSession>;
55
56
  timings: Partial<Record<AbsoluteExpoDevState, number>>;
56
57
  };
57
58
  export type InstallAbsoluteExpoAndroidReleaseOptions = {
@@ -96,9 +97,4 @@ export declare const planAbsoluteExpoDevSession: (config: NormalizedAbsoluteMobi
96
97
  export declare const installAbsoluteExpoAndroidRelease: (options: InstallAbsoluteExpoAndroidReleaseOptions) => Promise<AbsoluteExpoAndroidReleaseInstallation>;
97
98
  export declare const installAbsoluteExpoIosRelease: (options: InstallAbsoluteExpoIosReleaseOptions) => Promise<AbsoluteExpoIosReleaseInstallation>;
98
99
  export declare const parseBootedAbsoluteExpoIosSimulators: (source: string) => string[];
99
- export declare const startAbsoluteExpoDevSession: (options: StartAbsoluteExpoDevOptions) => Promise<{
100
- metroPort: number;
101
- platforms: AbsoluteExpoDevPlatform[];
102
- timings: Partial<Record<AbsoluteExpoDevState, number>>;
103
- close: () => Promise<void>;
104
- }>;
100
+ export declare const startAbsoluteExpoDevSession: (options: StartAbsoluteExpoDevOptions) => Promise<AbsoluteExpoDevSession>;
@@ -1,3 +1,3 @@
1
- export declare const expoNativeObservabilityRuntimeSource = "// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.\nimport { requireNativeModule } from 'expo';\nimport { AppState, Platform } from 'react-native';\nimport { ABSOLUTE_MOBILE_MANIFEST } from './webAssets';\n\ntype NativeObservabilityModule = {\n\tacknowledge(options: { ids: string[] }): Promise<void>;\n\tcrashForTesting(options: { testId: string }): Promise<boolean>;\n\tpending(): Promise<{ reports: unknown[] }>;\n};\ntype NativeReport = { details: Record<string, unknown>; id: string; kind: string; occurredAt: number; platform: 'android' | 'ios' };\nconst native = requireNativeModule<NativeObservabilityModule>('AbsoluteMobileObservability');\nconst KINDS = new Set(['anr', 'app-launch', 'cpu-exception', 'crash', 'disk-write-exception', 'hang', 'initialization-failure', 'low-memory', 'native-crash', 'resource-exhaustion', 'signal']);\nconst ID = /^[A-Za-z0-9._:-]{1,128}$/;\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null && !Array.isArray(value);\nconst redactText = (value: string) => value.slice(0, 8192)\n\t.replace(/\\b(Bearer)\\s+[A-Za-z0-9._~+/-]+=*/gi, '$1 [REDACTED]')\n\t.replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\\s]*/gi, '$1[REDACTED]')\n\t.replace(/\\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\\s*[:=]\\s*)[^,\\s;]+/gi, '$1[REDACTED]')\n\t.replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g, '[REDACTED]');\nconst redact = (value: unknown, depth = 0): unknown => {\n\tif (depth >= 8) return '[TRUNCATED]';\n\tif (typeof value === 'string') return redactText(value);\n\tif (value === null || typeof value === 'number' || typeof value === 'boolean') return value;\n\tif (Array.isArray(value)) return value.slice(0, 64).map(entry => redact(entry, depth + 1));\n\tif (!isRecord(value)) return String(value).slice(0, 8192);\n\treturn Object.fromEntries(Object.entries(value).slice(0, 128).map(([key, entry]) => [key, /(?:authorization|cookie|password|secret|token)/i.test(key) ? '[REDACTED]' : redact(entry, depth + 1)]));\n};\nconst parse = (value: unknown): NativeReport | undefined => {\n\tif (!isRecord(value) || !isRecord(value.details) || typeof value.id !== 'string' || !ID.test(value.id) || typeof value.kind !== 'string' || !KINDS.has(value.kind) || typeof value.occurredAt !== 'number' || !Number.isFinite(value.occurredAt) || value.occurredAt <= 0 || value.platform !== 'android' && value.platform !== 'ios') return;\n\tconst details = redact(value.details);\n\tif (!isRecord(details) || new TextEncoder().encode(JSON.stringify(details)).byteLength > 64 * 1024) return;\n\treturn { details, id: value.id, kind: value.kind, occurredAt: value.occurredAt, platform: value.platform };\n};\nconst sampled = (id: string, rate: number) => {\n\tif (rate >= 1) return true;\n\tlet hash = 2166136261;\n\tfor (const character of id) { hash ^= character.codePointAt(0) ?? 0; hash = Math.imul(hash, 16777619); }\n\treturn (hash >>> 0) / 4294967296 < rate;\n};\nlet drainPromise: Promise<void> | undefined;\nlet started = false;\nconst drain = () => {\n\tdrainPromise ??= (async () => {\n\t\tconst manifest = ABSOLUTE_MOBILE_MANIFEST;\n\t\tconst config = manifest?.observability;\n\t\tif (!manifest || !config || Platform.OS !== 'android' && Platform.OS !== 'ios') return;\n\t\tconst reports = (await native.pending()).reports.slice(0, 8).map(parse).filter((report): report is NativeReport => report !== undefined);\n\t\tconst discarded = reports.filter(report => !sampled(report.id, config.sampleRate));\n\t\tif (discarded.length) await native.acknowledge({ ids: discarded.map(report => report.id) });\n\t\tconst selected = reports.filter(report => sampled(report.id, config.sampleRate));\n\t\tif (!selected.length) return;\n\t\tconst response = await fetch(config.endpoint, {\n\t\t\tbody: JSON.stringify({ ...(config.environment ? { environment: config.environment } : {}), events: selected.map(report => ({ at: report.occurredAt, extra: { nativeDiagnostic: report.details, nativeDiagnosticId: report.id }, groupingKey: 'absolute-native:' + report.platform + ':' + report.kind, level: ['app-launch', 'cpu-exception', 'disk-write-exception', 'low-memory', 'resource-exhaustion', 'signal'].includes(report.kind) ? 'warning' : 'error', message: 'Native process diagnostic \u2014 ' + report.kind, name: 'AbsoluteMobileNativeDiagnostic', tags: { absoluteMobile: 'true', mobileAppBuild: manifest.appBuild, mobileEngine: 'expo', mobileFailurePhase: 'native-process', mobileManifestFormat: '1', mobileNativeRuntime: 'expo', mobilePlatform: report.platform, mobileRuntime: manifest.runtime } })), project: config.project, release: manifest.appBuild, v: 1 }),\n\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\tmethod: 'POST'\n\t\t});\n\t\tif (response.ok) await native.acknowledge({ ids: selected.map(report => report.id) });\n\t})().catch(() => undefined).finally(() => { drainPromise = undefined; });\n\treturn drainPromise;\n};\nexport const startAbsoluteExpoNativeObservability = () => {\n\tif (!started) {\n\t\tstarted = true;\n\t\tAppState.addEventListener('change', state => { if (state === 'active') void drain(); });\n\t}\n\treturn drain();\n};\nexport const crashAbsoluteExpoNativeObservabilityForTesting = (testId: string) => native.crashForTesting({ testId });\n";
1
+ export declare const expoNativeObservabilityRuntimeSource = "// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.\nimport { requireNativeModule } from 'expo';\nimport { AppState, Platform } from 'react-native';\nimport { ABSOLUTE_MOBILE_MANIFEST } from './webAssets';\n\ntype NativeObservabilityModule = {\n\tacknowledge(options: { ids: string[] }): Promise<void>;\n\tcrashForTesting(options: { testId: string }): Promise<boolean>;\n\tenqueueForTesting(options: { testId: string }): Promise<boolean>;\n\tpending(): Promise<{ reports: unknown[] }>;\n};\ntype NativeReport = { details: Record<string, unknown>; id: string; kind: string; occurredAt: number; platform: 'android' | 'ios' };\nconst native = requireNativeModule<NativeObservabilityModule>('AbsoluteMobileObservability');\nconst KINDS = new Set(['anr', 'app-launch', 'cpu-exception', 'crash', 'disk-write-exception', 'hang', 'initialization-failure', 'low-memory', 'native-crash', 'resource-exhaustion', 'signal']);\nconst ID = /^[A-Za-z0-9._:-]{1,128}$/;\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null && !Array.isArray(value);\nconst redactText = (value: string) => value.slice(0, 8192)\n\t.replace(/\\b(Bearer)\\s+[A-Za-z0-9._~+/-]+=*/gi, '$1 [REDACTED]')\n\t.replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\\s]*/gi, '$1[REDACTED]')\n\t.replace(/\\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\\s*[:=]\\s*)[^,\\s;]+/gi, '$1[REDACTED]')\n\t.replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g, '[REDACTED]');\nconst redact = (value: unknown, depth = 0): unknown => {\n\tif (depth >= 8) return '[TRUNCATED]';\n\tif (typeof value === 'string') return redactText(value);\n\tif (value === null || typeof value === 'number' || typeof value === 'boolean') return value;\n\tif (Array.isArray(value)) return value.slice(0, 64).map(entry => redact(entry, depth + 1));\n\tif (!isRecord(value)) return String(value).slice(0, 8192);\n\treturn Object.fromEntries(Object.entries(value).slice(0, 128).map(([key, entry]) => [key, /(?:authorization|cookie|password|secret|token)/i.test(key) ? '[REDACTED]' : redact(entry, depth + 1)]));\n};\nconst parse = (value: unknown): NativeReport | undefined => {\n\tif (!isRecord(value) || !isRecord(value.details) || typeof value.id !== 'string' || !ID.test(value.id) || typeof value.kind !== 'string' || !KINDS.has(value.kind) || typeof value.occurredAt !== 'number' || !Number.isFinite(value.occurredAt) || value.occurredAt <= 0 || value.platform !== 'android' && value.platform !== 'ios') return;\n\tconst details = redact(value.details);\n\tif (!isRecord(details) || new TextEncoder().encode(JSON.stringify(details)).byteLength > 64 * 1024) return;\n\treturn { details, id: value.id, kind: value.kind, occurredAt: value.occurredAt, platform: value.platform };\n};\nconst sampled = (id: string, rate: number) => {\n\tif (rate >= 1) return true;\n\tlet hash = 2166136261;\n\tfor (const character of id) { hash ^= character.codePointAt(0) ?? 0; hash = Math.imul(hash, 16777619); }\n\treturn (hash >>> 0) / 4294967296 < rate;\n};\nlet drainPromise: Promise<void> | undefined;\nlet started = false;\nconst drain = () => {\n\tdrainPromise ??= (async () => {\n\t\tconst manifest = ABSOLUTE_MOBILE_MANIFEST;\n\t\tconst config = manifest?.observability;\n\t\tif (!manifest || !config || Platform.OS !== 'android' && Platform.OS !== 'ios') return;\n\t\tconst reports = (await native.pending()).reports.slice(0, 8).map(parse).filter((report): report is NativeReport => report !== undefined);\n\t\tconst discarded = reports.filter(report => !sampled(report.id, config.sampleRate));\n\t\tif (discarded.length) await native.acknowledge({ ids: discarded.map(report => report.id) });\n\t\tconst selected = reports.filter(report => sampled(report.id, config.sampleRate));\n\t\tif (!selected.length) return;\n\t\tconst response = await fetch(config.endpoint, {\n\t\t\tbody: JSON.stringify({ ...(config.environment ? { environment: config.environment } : {}), events: selected.map(report => ({ at: report.occurredAt, extra: { nativeDiagnostic: report.details, nativeDiagnosticId: report.id }, groupingKey: 'absolute-native:' + report.platform + ':' + report.kind, level: ['app-launch', 'cpu-exception', 'disk-write-exception', 'low-memory', 'resource-exhaustion', 'signal'].includes(report.kind) ? 'warning' : 'error', message: 'Native process diagnostic \u2014 ' + report.kind, name: 'AbsoluteMobileNativeDiagnostic', tags: { absoluteMobile: 'true', mobileAppBuild: manifest.appBuild, mobileEngine: 'expo', mobileFailurePhase: 'native-process', mobileManifestFormat: '1', mobileNativeRuntime: 'expo', mobilePlatform: report.platform, mobileRuntime: manifest.runtime } })), project: config.project, release: manifest.appBuild, v: 1 }),\n\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\tmethod: 'POST'\n\t\t});\n\t\tif (response.ok) await native.acknowledge({ ids: selected.map(report => report.id) });\n\t})().catch(() => undefined).finally(() => { drainPromise = undefined; });\n\treturn drainPromise;\n};\nexport const startAbsoluteExpoNativeObservability = () => {\n\tif (!started) {\n\t\tstarted = true;\n\t\tAppState.addEventListener('change', state => { if (state === 'active') void drain(); });\n\t}\n\treturn drain();\n};\nexport const crashAbsoluteExpoNativeObservabilityForTesting = (testId: string) => native.crashForTesting({ testId });\nexport const enqueueAbsoluteExpoNativeObservabilityForTesting = async (testId: string) => {\n\tawait drain();\n\tconst enqueued = await native.enqueueForTesting({ testId });\n\tawait drain();\n\treturn enqueued;\n};\n";
2
2
  export declare const absoluteExpoNativeObservabilityFiles: (project: string) => Map<string, string>;
3
3
  export declare const absoluteExpoNativeObservabilityPaths: (project: string) => string[];
@@ -0,0 +1,21 @@
1
+ export type AbsoluteExpoNativeChange = {
2
+ afterFingerprint: string;
3
+ beforeFingerprint: string;
4
+ paths: string[];
5
+ rootInputChanged: boolean;
6
+ };
7
+ export type AbsoluteExpoNativeWatcher = {
8
+ close: () => void;
9
+ };
10
+ export type AbsoluteExpoNativeWatcherOptions = {
11
+ debounceMs?: number;
12
+ expoProjectDirectory: string;
13
+ onChange: (change: AbsoluteExpoNativeChange) => Promise<void>;
14
+ onError?: (error: unknown) => void;
15
+ projectRoot: string;
16
+ signal?: AbortSignal;
17
+ };
18
+ declare const fingerprintAbsoluteExpoNativeInputs: (options: Pick<AbsoluteExpoNativeWatcherOptions, "expoProjectDirectory" | "projectRoot">) => Promise<string>;
19
+ declare const isAbsoluteExpoNativeRootInput: (path: string) => boolean;
20
+ declare const createAbsoluteExpoNativeWatcher: (options: AbsoluteExpoNativeWatcherOptions) => Promise<AbsoluteExpoNativeWatcher>;
21
+ export { createAbsoluteExpoNativeWatcher, fingerprintAbsoluteExpoNativeInputs, isAbsoluteExpoNativeRootInput };
@@ -21,6 +21,7 @@ export * from './deviceCapabilities';
21
21
  export * from './expoBridge';
22
22
  export * from './expoCodeSigning';
23
23
  export * from './expoDevController';
24
+ export * from './expoNativeWatcher';
24
25
  export * from './expoProject';
25
26
  export * from './expoNativeObservability';
26
27
  export * from './expoUpdate';
@@ -180,15 +180,12 @@ export declare const acquireAbsoluteRemoteMacReleaseLease: (project: AbsoluteRem
180
180
  staleSeconds?: number;
181
181
  transport?: Pick<AbsoluteRemoteMacTransport, "capture">;
182
182
  }) => Promise<AbsoluteRemoteMacLease>;
183
- declare const inspectAbsoluteRemoteMacWorkspace: (profile: AbsoluteRemoteMacProfile, transport?: Pick<AbsoluteRemoteMacTransport, "capture">) => Promise<AbsoluteRemoteMacWorkspaceInspection>;
184
- /** Remove only abandoned staging directories. Project dependency/native caches,
185
- * immutable releases, and active leases are deliberately retained.
186
- */
187
183
  declare const cleanAbsoluteRemoteMacWorkspace: (profile: AbsoluteRemoteMacProfile, transport?: Pick<AbsoluteRemoteMacTransport, "capture">) => Promise<{
188
184
  profile: string;
189
185
  removed: number;
190
186
  workspaceRoot: string;
191
187
  }>;
188
+ declare const inspectAbsoluteRemoteMacWorkspace: (profile: AbsoluteRemoteMacProfile, transport?: Pick<AbsoluteRemoteMacTransport, "capture">) => Promise<AbsoluteRemoteMacWorkspaceInspection>;
192
189
  export { cleanAbsoluteRemoteMacWorkspace, inspectAbsoluteRemoteMacWorkspace };
193
190
  export declare const installAbsoluteRemoteMacAgent: (project: AbsoluteRemoteIosDevProject) => Promise<{
194
191
  remotePath: string;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Detach a Bun/Node timer without assuming the DOM or server timer type wins
3
+ * in a mixed-runtime TypeScript program. Browser numeric handles are a no-op.
4
+ */
5
+ export declare const unrefTimer: (timer: unknown) => void;
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "@absolutejs/deploy": "0.25.14",
13
13
  "@absolutejs/devices": "0.7.0",
14
14
  "@absolutejs/devices-capacitor": "0.8.0",
15
- "@absolutejs/devices-expo": "0.0.2",
15
+ "@absolutejs/devices-expo": "0.0.3",
16
16
  "@absolutejs/http": "0.0.1",
17
17
  "@absolutejs/pwa": "0.14.0",
18
18
  "@capacitor/browser": "8.0.4",
@@ -472,9 +472,12 @@
472
472
  "test:native:android:observability": "ABSOLUTE_TEST_NATIVE_ANDROID=1 bun test tests/native/android-embedded-bundle-conformance.test.ts -t 'native process crash'",
473
473
  "test:native:android:updates": "ABSOLUTE_TEST_NATIVE_ANDROID=1 bun test tests/native/android-embedded-bundle-conformance.test.ts -t 'signed web updates'",
474
474
  "test:native:android:upgrade": "ABSOLUTE_TEST_NATIVE_ANDROID=1 bun test tests/native/android-embedded-bundle-conformance.test.ts -t 'installed APK upgrade'",
475
+ "test:native:expo:android:hmr": "ABSOLUTE_TEST_NATIVE_EXPO_HMR_PLATFORM=android bun test tests/native/expo-hmr-conformance.test.ts",
475
476
  "test:native:expo:android:observability": "ABSOLUTE_TEST_NATIVE_EXPO_ANDROID=1 bun test tests/native/expo-android-observability-conformance.test.ts",
476
477
  "test:native:expo:android:updates": "ABSOLUTE_TEST_NATIVE_EXPO_ANDROID_UPDATES=1 bun test tests/native/expo-android-update-conformance.test.ts",
477
478
  "test:native:expo:android:upgrade": "ABSOLUTE_TEST_NATIVE_EXPO_ANDROID_UPGRADE=1 bun test tests/native/expo-android-upgrade-conformance.test.ts",
479
+ "test:native:expo:ios:hmr": "ABSOLUTE_TEST_NATIVE_EXPO_HMR_PLATFORM=ios bun test tests/native/expo-hmr-conformance.test.ts",
480
+ "test:native:expo:ios:observability": "ABSOLUTE_TEST_NATIVE_EXPO_IOS_OBSERVABILITY=1 bun test tests/native/expo-ios-observability-conformance.test.ts",
478
481
  "test:native:expo:ios:updates": "ABSOLUTE_TEST_NATIVE_EXPO_IOS_UPDATES=1 bun test tests/native/expo-ios-update-conformance.test.ts",
479
482
  "test:native:expo:ios:upgrade": "ABSOLUTE_TEST_NATIVE_EXPO_IOS_UPGRADE=1 bun test tests/native/expo-ios-upgrade-conformance.test.ts",
480
483
  "test:native:ios": "bun run test:native:ios:lifecycle && bun run test:native:ios:bundle",
@@ -530,7 +533,7 @@
530
533
  ]
531
534
  }
532
535
  },
533
- "version": "0.20.0-beta.91",
536
+ "version": "0.20.0-beta.93",
534
537
  "workspaces": [
535
538
  "tests/fixtures/*",
536
539
  "tests/fixtures/_packages/*"