expo 54.0.0-canary-20250722-599a28f → 54.0.0-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/android/build.gradle +2 -2
  2. package/android/src/main/java/expo/modules/ExpoReactHostFactory.kt +1 -7
  3. package/android/src/main/java/expo/modules/ReactActivityDelegateWrapper.kt +8 -8
  4. package/android/src/main/java/expo/modules/ReactNativeHostWrapper.kt +0 -5
  5. package/android/src/test/resources/robolectric.properties +1 -0
  6. package/build/Expo.d.ts +9 -1
  7. package/build/Expo.d.ts.map +1 -1
  8. package/build/async-require/fetchAsync.native.d.ts.map +1 -1
  9. package/build/async-require/hmr.d.ts.map +1 -1
  10. package/build/winter/FormData.d.ts.map +1 -1
  11. package/build/winter/fetch/RequestUtils.d.ts.map +1 -1
  12. package/build/winter/fetch/convertFormData.d.ts.map +1 -1
  13. package/build/winter/installGlobal.d.ts +25 -0
  14. package/build/winter/installGlobal.d.ts.map +1 -0
  15. package/bundledNativeModules.json +94 -92
  16. package/devtools.d.ts +1 -1
  17. package/devtools.js +1 -1
  18. package/internal/babel-preset.d.ts +2 -0
  19. package/internal/babel-preset.js +2 -0
  20. package/internal/unstable-autolinking-exports.d.ts +2 -0
  21. package/internal/unstable-autolinking-exports.js +2 -0
  22. package/internal/unstable-expo-updates-cli-exports.d.ts +2 -0
  23. package/internal/unstable-expo-updates-cli-exports.js +2 -0
  24. package/ios/AppDelegates/ExpoAppDelegate.swift +1 -1
  25. package/ios/AppDelegates/ExpoReactNativeFactory.swift +2 -2
  26. package/ios/AppDelegates/ExpoReactNativeFactoryDelegate.swift +1 -1
  27. package/ios/AppDelegates/RCTAppDelegateUmbrella.h +5 -0
  28. package/ios/Fetch/ExpoFetchCustomExtension.swift +1 -1
  29. package/ios/Fetch/ExpoFetchModule.swift +3 -3
  30. package/ios/Fetch/ExpoURLSessionTask.swift +2 -2
  31. package/ios/Fetch/NativeRequest.swift +1 -1
  32. package/ios/Fetch/NativeResponse.swift +2 -2
  33. package/package.json +27 -24
  34. package/src/Expo.ts +4 -0
  35. package/src/async-require/fetchAsync.native.ts +48 -10
  36. package/src/async-require/hmr.ts +1 -2
  37. package/src/async-require/messageSocket.native.ts +0 -3
  38. package/src/winter/FormData.ts +1 -9
  39. package/src/winter/fetch/RequestUtils.ts +15 -1
  40. package/src/winter/fetch/__tests__/convertFormData-test.native.ts +1 -3
  41. package/src/winter/fetch/convertFormData.ts +56 -27
  42. package/src/winter/installGlobal.ts +109 -0
  43. package/src/winter/runtime.native.ts +1 -20
  44. package/template.tgz +0 -0
  45. package/build/devtools/DevToolsPluginClient.d.ts +0 -72
  46. package/build/devtools/DevToolsPluginClient.d.ts.map +0 -1
  47. package/build/devtools/DevToolsPluginClientFactory.d.ts +0 -16
  48. package/build/devtools/DevToolsPluginClientFactory.d.ts.map +0 -1
  49. package/build/devtools/DevToolsPluginClientImplApp.d.ts +0 -15
  50. package/build/devtools/DevToolsPluginClientImplApp.d.ts.map +0 -1
  51. package/build/devtools/DevToolsPluginClientImplBrowser.d.ts +0 -14
  52. package/build/devtools/DevToolsPluginClientImplBrowser.d.ts.map +0 -1
  53. package/build/devtools/MessageFramePacker.d.ts +0 -50
  54. package/build/devtools/MessageFramePacker.d.ts.map +0 -1
  55. package/build/devtools/ProtocolVersion.d.ts +0 -7
  56. package/build/devtools/ProtocolVersion.d.ts.map +0 -1
  57. package/build/devtools/WebSocketBackingStore.d.ts +0 -10
  58. package/build/devtools/WebSocketBackingStore.d.ts.map +0 -1
  59. package/build/devtools/WebSocketWithReconnect.d.ts +0 -81
  60. package/build/devtools/WebSocketWithReconnect.d.ts.map +0 -1
  61. package/build/devtools/devtools.types.d.ts +0 -42
  62. package/build/devtools/devtools.types.d.ts.map +0 -1
  63. package/build/devtools/getConnectionInfo.d.ts +0 -6
  64. package/build/devtools/getConnectionInfo.d.ts.map +0 -1
  65. package/build/devtools/getConnectionInfo.native.d.ts +0 -6
  66. package/build/devtools/getConnectionInfo.native.d.ts.map +0 -1
  67. package/build/devtools/index.d.ts +0 -12
  68. package/build/devtools/index.d.ts.map +0 -1
  69. package/build/devtools/logger.d.ts +0 -6
  70. package/build/devtools/logger.d.ts.map +0 -1
  71. package/src/devtools/DevToolsPluginClient.ts +0 -240
  72. package/src/devtools/DevToolsPluginClientFactory.ts +0 -73
  73. package/src/devtools/DevToolsPluginClientImplApp.ts +0 -56
  74. package/src/devtools/DevToolsPluginClientImplBrowser.ts +0 -38
  75. package/src/devtools/MessageFramePacker.ts +0 -235
  76. package/src/devtools/ProtocolVersion.ts +0 -6
  77. package/src/devtools/WebSocketBackingStore.ts +0 -10
  78. package/src/devtools/WebSocketWithReconnect.ts +0 -318
  79. package/src/devtools/__tests__/DevToolsPluginClient-test.ts +0 -285
  80. package/src/devtools/__tests__/DevToolsPluginClientFactory-test.ts +0 -120
  81. package/src/devtools/__tests__/MessageFramePack-test.node.ts +0 -157
  82. package/src/devtools/__tests__/MockWebSocket.ts +0 -100
  83. package/src/devtools/__tests__/WebSocketWithReconnect-test.node.ts +0 -184
  84. package/src/devtools/__tests__/logger-test.ts +0 -20
  85. package/src/devtools/devtools.types.ts +0 -50
  86. package/src/devtools/getConnectionInfo.native.ts +0 -18
  87. package/src/devtools/getConnectionInfo.ts +0 -16
  88. package/src/devtools/index.ts +0 -53
  89. package/src/devtools/logger.ts +0 -29
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo",
3
- "version": "54.0.0-canary-20250722-599a28f",
3
+ "version": "54.0.0-preview.0",
4
4
  "description": "The Expo SDK",
5
5
  "main": "src/Expo.ts",
6
6
  "module": "src/Expo.ts",
@@ -20,6 +20,7 @@
20
20
  "android",
21
21
  "bin",
22
22
  "build",
23
+ "internal",
23
24
  "ios",
24
25
  "scripts",
25
26
  "src",
@@ -43,7 +44,8 @@
43
44
  "requiresExtraSetup.json",
44
45
  "tsconfig.base.json",
45
46
  "types",
46
- "virtual"
47
+ "virtual",
48
+ "template.tgz"
47
49
  ],
48
50
  "scripts": {
49
51
  "build": "expo-module build",
@@ -73,41 +75,41 @@
73
75
  "homepage": "https://github.com/expo/expo/tree/main/packages/expo",
74
76
  "dependencies": {
75
77
  "@babel/runtime": "^7.20.0",
76
- "@expo/cli": "1.0.0-canary-20250722-599a28f",
77
- "@expo/config": "11.0.14-canary-20250722-599a28f",
78
- "@expo/config-plugins": "10.0.4-canary-20250722-599a28f",
79
- "@expo/fingerprint": "0.13.5-canary-20250722-599a28f",
80
- "@expo/metro-config": "0.21.0-canary-20250722-599a28f",
78
+ "@expo/cli": "0.25.0",
79
+ "@expo/config": "~12.0.0",
80
+ "@expo/config-plugins": "~11.0.0",
81
+ "@expo/devtools": "0.1.0",
82
+ "@expo/fingerprint": "0.14.0",
83
+ "@expo/metro": "~0.1.1",
84
+ "@expo/metro-config": "0.21.0",
81
85
  "@expo/vector-icons": "^14.0.0",
82
- "babel-preset-expo": "13.3.0-canary-20250722-599a28f",
83
- "expo-asset": "11.2.0-canary-20250722-599a28f",
84
- "expo-constants": "17.1.8-canary-20250722-599a28f",
85
- "expo-file-system": "18.2.0-canary-20250722-599a28f",
86
- "expo-font": "13.4.0-canary-20250722-599a28f",
87
- "expo-keep-awake": "14.1.5-canary-20250722-599a28f",
88
- "expo-modules-autolinking": "2.2.0-canary-20250722-599a28f",
89
- "expo-modules-core": "2.6.0-canary-20250722-599a28f",
86
+ "babel-preset-expo": "~14.0.0",
87
+ "expo-asset": "~12.0.0",
88
+ "expo-constants": "~18.0.0",
89
+ "expo-file-system": "~19.0.0",
90
+ "expo-font": "~14.0.0",
91
+ "expo-keep-awake": "~15.0.0",
92
+ "expo-modules-autolinking": "3.0.0",
93
+ "expo-modules-core": "3.0.0",
90
94
  "pretty-format": "^29.7.0",
91
95
  "react-native-edge-to-edge": "1.6.0",
96
+ "react-refresh": "^0.14.2",
92
97
  "whatwg-url-without-unicode": "8.0.0-3"
93
98
  },
94
99
  "devDependencies": {
95
100
  "@types/node": "^22.14.0",
96
101
  "@types/react": "~19.0.10",
97
102
  "@types/react-test-renderer": "^19.1.0",
98
- "expo-module-scripts": "4.1.10-canary-20250722-599a28f",
103
+ "expo-module-scripts": "^5.0.0",
99
104
  "react": "19.1.0",
100
105
  "react-dom": "19.1.0",
101
- "react-native": "0.80.1",
102
- "web-streams-polyfill": "^3.3.2",
103
- "ws": "^8.18.0"
106
+ "react-native": "0.81.0",
107
+ "web-streams-polyfill": "^3.3.2"
104
108
  },
105
109
  "peerDependencies": {
106
- "@expo/dom-webview": "0.1.6-canary-20250722-599a28f",
107
- "@expo/metro-runtime": "6.0.0-canary-20250722-599a28f",
108
- "metro-runtime": "*",
110
+ "@expo/dom-webview": "*",
111
+ "@expo/metro-runtime": "*",
109
112
  "react": "*",
110
- "react-refresh": "*",
111
113
  "react-native": "*",
112
114
  "react-native-webview": "*"
113
115
  },
@@ -121,5 +123,6 @@
121
123
  "react-native-webview": {
122
124
  "optional": true
123
125
  }
124
- }
126
+ },
127
+ "gitHead": "cb7062e2c17d1fb09522834aaaac0e19b766df62"
125
128
  }
package/src/Expo.ts CHANGED
@@ -21,9 +21,13 @@ export {
21
21
  } from 'expo-modules-core';
22
22
 
23
23
  export type {
24
+ /** @deprecated Move to `SharedRef` with a type-only import instead */
24
25
  SharedRef as SharedRefType,
26
+ /** @deprecated Move to `EventEmitter` with a type-only import instead */
25
27
  EventEmitter as EventEmitterType,
28
+ /** @deprecated Move to `NativeModule` with a type-only import instead */
26
29
  NativeModule as NativeModuleType,
30
+ /** @deprecated Move to `SharedObject` with a type-only import instead */
27
31
  SharedObject as SharedObjectType,
28
32
  } from 'expo-modules-core/types';
29
33
 
@@ -7,10 +7,27 @@
7
7
  */
8
8
 
9
9
  // @ts-expect-error
10
- import Networking from 'react-native/Libraries/Network/RCTNetworking';
10
+ import { Networking } from 'react-native';
11
11
 
12
12
  type Subscriber = { remove: () => void };
13
13
 
14
+ class LoadBundleFromServerError extends Error {
15
+ name = 'LoadBundleFromServerError';
16
+
17
+ constructor(
18
+ message: string,
19
+ public url: string,
20
+ public isTimeout: boolean,
21
+ options?: ErrorOptions
22
+ ) {
23
+ super(message, options);
24
+ }
25
+ }
26
+
27
+ class LoadBundleFromServerRequestError extends LoadBundleFromServerError {
28
+ name = 'LoadBundleFromServerRequestError';
29
+ }
30
+
14
31
  export function fetchAsync(
15
32
  url: string
16
33
  ): Promise<{ body: string; status: number; headers: Record<string, string> }> {
@@ -21,9 +38,10 @@ export function fetchAsync(
21
38
  let dataListener: Subscriber | null = null;
22
39
  let completeListener: Subscriber | null = null;
23
40
  let responseListener: Subscriber | null = null;
41
+ let incrementalDataListener: Subscriber | null = null;
24
42
  return new Promise<{ body: string; status: number; headers: Record<string, string> }>(
25
43
  (resolve, reject) => {
26
- const addListener = Networking.addListener.bind(Networking) as (
44
+ const addListener = Networking.addListener.bind() as (
27
45
  event: string,
28
46
  callback: (props: [string, any, any]) => any
29
47
  ) => Subscriber;
@@ -32,6 +50,18 @@ export function fetchAsync(
32
50
  responseText = response;
33
51
  }
34
52
  });
53
+ incrementalDataListener = addListener(
54
+ 'didReceiveNetworkIncrementalData',
55
+ ([requestId, data]) => {
56
+ if (requestId === id) {
57
+ if (responseText != null) {
58
+ responseText += data;
59
+ } else {
60
+ responseText = data;
61
+ }
62
+ }
63
+ }
64
+ );
35
65
  responseListener = addListener(
36
66
  'didReceiveNetworkResponse',
37
67
  ([requestId, status, responseHeaders]) => {
@@ -41,15 +71,22 @@ export function fetchAsync(
41
71
  }
42
72
  }
43
73
  );
44
- completeListener = addListener('didCompleteNetworkResponse', ([requestId, error]) => {
45
- if (requestId === id) {
46
- if (error) {
47
- reject(error);
48
- } else {
49
- resolve({ body: responseText!, status: statusCode!, headers });
74
+ completeListener = addListener(
75
+ 'didCompleteNetworkResponse',
76
+ ([requestId, error, isTimeout]) => {
77
+ if (requestId === id) {
78
+ if (error) {
79
+ reject(
80
+ new LoadBundleFromServerRequestError('Could not load bundle', url, isTimeout, {
81
+ cause: error,
82
+ })
83
+ );
84
+ } else {
85
+ resolve({ body: responseText!, status: statusCode!, headers });
86
+ }
50
87
  }
51
88
  }
52
- });
89
+ );
53
90
  (Networking.sendRequest as any)(
54
91
  'GET',
55
92
  'asyncRequest',
@@ -59,7 +96,7 @@ export function fetchAsync(
59
96
  },
60
97
  '',
61
98
  'text',
62
- false,
99
+ true,
63
100
  0,
64
101
  (requestId: string) => {
65
102
  id = requestId;
@@ -71,5 +108,6 @@ export function fetchAsync(
71
108
  dataListener?.remove();
72
109
  completeListener?.remove();
73
110
  responseListener?.remove();
111
+ incrementalDataListener?.remove();
74
112
  });
75
113
  }
@@ -8,8 +8,7 @@
8
8
  * Based on this but with web support:
9
9
  * https://github.com/facebook/react-native/blob/086714b02b0fb838dee5a66c5bcefe73b53cf3df/Libraries/Utilities/HMRClient.js
10
10
  */
11
- // @ts-expect-error: no types for MetroHMRClient
12
- import MetroHMRClient from 'metro-runtime/src/modules/HMRClient';
11
+ import MetroHMRClient from '@expo/metro/metro-runtime/modules/HMRClient';
13
12
  import prettyFormat, { plugins } from 'pretty-format';
14
13
  import { DeviceEventEmitter } from 'react-native';
15
14
 
@@ -1,7 +1,4 @@
1
1
  /* eslint-env browser */
2
- // @ts-expect-error: untyped module
3
- import WebSocket from 'react-native/Libraries/WebSocket/WebSocket';
4
-
5
2
  import getDevServer from './getDevServer';
6
3
 
7
4
  declare namespace globalThis {
@@ -74,15 +74,7 @@ function normalizeArgs(
74
74
  ): [string, File | string] {
75
75
  if (value instanceof Blob) {
76
76
  // @ts-expect-error: `Blob.data.blobId` is react-native's proprietary property.
77
- if (value.data?.blobId != null) {
78
- // For react-native created Blob objects,
79
- // we need to keep its original form as-is without breaking functionality.
80
- // However, we need to pass `name` for our file name handling.
81
- // @ts-expect-error: Mutating the Blob object to add the `name` property.
82
- value.name = blobFilename ?? 'blob';
83
- } else {
84
- value = { type: value.type, name: blobFilename ?? 'blob', blob: value };
85
- }
77
+ value.name = blobFilename ?? blob.name ?? 'blob';
86
78
  } else if (typeof value !== 'object') {
87
79
  value = String(value);
88
80
  }
@@ -31,6 +31,20 @@ export async function convertReadableStreamToUint8ArrayAsync(
31
31
  return result;
32
32
  }
33
33
 
34
+ // Also accept instances that don't extend blob but have required methods (for filesystem and custom blob module)
35
+ function isBlob(obj: any): obj is Blob {
36
+ if (typeof obj !== 'object') {
37
+ return false;
38
+ }
39
+ if (!('arrayBuffer' in obj)) {
40
+ return false;
41
+ }
42
+ if (!('type' in obj)) {
43
+ return false;
44
+ }
45
+ return true;
46
+ }
47
+
34
48
  /**
35
49
  * Normalize a BodyInit object to a Uint8Array for NativeRequest
36
50
  */
@@ -54,7 +68,7 @@ export async function normalizeBodyInitAsync(
54
68
  return { body: new Uint8Array(body.buffer, body.byteOffset, body.byteLength) };
55
69
  }
56
70
 
57
- if (body instanceof Blob) {
71
+ if (body instanceof Blob || isBlob(body)) {
58
72
  return {
59
73
  body: new Uint8Array(await blobToArrayBufferAsync(body)),
60
74
  overriddenHeaders: [['Content-Type', body.type]],
@@ -59,9 +59,7 @@ describe(convertFormDataAsync, () => {
59
59
  it(`should convert expo-file-system FileBlob`, async () => {
60
60
  const formData = new ExpoFormData();
61
61
  const mockFileBlob = {
62
- file: {
63
- bytes: () => new Uint8Array([65, 66, 67]),
64
- },
62
+ bytes: () => new Uint8Array([65, 66, 67]),
65
63
  };
66
64
  // @ts-ignore
67
65
  formData.append('blob', mockFileBlob);
@@ -1,4 +1,33 @@
1
1
  import { blobToArrayBufferAsync } from '../../utils/blobUtils';
2
+ import { type ExpoFormDataValue } from '../FormData';
3
+
4
+ function encodeFilename(filename: string): string {
5
+ return encodeURIComponent(filename.replace(/\//g, '_'));
6
+ }
7
+
8
+ type ExpoFormHeaders = {
9
+ 'content-disposition': string | undefined;
10
+ 'content-type': string | undefined;
11
+ };
12
+
13
+ function getFormDataPartHeaders(part: ExpoFormDataValue, name: string) {
14
+ const contentDisposition = 'form-data; name="' + name + '"';
15
+
16
+ const headers: ExpoFormHeaders = {
17
+ 'content-disposition': contentDisposition,
18
+ 'content-type': undefined,
19
+ };
20
+
21
+ if (typeof part === 'object') {
22
+ if ('name' in part && typeof part.name === 'string') {
23
+ headers['content-disposition'] += `; filename="${encodeFilename(part.name)}"`;
24
+ }
25
+ if ('type' in part && typeof part.type === 'string') {
26
+ headers['content-type'] = part.type;
27
+ }
28
+ }
29
+ return headers;
30
+ }
2
31
 
3
32
  /**
4
33
  * Convert FormData to Uint8Array with a boundary
@@ -10,40 +39,40 @@ export async function convertFormDataAsync(
10
39
  formData: FormData,
11
40
  boundary: string = createBoundary()
12
41
  ): Promise<{ body: Uint8Array; boundary: string }> {
13
- // @ts-expect-error: React Native's FormData is not compatible with the web's FormData
14
- if (typeof formData.getParts !== 'function') {
15
- throw new Error('Unsupported FormData implementation');
42
+ if (typeof formData.entries !== 'function') {
43
+ // @ts-expect-error: React Native's FormData is not 100% compatible with ours
44
+ if (typeof formData.getParts == 'function') {
45
+ formData.entries = function () {
46
+ // @ts-expect-error
47
+ return formData.getParts().map((part) => {
48
+ if (part.string) return part.string;
49
+ if (part.file) return part.file;
50
+ if (part.blob) return part.blob;
51
+ });
52
+ };
53
+ } else {
54
+ throw new Error('Unsupported FormData implementation');
55
+ }
16
56
  }
17
57
  // @ts-expect-error: React Native's FormData is not 100% compatible with ours
18
- const parts: ExpoFormDataPart[] = formData.getParts();
58
+ const entries: [string, ExpoFormDataValue][] = formData.entries();
19
59
 
20
60
  const results: (Uint8Array | string)[] = [];
21
- for (const entry of parts) {
61
+ for (const [name, entry] of entries) {
22
62
  results.push(`--${boundary}\r\n`);
23
- for (const [headerKey, headerValue] of Object.entries(entry.headers)) {
24
- results.push(`${headerKey}: ${headerValue}\r\n`);
63
+ for (const [headerKey, headerValue] of Object.entries(getFormDataPartHeaders(entry, name))) {
64
+ if (headerValue) {
65
+ results.push(`${headerKey}: ${headerValue}\r\n`);
66
+ }
25
67
  }
26
68
  results.push(`\r\n`);
27
- if ('string' in entry) {
28
- results.push(entry.string);
29
- } else if ('file' in entry) {
30
- results.push(entry.file.bytes());
31
- } else if ('blob' in entry) {
32
- results.push(new Uint8Array(await blobToArrayBufferAsync(entry.blob)));
33
- } else if (entry._data?.blobId != null) {
34
- // When `FormData.getParts()` is called, React Native will use the spread syntax to copy the object and lose the Blob type info.
35
- // We should find the original Blob instance from the `FormData._parts` internal properties.
36
- // @ts-expect-error: react-native's proprietary Blob type
37
- const formDatum = formData._parts?.find(
38
- ([_name, value]: [name: string, value: any]) => value.data?.blobId === entry._data.blobId
39
- );
40
- if (formDatum == null) {
41
- throw new Error('Cannot find the original Blob instance from FormData');
42
- }
43
- if (!(formDatum[1] instanceof Blob)) {
44
- throw new Error('Unexpected value type for Blob entry in FormData');
45
- }
46
- results.push(new Uint8Array(await blobToArrayBufferAsync(formDatum[1])));
69
+ if (typeof entry === 'string') {
70
+ results.push(entry);
71
+ } else if (entry instanceof Blob) {
72
+ results.push(new Uint8Array(await blobToArrayBufferAsync(entry)));
73
+ } else if (typeof entry === 'object' && 'bytes' in entry) {
74
+ // @ts-expect-error: File or ExpoBlob don't extend Blob but implement the interface.
75
+ results.push(await entry.bytes());
47
76
  } else {
48
77
  throw new Error('Unsupported FormDataPart implementation');
49
78
  }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Copyright © 2025 650 Industries.
3
+ * Copyright © Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * Fork of unexposed react-native module
9
+ * https://github.com/facebook/react-native/blob/c5fb371061c1083684a23aa0852f6dbfb74a8b52/packages/react-native/Libraries/Utilities/PolyfillFunctions.js#L1
10
+ */
11
+
12
+ // Add a well-known shared symbol that doesn't show up in iteration or inspection
13
+ // this can be used to detect if the global object abides by the Expo team's documented
14
+ // built-in requirements.
15
+ const BUILTIN_SYMBOL = Symbol.for('expo.builtin');
16
+
17
+ /** Defines a lazily evaluated property on the supplied `object` */
18
+ function defineLazyObjectProperty<T>(
19
+ object: object,
20
+ name: string,
21
+ descriptor: {
22
+ get: () => T;
23
+ enumerable?: boolean;
24
+ writable?: boolean;
25
+ }
26
+ ): void {
27
+ const { get } = descriptor;
28
+ const enumerable = descriptor.enumerable !== false;
29
+ const writable = descriptor.writable !== false;
30
+
31
+ let value: any;
32
+ let valueSet = false;
33
+ function getValue(): T {
34
+ // WORKAROUND: A weird infinite loop occurs where calling `getValue` calls
35
+ // `setValue` which calls `Object.defineProperty` which somehow triggers
36
+ // `getValue` again. Adding `valueSet` breaks this loop.
37
+ if (!valueSet) {
38
+ // Calling `get()` here can trigger an infinite loop if it fails to
39
+ // remove the getter on the property, which can happen when executing
40
+ // JS in a V8 context. `valueSet = true` will break this loop, and
41
+ // sets the value of the property to undefined, until the code in `get()`
42
+ // finishes, at which point the property is set to the correct value.
43
+ valueSet = true;
44
+ setValue(get());
45
+ }
46
+ return value;
47
+ }
48
+ function setValue(newValue: T): void {
49
+ value = newValue;
50
+ valueSet = true;
51
+ Object.defineProperty(object, name, {
52
+ value: newValue,
53
+ configurable: true,
54
+ enumerable,
55
+ writable,
56
+ });
57
+ }
58
+
59
+ Object.defineProperty(object, name, {
60
+ get: getValue,
61
+ set: setValue,
62
+ configurable: true,
63
+ enumerable,
64
+ });
65
+ }
66
+
67
+ /**
68
+ * Sets an object's property. If a property with the same name exists, this will
69
+ * replace it but maintain its descriptor configuration. The property will be
70
+ * replaced with a lazy getter.
71
+ *
72
+ * In DEV mode the original property value will be preserved as `original[PropertyName]`
73
+ * so that, if necessary, it can be restored. For example, if you want to route
74
+ * network requests through DevTools (to trace them):
75
+ *
76
+ * global.XMLHttpRequest = global.originalXMLHttpRequest;
77
+ *
78
+ * @see https://github.com/facebook/react-native/issues/934
79
+ */
80
+ export function installGlobal<T extends object>(name: string, getValue: () => T): void {
81
+ // @ts-ignore: globalThis is not defined in all environments
82
+ const object = typeof global !== 'undefined' ? global : globalThis;
83
+ const descriptor = Object.getOwnPropertyDescriptor(object, name);
84
+ if (__DEV__ && descriptor) {
85
+ const backupName = `original${name[0].toUpperCase()}${name.slice(1)}`;
86
+ Object.defineProperty(object, backupName, descriptor);
87
+ }
88
+
89
+ const { enumerable, writable, configurable = false } = descriptor || {};
90
+ if (descriptor && !configurable) {
91
+ console.error('Failed to set polyfill. ' + name + ' is not configurable.');
92
+ return;
93
+ }
94
+
95
+ defineLazyObjectProperty(object, name, {
96
+ get() {
97
+ const value = getValue();
98
+ Object.defineProperty(value, BUILTIN_SYMBOL, {
99
+ value: true,
100
+ enumerable: false,
101
+ configurable: false,
102
+ });
103
+
104
+ return value;
105
+ },
106
+ enumerable: enumerable !== false,
107
+ writable: writable !== false,
108
+ });
109
+ }
@@ -1,27 +1,8 @@
1
1
  // This file configures the runtime environment to increase compatibility with WinterCG.
2
2
  // https://wintercg.org/
3
3
 
4
- // @ts-ignore: PolyfillFunctions does not have types exported
5
- import { polyfillGlobal as installGlobal } from 'react-native/Libraries/Utilities/PolyfillFunctions';
6
-
7
4
  import { installFormDataPatch } from './FormData';
8
- // Add a well-known shared symbol that doesn't show up in iteration or inspection
9
- // this can be used to detect if the global object abides by the Expo team's documented
10
- // built-in requirements.
11
- const BUILTIN_SYMBOL = Symbol.for('expo.builtin');
12
-
13
- function addBuiltinSymbol(obj: object) {
14
- Object.defineProperty(obj, BUILTIN_SYMBOL, {
15
- value: true,
16
- enumerable: false,
17
- configurable: false,
18
- });
19
- return obj;
20
- }
21
-
22
- function install(name: string, getValue: () => any) {
23
- installGlobal(name, () => addBuiltinSymbol(getValue()));
24
- }
5
+ import { installGlobal as install } from './installGlobal';
25
6
 
26
7
  // https://encoding.spec.whatwg.org/#textdecoder
27
8
  install('TextDecoder', () => require('./TextDecoder').TextDecoder);
package/template.tgz ADDED
Binary file
@@ -1,72 +0,0 @@
1
- import { WebSocketBackingStore } from './WebSocketBackingStore';
2
- import type { ConnectionInfo, DevToolsPluginClientOptions, HandshakeMessageParams } from './devtools.types';
3
- export interface EventSubscription {
4
- remove(): void;
5
- }
6
- /**
7
- * This client is for the Expo DevTools Plugins to communicate between the app and the DevTools webpage hosted in a browser.
8
- * All the code should be both compatible with browsers and React Native.
9
- */
10
- export declare abstract class DevToolsPluginClient {
11
- readonly connectionInfo: ConnectionInfo;
12
- private readonly options?;
13
- private listeners;
14
- private static defaultWSStore;
15
- private readonly wsStore;
16
- protected isClosed: boolean;
17
- protected retries: number;
18
- private readonly messageFramePacker;
19
- constructor(connectionInfo: ConnectionInfo, options?: DevToolsPluginClientOptions | undefined);
20
- /**
21
- * Initialize the connection.
22
- * @hidden
23
- */
24
- initAsync(): Promise<void>;
25
- /**
26
- * Close the connection.
27
- */
28
- closeAsync(): Promise<void>;
29
- /**
30
- * Send a message to the other end of DevTools.
31
- * @param method A method name.
32
- * @param params any extra payload.
33
- */
34
- sendMessage(method: string, params: any): void;
35
- /**
36
- * Subscribe to a message from the other end of DevTools.
37
- * @param method Subscribe to a message with a method name.
38
- * @param listener Listener to be called when a message is received.
39
- */
40
- addMessageListener(method: string, listener: (params: any) => void): EventSubscription;
41
- /**
42
- * Subscribe to a message from the other end of DevTools just once.
43
- * @param method Subscribe to a message with a method name.
44
- * @param listener Listener to be called when a message is received.
45
- */
46
- addMessageListenerOnce(method: string, listener: (params: any) => void): void;
47
- /**
48
- * Internal handshake message sender.
49
- * @hidden
50
- */
51
- protected sendHandshakeMessage(params: HandshakeMessageParams): void;
52
- /**
53
- * Internal handshake message listener.
54
- * @hidden
55
- */
56
- protected addHandskakeMessageListener(listener: (params: HandshakeMessageParams) => void): EventSubscription;
57
- /**
58
- * Returns whether the client is connected to the server.
59
- */
60
- isConnected(): boolean;
61
- /**
62
- * The method to create the WebSocket connection.
63
- */
64
- protected connectAsync(): Promise<WebSocket>;
65
- protected handleMessage: (event: WebSocketMessageEvent) => Promise<void>;
66
- /**
67
- * Get the WebSocket backing store. Exposed for testing.
68
- * @hidden
69
- */
70
- getWebSocketBackingStore(): WebSocketBackingStore;
71
- }
72
- //# sourceMappingURL=DevToolsPluginClient.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DevToolsPluginClient.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EACV,cAAc,EACd,2BAA2B,EAC3B,sBAAsB,EACvB,MAAM,kBAAkB,CAAC;AAS1B,MAAM,WAAW,iBAAiB;IAChC,MAAM,IAAI,IAAI,CAAC;CAChB;AAED;;;GAGG;AACH,8BAAsB,oBAAoB;aAYtB,cAAc,EAAE,cAAc;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAZ3B,OAAO,CAAC,SAAS,CAAyD;IAE1E,OAAO,CAAC,MAAM,CAAC,cAAc,CAAsD;IACnF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8D;IAEtF,SAAS,CAAC,QAAQ,UAAS;IAC3B,SAAS,CAAC,OAAO,SAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CACR;gBAGT,cAAc,EAAE,cAAc,EAC7B,OAAO,CAAC,EAAE,2BAA2B,YAAA;IAMxD;;;OAGG;IACU,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAQvC;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWxC;;;;OAIG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG;IAmB9C;;;;OAIG;IACI,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,GAAG,iBAAiB;IAU7F;;;;OAIG;IACI,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAQpF;;;OAGG;IACH,SAAS,CAAC,oBAAoB,CAAC,MAAM,EAAE,sBAAsB;IAQ7D;;;OAGG;IACH,SAAS,CAAC,2BAA2B,CACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,GACjD,iBAAiB;IA2BpB;;OAEG;IACI,WAAW,IAAI,OAAO;IAI7B;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAyB5C,SAAS,CAAC,aAAa,GAAU,OAAO,qBAAqB,mBA6B3D;IAEF;;;OAGG;IACI,wBAAwB,IAAI,qBAAqB;CAGzD"}
@@ -1,16 +0,0 @@
1
- import type { DevToolsPluginClient } from './DevToolsPluginClient';
2
- import type { ConnectionInfo, DevToolsPluginClientOptions } from './devtools.types';
3
- /**
4
- * Factory of DevToolsPluginClient based on sender types.
5
- * @hidden
6
- */
7
- export declare function createDevToolsPluginClient(connectionInfo: ConnectionInfo, options?: DevToolsPluginClientOptions): Promise<DevToolsPluginClient>;
8
- /**
9
- * Public API to get the DevToolsPluginClient instance.
10
- */
11
- export declare function getDevToolsPluginClientAsync(pluginName: string, options?: DevToolsPluginClientOptions): Promise<DevToolsPluginClient>;
12
- /**
13
- * Internal testing API to cleanup all DevToolsPluginClient instances.
14
- */
15
- export declare function cleanupDevToolsPluginInstances(): void;
16
- //# sourceMappingURL=DevToolsPluginClientFactory.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DevToolsPluginClientFactory.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClientFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAGnE,OAAO,KAAK,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAKpF;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,cAAc,EAAE,cAAc,EAC9B,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,oBAAoB,CAAC,CAS/B;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAChD,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,oBAAoB,CAAC,CAyB/B;AAED;;GAEG;AACH,wBAAgB,8BAA8B,SAU7C"}
@@ -1,15 +0,0 @@
1
- import { DevToolsPluginClient } from './DevToolsPluginClient';
2
- /**
3
- * The DevToolsPluginClient for the app -> browser communication.
4
- */
5
- export declare class DevToolsPluginClientImplApp extends DevToolsPluginClient {
6
- private browserClientMap;
7
- /**
8
- * Initialize the connection.
9
- * @hidden
10
- */
11
- initAsync(): Promise<void>;
12
- private addHandshakeHandler;
13
- private terminateBrowserClient;
14
- }
15
- //# sourceMappingURL=DevToolsPluginClientImplApp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DevToolsPluginClientImplApp.d.ts","sourceRoot":"","sources":["../../src/devtools/DevToolsPluginClientImplApp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,oBAAoB;IAEnE,OAAO,CAAC,gBAAgB,CAA8B;IAEtD;;;OAGG;IACY,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC,OAAO,CAAC,mBAAmB;IA4B3B,OAAO,CAAC,sBAAsB;CAQ/B"}