first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import NativeSourceCode from '../../NativeModules/specs/NativeSourceCode';
let _cachedDevServerURL: ?string;
let _cachedFullBundleURL: ?string;
const FALLBACK = 'http://localhost:8081/';
type DevServerInfo = {
url: string,
fullBundleUrl: ?string,
bundleLoadedFromServer: boolean,
...
};
/**
* Many RN development tools rely on the development server (packager) running
* @return URL to packager with trailing slash
*/
export default function getDevServer(): DevServerInfo {
if (_cachedDevServerURL === undefined) {
const scriptUrl = NativeSourceCode.getConstants().scriptURL;
const match = scriptUrl.match(/^https?:\/\/.*?\//);
_cachedDevServerURL = match ? match[0] : null;
_cachedFullBundleURL = match ? scriptUrl : null;
}
return {
url: _cachedDevServerURL ?? FALLBACK,
fullBundleUrl: _cachedFullBundleURL,
bundleLoadedFromServer: _cachedDevServerURL !== null,
};
}

View File

@@ -0,0 +1,196 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import Networking from '../../Network/RCTNetworking';
import DevLoadingView from '../../Utilities/DevLoadingView';
import HMRClient from '../../Utilities/HMRClient';
import getDevServer from './getDevServer';
declare var global: {globalEvalWithSourceUrl?: (string, string) => mixed, ...};
let pendingRequests = 0;
const cachedPromisesByUrl = new Map<string, Promise<void>>();
export class LoadBundleFromServerError extends Error {
url: string;
isTimeout: boolean;
constructor(
message: string,
url: string,
isTimeout: boolean,
options?: {cause: mixed, ...},
): void {
super(message, options);
this.url = url;
this.isTimeout = isTimeout;
this.name = 'LoadBundleFromServerError';
}
}
export class LoadBundleFromServerRequestError extends LoadBundleFromServerError {
constructor(
message: string,
url: string,
isTimeout: boolean,
options?: {cause: mixed, ...},
): void {
super(message, url, isTimeout, options);
this.name = 'LoadBundleFromServerRequestError';
}
}
function asyncRequest(
url: string,
): Promise<{body: string, headers: {[string]: string}}> {
let id = null;
let responseText = null;
let headers = null;
let dataListener;
let completeListener;
let responseListener;
let incrementalDataListener;
return new Promise<{body: string, headers: {[string]: string}}>(
(resolve, reject) => {
dataListener = Networking.addListener(
'didReceiveNetworkData',
([requestId, response]) => {
if (requestId === id) {
responseText = response;
}
},
);
incrementalDataListener = Networking.addListener(
'didReceiveNetworkIncrementalData',
([requestId, data]) => {
if (requestId === id) {
if (responseText != null) {
responseText += data;
} else {
responseText = data;
}
}
},
);
responseListener = Networking.addListener(
'didReceiveNetworkResponse',
([requestId, status, responseHeaders]) => {
if (requestId === id) {
headers = responseHeaders;
}
},
);
completeListener = Networking.addListener(
'didCompleteNetworkResponse',
([requestId, errorMessage, isTimeout]) => {
if (requestId === id) {
if (errorMessage) {
reject(
new LoadBundleFromServerRequestError(
'Could not load bundle',
url,
isTimeout,
{
cause: errorMessage,
},
),
);
} else {
//$FlowFixMe[incompatible-type]
resolve({body: responseText, headers});
}
}
},
);
Networking.sendRequest(
'GET',
'asyncRequest',
url,
{},
'',
'text',
true,
0,
requestId => {
id = requestId;
},
true,
);
},
).finally(() => {
dataListener?.remove();
completeListener?.remove();
responseListener?.remove();
incrementalDataListener?.remove();
});
}
function buildUrlForBundle(bundlePathAndQuery: string) {
const {url: serverUrl} = getDevServer();
return (
serverUrl.replace(/\/+$/, '') + '/' + bundlePathAndQuery.replace(/^\/+/, '')
);
}
export default function loadBundleFromServer(
bundlePathAndQuery: string,
): Promise<void> {
const requestUrl = buildUrlForBundle(bundlePathAndQuery);
let loadPromise = cachedPromisesByUrl.get(requestUrl);
if (loadPromise) {
return loadPromise;
}
DevLoadingView.showMessage('Downloading...', 'load');
++pendingRequests;
loadPromise = asyncRequest(requestUrl)
.then<void>(({body, headers}) => {
if (
headers['Content-Type'] != null &&
headers['Content-Type'].indexOf('application/json') >= 0
) {
// Errors are returned as JSON.
throw new LoadBundleFromServerError(
'Could not load bundle',
bundlePathAndQuery,
false, // isTimeout
{
cause:
JSON.parse(body).message ||
`Unknown error fetching '${bundlePathAndQuery}'`,
},
);
}
HMRClient.registerBundle(requestUrl);
// Some engines do not support `sourceURL` as a comment. We expose a
// `globalEvalWithSourceUrl` function to handle updates in that case.
if (global.globalEvalWithSourceUrl) {
global.globalEvalWithSourceUrl(body, requestUrl);
} else {
// eslint-disable-next-line no-eval
eval(body);
}
})
.catch<void>(e => {
cachedPromisesByUrl.delete(requestUrl);
throw e;
})
.finally(() => {
if (!--pendingRequests) {
DevLoadingView.hide();
}
});
cachedPromisesByUrl.set(requestUrl, loadPromise);
return loadPromise;
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
const getDevServer = require('./getDevServer').default;
export default function openFileInEditor(file: string, lineNumber: number) {
// $FlowFixMe[unused-promise]
fetch(getDevServer().url + 'open-stack-frame', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({file, lineNumber}),
});
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
const getDevServer = require('./getDevServer').default;
export default function openURLInBrowser(url: string) {
// $FlowFixMe[unused-promise]
fetch(getDevServer().url + 'open-url', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({url}),
});
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
import type {StackFrame} from '../NativeExceptionsManager';
import type {HermesParsedStack} from './parseHermesStack';
const parseHermesStack = require('./parseHermesStack').default;
function convertHermesStack(stack: HermesParsedStack): Array<StackFrame> {
const frames: Array<StackFrame> = [];
for (const entry of stack.entries) {
if (entry.type !== 'FRAME') {
continue;
}
const {location, functionName} = entry;
if (location.type === 'NATIVE' || location.type === 'INTERNAL_BYTECODE') {
continue;
}
frames.push({
methodName: functionName,
file: location.sourceUrl,
lineNumber: location.line1Based,
column:
location.type === 'SOURCE'
? location.column1Based - 1
: location.virtualOffset0Based,
});
}
return frames;
}
export default function parseErrorStack(
errorStack?: string,
): Array<StackFrame> {
if (errorStack == null) {
return [];
}
const stacktraceParser = require('stacktrace-parser');
const parsedStack = Array.isArray(errorStack)
? errorStack
: global.HermesInternal
? convertHermesStack(parseHermesStack(errorStack))
: stacktraceParser.parse(errorStack).map((frame): StackFrame => ({
...frame,
column: frame.column != null ? frame.column - 1 : null,
}));
return parsedStack;
}

View File

@@ -0,0 +1,147 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
type HermesStackLocationNative = $ReadOnly<{
type: 'NATIVE',
}>;
type HermesStackLocationSource = $ReadOnly<{
type: 'SOURCE',
sourceUrl: string,
line1Based: number,
column1Based: number,
}>;
type HermesStackLocationInternalBytecode = $ReadOnly<{
type: 'INTERNAL_BYTECODE',
sourceUrl: string,
line1Based: number,
virtualOffset0Based: number,
}>;
type HermesStackLocationBytecode = $ReadOnly<{
type: 'BYTECODE',
sourceUrl: string,
line1Based: number,
virtualOffset0Based: number,
}>;
type HermesStackLocation =
| HermesStackLocationNative
| HermesStackLocationSource
| HermesStackLocationInternalBytecode
| HermesStackLocationBytecode;
type HermesStackEntryFrame = $ReadOnly<{
type: 'FRAME',
location: HermesStackLocation,
functionName: string,
}>;
type HermesStackEntrySkipped = $ReadOnly<{
type: 'SKIPPED',
count: number,
}>;
type HermesStackEntry = HermesStackEntryFrame | HermesStackEntrySkipped;
export type HermesParsedStack = $ReadOnly<{
message: string,
entries: $ReadOnlyArray<HermesStackEntry>,
}>;
// Capturing groups:
// 1. function name
// 2. is this a native stack frame?
// 3. is this a bytecode address or a source location?
// 4. source URL (filename)
// 5. line number (1 based)
// 6. column number (1 based) or virtual offset (0 based)
const RE_FRAME =
/^ {4}at (.+?)(?: \((native)\)?| \((address at )?(.*?):(\d+):(\d+)\))$/;
// Capturing groups:
// 1. count of skipped frames
const RE_SKIPPED = /^ {4}... skipping (\d+) frames$/;
const RE_COMPONENT_NO_STACK = /^ {4}at .*$/;
function isInternalBytecodeSourceUrl(sourceUrl: string): boolean {
// See https://github.com/facebook/hermes/blob/3332fa020cae0bab751f648db7c94e1d687eeec7/lib/VM/Runtime.cpp#L1100
return sourceUrl === 'InternalBytecode.js';
}
function parseLine(line: string): ?HermesStackEntry {
const asFrame = line.match(RE_FRAME);
if (asFrame) {
return {
type: 'FRAME',
functionName: asFrame[1],
location:
asFrame[2] === 'native'
? {type: 'NATIVE'}
: asFrame[3] === 'address at '
? isInternalBytecodeSourceUrl(asFrame[4])
? {
type: 'INTERNAL_BYTECODE',
sourceUrl: asFrame[4],
line1Based: Number.parseInt(asFrame[5], 10),
virtualOffset0Based: Number.parseInt(asFrame[6], 10),
}
: {
type: 'BYTECODE',
sourceUrl: asFrame[4],
line1Based: Number.parseInt(asFrame[5], 10),
virtualOffset0Based: Number.parseInt(asFrame[6], 10),
}
: {
type: 'SOURCE',
sourceUrl: asFrame[4],
line1Based: Number.parseInt(asFrame[5], 10),
column1Based: Number.parseInt(asFrame[6], 10),
},
};
}
const asSkipped = line.match(RE_SKIPPED);
if (asSkipped) {
return {
type: 'SKIPPED',
count: Number.parseInt(asSkipped[1], 10),
};
}
}
export default function parseHermesStack(stack: string): HermesParsedStack {
const lines = stack.split(/\n/);
let entries: Array<HermesStackEntryFrame | HermesStackEntrySkipped> = [];
let lastMessageLine = -1;
for (let i = 0; i < lines.length; ++i) {
const line = lines[i];
if (!line) {
continue;
}
const entry = parseLine(line);
if (entry) {
entries.push(entry);
continue;
}
if (RE_COMPONENT_NO_STACK.test(line)) {
// Skip component stacks without source location.
// TODO: This will not be displayed, not sure how to handle it.
continue;
}
// No match - we're still in the message
lastMessageLine = i;
entries = [];
}
const message = lines.slice(0, lastMessageLine + 1).join('\n');
return {message, entries};
}

View File

@@ -0,0 +1,51 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
import type {StackFrame} from '../NativeExceptionsManager';
const getDevServer = require('./getDevServer').default;
export type CodeFrame = $ReadOnly<{
content: string,
location: ?{
row: number,
column: number,
...
},
fileName: string,
}>;
export type SymbolicatedStackTrace = $ReadOnly<{
stack: Array<StackFrame>,
codeFrame: ?CodeFrame,
}>;
export default async function symbolicateStackTrace(
stack: Array<StackFrame>,
extraData?: mixed,
): Promise<SymbolicatedStackTrace> {
const devServer = getDevServer();
if (!devServer.bundleLoadedFromServer) {
throw new Error('Bundle was not loaded from Metro.');
}
// Lazy-load `fetch` until the first symbolication call to avoid circular requires.
const fetch = global.fetch ?? require('../../Network/fetch').fetch;
const response = await fetch(devServer.url + 'symbolicate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({stack, extraData}),
});
return await response.json();
}

View File

@@ -0,0 +1,297 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
import type {ExtendedError} from './ExtendedError';
import type {ExceptionData} from './NativeExceptionsManager';
export class SyntheticError extends Error {
name: string = '';
}
type ExceptionDecorator = ExceptionData => ExceptionData;
let userExceptionDecorator: ?ExceptionDecorator;
let inUserExceptionDecorator = false;
// This string is used to decorate an ExtendedError with extra data in select usecases.
// Note that data passed using this method should be strictly contained,
// as data that's not serializable/too large may cause issues with passing the error to the native code.
// TODO(T204185517): We should use a Symbol for this, but jsi through jsc doesn't support it yet.
const decoratedExtraDataKey = 'RN$ErrorExtraDataKey';
/**
* Allows the app to add information to the exception report before it is sent
* to native. This API is not final.
*/
function unstable_setExceptionDecorator(
exceptionDecorator: ?ExceptionDecorator,
) {
userExceptionDecorator = exceptionDecorator;
}
function preprocessException(data: ExceptionData): ExceptionData {
if (userExceptionDecorator && !inUserExceptionDecorator) {
inUserExceptionDecorator = true;
try {
return userExceptionDecorator(data);
} catch {
// Fall through
} finally {
inUserExceptionDecorator = false;
}
}
return data;
}
/**
* Handles the developer-visible aspect of errors and exceptions
*/
let exceptionID = 0;
function reportException(
e: ExtendedError,
isFatal: boolean,
reportToConsole: boolean, // only true when coming from handleException; the error has not yet been logged
) {
const parseErrorStack = require('./Devtools/parseErrorStack').default;
const stack = parseErrorStack(e?.stack);
const currentExceptionID = ++exceptionID;
const originalMessage = e.message || '';
let message = originalMessage;
if (e.componentStack != null) {
message += `\n\nThis error is located at:${e.componentStack}`;
}
const namePrefix = e.name == null || e.name === '' ? '' : `${e.name}: `;
if (!message.startsWith(namePrefix)) {
message = namePrefix + message;
}
// $FlowFixMe[unclear-type]
const extraData: Object = {
// $FlowFixMe[incompatible-use] we can't define a type with a Symbol-keyed field in flow
...e[decoratedExtraDataKey],
jsEngine: e.jsEngine,
rawStack: e.stack,
};
if (e.cause != null && typeof e.cause === 'object') {
extraData.stackSymbols = e.cause.stackSymbols;
extraData.stackReturnAddresses = e.cause.stackReturnAddresses;
extraData.stackElements = e.cause.stackElements;
}
const data = preprocessException({
message,
originalMessage: message === originalMessage ? null : originalMessage,
name: e.name == null || e.name === '' ? null : e.name,
componentStack:
typeof e.componentStack === 'string' ? e.componentStack : null,
stack,
id: currentExceptionID,
isFatal,
extraData,
});
if (reportToConsole) {
// we feed back into console.error, to make sure any methods that are
// monkey patched on top of console.error are called when coming from
// handleException
console.error(e);
}
if (__DEV__) {
// reportToConsole is only true when coming from handleException,
// and the error has not yet been logged. If it's false, then it was
// reported to LogBox in reactConsoleErrorHandler, and we don't need to.
if (reportToConsole) {
const LogBox = require('../LogBox/LogBox').default;
LogBox.addException({
...data,
isComponentError: !!e.isComponentError,
});
}
} else if (isFatal || e.type !== 'warn') {
const NativeExceptionsManager =
require('./NativeExceptionsManager').default;
if (NativeExceptionsManager) {
if (isFatal) {
if (global.RN$hasHandledFatalException?.()) {
return;
}
global.RN$notifyOfFatalException?.();
}
NativeExceptionsManager.reportException(data);
}
}
}
declare var console: {
error: (...data: $ReadOnlyArray<mixed>) => void,
_errorOriginal: (...data: $ReadOnlyArray<mixed>) => void,
reportErrorsAsExceptions: boolean,
...
};
// If we trigger console.error _from_ handleException,
// we do want to make sure that console.error doesn't trigger error reporting again
let inExceptionHandler = false;
/**
* Logs exceptions to the (native) console and displays them
*/
function handleException(e: mixed, isFatal: boolean) {
// TODO(T196834299): We should really use a c++ turbomodule for this
const reportToConsole = true;
if (
!global.RN$handleException ||
!global.RN$handleException(e, isFatal, reportToConsole)
) {
let error: Error;
if (e instanceof Error) {
error = e;
} else {
// Workaround for reporting errors caused by `throw 'some string'`
// Unfortunately there is no way to figure out the stacktrace in this
// case, so if you ended up here trying to trace an error, look for
// `throw '<error message>'` somewhere in your codebase.
error = new SyntheticError(e);
}
try {
inExceptionHandler = true;
/* $FlowFixMe[class-object-subtyping] added when improving typing for this
* parameters */
// $FlowFixMe[incompatible-type]
reportException(error, isFatal, reportToConsole);
} finally {
inExceptionHandler = false;
}
}
}
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
* LTI update could not be added via codemod */
function reactConsoleErrorHandler(...args) {
// bubble up to any original handlers
console._errorOriginal(...args);
if (!console.reportErrorsAsExceptions) {
return;
}
if (inExceptionHandler || global.RN$inExceptionHandler?.()) {
// The fundamental trick here is that are multiple entry point to logging errors:
// (see D19743075 for more background)
//
// 1. An uncaught exception being caught by the global handler
// 2. An error being logged throw console.error
//
// However, console.error is monkey patched multiple times: by this module, and by the
// DevTools setup that sends messages to Metro.
// The patching order cannot be relied upon.
//
// So, some scenarios that are handled by this flag:
//
// Logging an error:
// 1. console.error called from user code
// 2. (possibly) arrives _first_ at DevTool handler, send to Metro
// 3. Bubbles to here
// 4. goes into report Exception.
// 5. should not trigger console.error again, to avoid looping / logging twice
// 6. should still bubble up to original console
// (which might either be console.log, or the DevTools handler in case it patched _earlier_ and (2) didn't happen)
//
// Throwing an uncaught exception:
// 1. exception thrown
// 2. picked up by handleException
// 3. should be sent to console.error (not console._errorOriginal, as DevTools might have patched _later_ and it needs to send it to Metro)
// 4. that _might_ bubble again to the `reactConsoleErrorHandle` defined here
// -> should not handle exception _again_, to avoid looping / showing twice (this code branch)
// 5. should still bubble up to original console (which might either be console.log, or the DevTools handler in case that one patched _earlier_)
return;
}
let error;
const firstArg = args[0];
if (firstArg?.stack) {
// reportException will console.error this with high enough fidelity.
error = firstArg;
} else {
const stringifySafe = require('../Utilities/stringifySafe').default;
const message = args
.map(arg => (typeof arg === 'string' ? arg : stringifySafe(arg)))
.join(' ');
error = new SyntheticError(message);
error.name = 'console.error';
}
const isFatal = false;
const reportToConsole = false;
if (
!global.RN$handleException ||
!global.RN$handleException(error, isFatal, reportToConsole)
) {
if (__DEV__) {
// If we're not reporting to the console in reportException,
// we need to report it as a console.error here.
/* $FlowFixMe[constant-condition] Error discovered during Constant
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
if (!reportToConsole) {
require('../LogBox/LogBox').default.addConsoleLog('error', ...args);
}
}
if (error.message.startsWith('Warning: ')) {
// React warnings use console.error so that a stack trace is shown, but
// we don't (currently) want these to report to native.
// Note: We can probably remove this, but would be a breaking change
// if the warning module is still used somewhere.
// Logic duplicated in polyfills/console.js
return;
}
reportException(
/* $FlowFixMe[class-object-subtyping] added when improving typing for this
* parameters */
// $FlowFixMe[incompatible-type]
error,
isFatal,
reportToConsole,
);
}
}
/**
* Shows a redbox with stacktrace for all console.error messages. Disable by
* setting `console.reportErrorsAsExceptions = false;` in your app.
*/
function installConsoleErrorReporter() {
// Enable reportErrorsAsExceptions
if (console._errorOriginal) {
return; // already installed
}
// Flow doesn't like it when you set arbitrary values on a global object
console._errorOriginal = console.error.bind(console);
console.error = reactConsoleErrorHandler;
if (console.reportErrorsAsExceptions === undefined) {
// Individual apps can disable this
// Flow doesn't like it when you set arbitrary values on a global object
console.reportErrorsAsExceptions = true;
}
}
const ExceptionsManager = {
decoratedExtraDataKey,
handleException,
installConsoleErrorReporter,
SyntheticError, // <- for backwards compatibility
unstable_setExceptionDecorator,
};
export default ExceptionsManager;

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
export type ExtendedError = Error &
interface {
jsEngine?: string,
preventSymbolication?: boolean,
componentStack?: string,
isComponentError?: boolean,
type?: string,
// Note: A field keyed by the Symbol ExceptionsManager.decoratedExtraDataKey is also read from ExtendedErrors.
// This field isn't documented in the types as Flow does not support this usecase, but it's effectively:
// [decoratedExtraDataKey]?: {[string]: mixed},
// Included for native errors
cause?: {
name: string,
message: string,
// $FlowFixMe[unclear-type]
stackElements?: $ReadOnlyArray<Object>,
// $FlowFixMe[unclear-type]
stackSymbols?: $ReadOnlyArray<Object>,
// $FlowFixMe[unclear-type]
stackReturnAddresses?: $ReadOnlyArray<Object>,
},
};

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use client';
/**
* Sets up global variables typical in most JavaScript environments.
*
* 1. Global timers (via `setTimeout` etc).
* 2. Global console object.
* 3. Hooks for printing stack traces with source maps.
*
* Leaves enough room in the environment for implementing your own:
*
* 1. Require system.
* 2. Bridged modules.
*
*/
'use strict';
const start = Date.now();
require('../../src/private/setup/setUpDefaultReactNativeEnvironment').default();
const GlobalPerformanceLogger =
require('../Utilities/GlobalPerformanceLogger').default;
// We could just call GlobalPerformanceLogger.markPoint at the top of the file,
// but then we'd be excluding the time it took to require the logger.
// Instead, we just use Date.now and backdate the timestamp.
GlobalPerformanceLogger.markPoint(
'initializeCore_start',
GlobalPerformanceLogger.currentTimestamp() - (Date.now() - start),
);
GlobalPerformanceLogger.markPoint('initializeCore_end');

View File

@@ -0,0 +1,14 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
export * from '../../src/private/specs_DEPRECATED/modules/NativeExceptionsManager';
import NativeExceptionsManager from '../../src/private/specs_DEPRECATED/modules/NativeExceptionsManager';
export default NativeExceptionsManager;

View File

@@ -0,0 +1,39 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {IEventEmitter} from '../vendor/emitter/EventEmitter';
import EventEmitter from '../vendor/emitter/EventEmitter';
export type RawEventEmitterEvent = $ReadOnly<{
eventName: string,
// We expect, but do not/cannot require, that nativeEvent is an object
// with the properties: key, elementType (string), type (string), tag (numeric),
// and a stateNode of the native element/Fiber the event was emitted to.
nativeEvent: {[string]: mixed},
}>;
type RawEventDefinitions = {
[eventChannel: string]: [RawEventEmitterEvent],
};
const RawEventEmitter: IEventEmitter<RawEventDefinitions> =
new EventEmitter<RawEventDefinitions>();
// See the React renderer / react repo for how this is used.
// Raw events are emitted here when they are received in JS
// and before any event Plugins process them or before components
// have a chance to respond to them. This allows you to implement
// app-specific perf monitoring, which is unimplemented by default,
// making this entire RawEventEmitter do nothing by default until
// *you* add listeners for your own app.
// Besides perf monitoring and maybe debugging, this RawEventEmitter
// should not be used.
export default RawEventEmitter;

View File

@@ -0,0 +1,65 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {ExtendedError} from './ExtendedError';
import ExceptionsManager, {SyntheticError} from './ExceptionsManager';
export type CapturedError = {
+componentStack: string,
+error: mixed,
+errorBoundary: ?{...},
...
};
const ReactFiberErrorDialog = {
/**
* Intercept lifecycle errors and ensure they are shown with the correct stack
* trace within the native redbox component.
*/
showErrorDialog({componentStack, error: errorValue}: CapturedError): boolean {
let error: ?ExtendedError;
// Typically, `errorValue` should be an error. However, other values such as
// strings (or even null) are sometimes thrown.
if (errorValue instanceof Error) {
/* $FlowFixMe[class-object-subtyping] added when improving typing for
* this parameters */
// $FlowFixMe[incompatible-type]
error = (errorValue: ExtendedError);
} else if (typeof errorValue === 'string') {
/* $FlowFixMe[class-object-subtyping] added when improving typing for
* this parameters */
// $FlowFixMe[incompatible-type]
error = (new SyntheticError(errorValue): ExtendedError);
} else {
/* $FlowFixMe[class-object-subtyping] added when improving typing for
* this parameters */
// $FlowFixMe[incompatible-type]
error = (new SyntheticError('Unspecified error'): ExtendedError);
}
try {
error.componentStack = componentStack;
error.isComponentError = true;
} catch {
// Ignored.
}
ExceptionsManager.handleException(error, false);
// Return false here to prevent ReactFiberErrorLogger default behavior of
// logging error details to console.error. Calls to console.error are
// automatically routed to the native redbox controller, which we've already
// done above by calling ExceptionsManager.
return false;
},
};
export default ReactFiberErrorDialog;

View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @noformat
* @generated by scripts/releases/set-version.js
*/
/**
* Object containing the current React Native version.
*
* Specifically, this is the source of truth for the resolved `react-native`
* package in the JavaScript bundle. Apps and libraries can use this to
* determine compatibility or enable version-specific features.
*
* @example
* ```js
* // Get the full version string
* const version = ReactNativeVersion.getVersionString();
*
* // Access individual version components
* const major = ReactNativeVersion.major;
* ```
*/
export default class ReactNativeVersion {
static major: number = 0;
static minor: number = 83;
static patch: number = 2;
static prerelease: string | null = null;
static getVersionString(): string {
return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
}
}
/**
* @deprecated Compatibility export — please import `ReactNativeVersion` from
* `react-native`.
* See https://github.com/react-native-community/discussions-and-proposals/pull/894.
*/
export const version = {
major: ReactNativeVersion.major,
minor: ReactNativeVersion.minor,
patch: ReactNativeVersion.patch,
prerelease: ReactNativeVersion.prerelease,
};

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import Platform from '../Utilities/Platform';
const ReactNativeVersion = require('./ReactNativeVersion');
/**
* Checks that the version of this React Native JS is compatible with the native
* code, throwing an error if it isn't.
*
* The existence of this module is part of the public interface of React Native
* even though it is used only internally within React Native. React Native
* implementations for other platforms (ex: Windows) may override this module
* and rely on its existence as a separate module.
*/
export function checkVersions(): void {
const nativeVersion = Platform.constants.reactNativeVersion;
if (
ReactNativeVersion.version.major !== nativeVersion.major ||
ReactNativeVersion.version.minor !== nativeVersion.minor
) {
console.error(
`React Native version mismatch.\n\nJavaScript version: ${_formatVersion(
(ReactNativeVersion.version: $FlowFixMe),
)}\n` +
`Native version: ${_formatVersion(nativeVersion)}\n\n` +
'Make sure that you have rebuilt the native code. If the problem ' +
'persists try clearing the Watchman and packager caches with ' +
'`watchman watch-del-all && npx react-native start --reset-cache`.',
);
}
}
function _formatVersion(
version: (typeof Platform)['constants']['reactNativeVersion'],
): string {
return (
`${version.major}.${version.minor}.${version.patch}` +
// eslint-disable-next-line eqeqeq
(version.prerelease != undefined ? `-${version.prerelease}` : '')
);
}

View File

@@ -0,0 +1,14 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
export * from '../../../src/private/specs_DEPRECATED/modules/NativeSegmentFetcher';
import NativeSegmentFetcher from '../../../src/private/specs_DEPRECATED/modules/NativeSegmentFetcher';
export default NativeSegmentFetcher;

View File

@@ -0,0 +1,492 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @deprecated
*/
import NativeTiming from './NativeTiming';
const BatchedBridge = require('../../BatchedBridge/BatchedBridge').default;
const Systrace = require('../../Performance/Systrace');
const invariant = require('invariant');
/**
* JS implementation of timer functions. Must be completely driven by an
* external clock signal, all that's stored here is timerID, timer type, and
* callback.
*/
export type JSTimerType =
| 'setTimeout'
| 'setInterval'
| 'requestAnimationFrame'
| 'queueReactNativeMicrotask'
| 'requestIdleCallback';
// These timing constants should be kept in sync with the ones in native ios and
// android `RCTTiming` module.
const FRAME_DURATION = 1000 / 60;
const IDLE_CALLBACK_FRAME_DEADLINE = 1;
// Parallel arrays
const callbacks: Array<?Function> = [];
const types: Array<?JSTimerType> = [];
const timerIDs: Array<?number> = [];
const freeIdxs: Array<number> = [];
let reactNativeMicrotasks: Array<number> = [];
let requestIdleCallbacks: Array<number> = [];
const requestIdleCallbackTimeouts: {[number]: number, ...} = {};
let GUID = 1;
const errors: Array<Error> = [];
let hasEmittedTimeDriftWarning = false;
// Returns a free index if one is available, and the next consecutive index otherwise.
function _getFreeIndex(): number {
const freeIdx = freeIdxs.pop();
if (freeIdx === undefined) {
return timerIDs.length;
}
return freeIdx;
}
function _allocateCallback(func: Function, type: JSTimerType): number {
const id = GUID++;
const freeIndex = _getFreeIndex();
timerIDs[freeIndex] = id;
callbacks[freeIndex] = func;
types[freeIndex] = type;
return id;
}
/**
* Calls the callback associated with the ID. Also unregister that callback
* if it was a one time timer (setTimeout), and not unregister it if it was
* recurring (setInterval).
*/
function _callTimer(timerID: number, frameTime: number, didTimeout: ?boolean) {
if (timerID > GUID) {
console.warn(
'Tried to call timer with ID %s but no such timer exists.',
timerID,
);
}
// timerIndex of -1 means that no timer with that ID exists. There are
// two situations when this happens, when a garbage timer ID was given
// and when a previously existing timer was deleted before this callback
// fired. In both cases we want to ignore the timer id, but in the former
// case we warn as well.
const timerIndex = timerIDs.indexOf(timerID);
if (timerIndex === -1) {
return;
}
const type = types[timerIndex];
const callback = callbacks[timerIndex];
if (!callback || !type) {
console.error('No callback found for timerID ' + timerID);
return;
}
if (__DEV__) {
Systrace.beginEvent(type + ' [invoke]');
}
// Clear the metadata
if (type !== 'setInterval') {
_clearIndex(timerIndex);
}
try {
if (
type === 'setTimeout' ||
type === 'setInterval' ||
type === 'queueReactNativeMicrotask'
) {
callback();
} else if (type === 'requestAnimationFrame') {
callback(global.performance.now());
} else if (type === 'requestIdleCallback') {
callback({
timeRemaining: function () {
// TODO: Optimisation: allow running for longer than one frame if
// there are no pending JS calls on the bridge from native. This
// would require a way to check the bridge queue synchronously.
return Math.max(
0,
FRAME_DURATION - (global.performance.now() - frameTime),
);
},
didTimeout: !!didTimeout,
});
} else {
console.error('Tried to call a callback with invalid type: ' + type);
}
} catch (e) {
// Don't rethrow so that we can run all timers.
errors.push(e);
}
if (__DEV__) {
Systrace.endEvent();
}
}
/**
* Performs a single pass over the enqueued reactNativeMicrotasks. Returns whether
* more reactNativeMicrotasks are queued up (can be used as a condition a while loop).
*/
function _callReactNativeMicrotasksPass() {
if (reactNativeMicrotasks.length === 0) {
return false;
}
if (__DEV__) {
Systrace.beginEvent('callReactNativeMicrotasksPass()');
}
// The main reason to extract a single pass is so that we can track
// in the system trace
const passReactNativeMicrotasks = reactNativeMicrotasks;
reactNativeMicrotasks = [];
// Use for loop rather than forEach as per @vjeux's advice
// https://github.com/facebook/react-native/commit/c8fd9f7588ad02d2293cac7224715f4af7b0f352#commitcomment-14570051
for (let i = 0; i < passReactNativeMicrotasks.length; ++i) {
_callTimer(passReactNativeMicrotasks[i], 0);
}
if (__DEV__) {
Systrace.endEvent();
}
return reactNativeMicrotasks.length > 0;
}
function _clearIndex(i: number) {
timerIDs[i] = null;
callbacks[i] = null;
types[i] = null;
freeIdxs.push(i);
}
function _freeCallback(timerID: number) {
// timerIDs contains nulls after timers have been removed;
// ignore nulls upfront so indexOf doesn't find them
if (timerID == null) {
return;
}
const index = timerIDs.indexOf(timerID);
// See corresponding comment in `callTimers` for reasoning behind this
if (index !== -1) {
const type = types[index];
_clearIndex(index);
if (
type !== 'queueReactNativeMicrotask' &&
type !== 'requestIdleCallback'
) {
deleteTimer(timerID);
}
}
}
/**
* JS implementation of timer functions. Must be completely driven by an
* external clock signal, all that's stored here is timerID, timer type, and
* callback.
*/
const JSTimers = {
/**
* @param {function} func Callback to be invoked after `duration` ms.
* @param {number} duration Number of milliseconds.
*/
setTimeout: function (
func: Function,
duration: number,
...args: any
): number {
const id = _allocateCallback(
() => func.apply(undefined, args),
'setTimeout',
);
createTimer(id, duration || 0, Date.now(), /* recurring */ false);
return id;
},
/**
* @param {function} func Callback to be invoked every `duration` ms.
* @param {number} duration Number of milliseconds.
*/
setInterval: function (
func: Function,
duration: number,
...args: any
): number {
const id = _allocateCallback(
() => func.apply(undefined, args),
'setInterval',
);
createTimer(id, duration || 0, Date.now(), /* recurring */ true);
return id;
},
/**
* The React Native microtask mechanism is used to back public APIs e.g.
* `queueMicrotask`, `clearImmediate`, and `setImmediate` (which is used by
* the Promise polyfill) when the JSVM microtask mechanism is not used.
*
* @param {function} func Callback to be invoked before the end of the
* current JavaScript execution loop.
*/
queueReactNativeMicrotask: function (func: Function, ...args: any): number {
const id = _allocateCallback(
() => func.apply(undefined, args),
'queueReactNativeMicrotask',
);
reactNativeMicrotasks.push(id);
return id;
},
/**
* @param {function} func Callback to be invoked every frame.
*/
requestAnimationFrame: function (func: Function): any | number {
const id = _allocateCallback(func, 'requestAnimationFrame');
createTimer(id, 1, Date.now(), /* recurring */ false);
return id;
},
/**
* @param {function} func Callback to be invoked every frame and provided
* with time remaining in frame.
* @param {?object} options
*/
requestIdleCallback: function (
func: Function,
options: ?Object,
): any | number {
if (requestIdleCallbacks.length === 0) {
setSendIdleEvents(true);
}
const timeout = options && options.timeout;
const id: number = _allocateCallback(
timeout != null
? (deadline: any) => {
const timeoutId: number = requestIdleCallbackTimeouts[id];
if (timeoutId) {
JSTimers.clearTimeout(timeoutId);
delete requestIdleCallbackTimeouts[id];
}
return func(deadline);
}
: func,
'requestIdleCallback',
);
requestIdleCallbacks.push(id);
if (timeout != null) {
const timeoutId: number = JSTimers.setTimeout(() => {
const index: number = requestIdleCallbacks.indexOf(id);
if (index > -1) {
requestIdleCallbacks.splice(index, 1);
_callTimer(id, global.performance.now(), true);
}
delete requestIdleCallbackTimeouts[id];
if (requestIdleCallbacks.length === 0) {
setSendIdleEvents(false);
}
}, timeout);
requestIdleCallbackTimeouts[id] = timeoutId;
}
return id;
},
cancelIdleCallback: function (timerID: number) {
_freeCallback(timerID);
const index = requestIdleCallbacks.indexOf(timerID);
if (index !== -1) {
requestIdleCallbacks.splice(index, 1);
}
const timeoutId = requestIdleCallbackTimeouts[timerID];
if (timeoutId) {
JSTimers.clearTimeout(timeoutId);
delete requestIdleCallbackTimeouts[timerID];
}
if (requestIdleCallbacks.length === 0) {
setSendIdleEvents(false);
}
},
clearTimeout: function (timerID: number) {
_freeCallback(timerID);
},
clearInterval: function (timerID: number) {
_freeCallback(timerID);
},
clearReactNativeMicrotask: function (timerID: number) {
_freeCallback(timerID);
const index = reactNativeMicrotasks.indexOf(timerID);
if (index !== -1) {
reactNativeMicrotasks.splice(index, 1);
}
},
cancelAnimationFrame: function (timerID: number) {
_freeCallback(timerID);
},
/**
* This is called from the native side. We are passed an array of timerIDs,
* and
*/
callTimers: function (timersToCall: Array<number>): any | void {
invariant(
timersToCall.length !== 0,
'Cannot call `callTimers` with an empty list of IDs.',
);
errors.length = 0;
for (let i = 0; i < timersToCall.length; i++) {
_callTimer(timersToCall[i], 0);
}
const errorCount = errors.length;
if (errorCount > 0) {
if (errorCount > 1) {
// Throw all the other errors in a setTimeout, which will throw each
// error one at a time
for (let ii = 1; ii < errorCount; ii++) {
JSTimers.setTimeout(
((error: Error) => {
throw error;
}).bind(null, errors[ii]),
0,
);
}
}
throw errors[0];
}
},
callIdleCallbacks: function (frameTime: number) {
if (
FRAME_DURATION - (Date.now() - frameTime) <
IDLE_CALLBACK_FRAME_DEADLINE
) {
return;
}
errors.length = 0;
if (requestIdleCallbacks.length > 0) {
const passIdleCallbacks = requestIdleCallbacks;
requestIdleCallbacks = [];
for (let i = 0; i < passIdleCallbacks.length; ++i) {
_callTimer(passIdleCallbacks[i], frameTime);
}
}
if (requestIdleCallbacks.length === 0) {
setSendIdleEvents(false);
}
errors.forEach(error =>
JSTimers.setTimeout(() => {
throw error;
}, 0),
);
},
/**
* This is called after we execute any command we receive from native but
* before we hand control back to native.
*/
callReactNativeMicrotasks() {
errors.length = 0;
while (_callReactNativeMicrotasksPass()) {}
errors.forEach(error =>
JSTimers.setTimeout(() => {
throw error;
}, 0),
);
},
/**
* Called from native (in development) when environment times are out-of-sync.
*/
emitTimeDriftWarning(warningMessage: string) {
if (hasEmittedTimeDriftWarning) {
return;
}
hasEmittedTimeDriftWarning = true;
console.warn(warningMessage);
},
};
function createTimer(
callbackID: number,
duration: number,
jsSchedulingTime: number,
repeats: boolean,
): void {
invariant(NativeTiming, 'NativeTiming is available');
NativeTiming.createTimer(callbackID, duration, jsSchedulingTime, repeats);
}
function deleteTimer(timerID: number): void {
invariant(NativeTiming, 'NativeTiming is available');
NativeTiming.deleteTimer(timerID);
}
function setSendIdleEvents(sendIdleEvents: boolean): void {
invariant(NativeTiming, 'NativeTiming is available');
NativeTiming.setSendIdleEvents(sendIdleEvents);
}
let ExportedJSTimers: {
callIdleCallbacks: (frameTime: number) => any | void,
callReactNativeMicrotasks: () => void,
callTimers: (timersToCall: Array<number>) => any | void,
cancelAnimationFrame: (timerID: number) => void,
cancelIdleCallback: (timerID: number) => void,
clearReactNativeMicrotask: (timerID: number) => void,
clearInterval: (timerID: number) => void,
clearTimeout: (timerID: number) => void,
emitTimeDriftWarning: (warningMessage: string) => any | void,
requestAnimationFrame: (func: any) => any | number,
requestIdleCallback: (func: any, options: ?any) => any | number,
queueReactNativeMicrotask: (func: any, ...args: any) => number,
setInterval: (func: any, duration: number, ...args: any) => number,
setTimeout: (func: any, duration: number, ...args: any) => number,
};
if (!NativeTiming) {
console.warn("Timing native module is not available, can't set timers.");
// $FlowFixMe[incompatible-type] : we can assume timers are generally available
ExportedJSTimers = ({
callReactNativeMicrotasks: JSTimers.callReactNativeMicrotasks,
queueReactNativeMicrotask: JSTimers.queueReactNativeMicrotask,
// $FlowFixMe[incompatible-variance]
}: typeof JSTimers);
} else {
// $FlowFixMe[incompatible-variance]
ExportedJSTimers = JSTimers;
}
BatchedBridge.setReactNativeMicrotasksCallback(
JSTimers.callReactNativeMicrotasks,
);
export default ExportedJSTimers;

View File

@@ -0,0 +1,15 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
* @deprecated
*/
export * from '../../../src/private/specs_DEPRECATED/modules/NativeTiming';
import NativeTiming from '../../../src/private/specs_DEPRECATED/modules/NativeTiming';
export default NativeTiming;

View File

@@ -0,0 +1,62 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @deprecated
*/
'use strict';
// Globally Unique Immediate ID.
let GUIID = 1;
// A global set of the currently cleared immediates.
const clearedImmediates: Set<number> = new Set();
/**
* Shim the setImmediate API on top of queueMicrotask.
* @param {function} func Callback to be invoked before the end of the
* current JavaScript execution loop.
*/
export function setImmediate(callback: Function, ...args: any): number {
if (arguments.length < 1) {
throw new TypeError(
'setImmediate must be called with at least one argument (a function to call)',
);
}
if (typeof callback !== 'function') {
throw new TypeError(
'The first argument to setImmediate must be a function.',
);
}
const id = GUIID++;
// This is an edgey case in which the sequentially assigned ID has been
// "guessed" and "cleared" ahead of time, so we need to clear it up first.
if (clearedImmediates.has(id)) {
clearedImmediates.delete(id);
}
// $FlowFixMe[incompatible-type]
global.queueMicrotask(() => {
if (!clearedImmediates.has(id)) {
callback.apply(undefined, args);
} else {
// Free up the Set entry.
clearedImmediates.delete(id);
}
});
return id;
}
/**
* @param {number} immediateID The ID of the immediate to be clearred.
*/
export function clearImmediate(immediateID: number) {
clearedImmediates.add(immediateID);
}

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
let resolvedPromise;
/**
* Polyfill for the microtask queueing API defined by WHATWG HTML spec.
* https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-queuemicrotask
*
* The method must queue a microtask to invoke @param {function} callback, and
* if the callback throws an exception, report the exception.
*/
export default function queueMicrotask(callback: Function) {
if (arguments.length < 1) {
throw new TypeError(
'queueMicrotask must be called with at least one argument (a function to call)',
);
}
if (typeof callback !== 'function') {
throw new TypeError('The argument to queueMicrotask must be a function.');
}
// Try to reuse a lazily allocated resolved promise from closure.
// $FlowFixMe[constant-condition]
(resolvedPromise || (resolvedPromise = Promise.resolve()))
.then(callback)
.catch(error =>
// Report the exception until the next tick.
setTimeout(() => {
throw error;
}, 0),
);
}

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
/**
* Check for compatibility between the JS and native code.
* You can use this module directly, or just require InitializeCore.
*/
const ReactNativeVersionCheck = require('./ReactNativeVersionCheck');
ReactNativeVersionCheck.checkVersions();

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
const {polyfillGlobal} = require('../Utilities/PolyfillFunctions');
/**
* Set up Promise. The native Promise implementation throws the following error:
* ERROR: Event loop not supported.
*
* If you don't need these polyfills, don't use InitializeCore; just directly
* require the modules you need from InitializeCore for setup.
*/
// If global.Promise is provided by Hermes, we are confident that it can provide
// all the methods needed by React Native, so we can directly use it.
if (global?.HermesInternal?.hasPromise?.()) {
const HermesPromise = global.Promise;
if (__DEV__) {
if (typeof HermesPromise !== 'function') {
console.error('HermesPromise does not exist');
}
global.HermesInternal?.enablePromiseRejectionTracker?.(
require('../promiseRejectionTrackingOptions').default,
);
}
} else {
polyfillGlobal('Promise', () => require('../Promise').default);
}

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
type Module = Object;
type RegisterCallableModule = (
name: string,
moduleOrFactory: Module | (() => Module),
) => void;
export const registerCallableModule: RegisterCallableModule;

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
type Module = {...};
type RegisterCallableModule = (
name: string,
moduleOrFactory: Module | (void => Module),
) => void;
const registerCallableModule: RegisterCallableModule = (function () {
if (global.RN$Bridgeless === true) {
return (name, moduleOrFactory) => {
if (typeof moduleOrFactory === 'function') {
global.RN$registerCallableModule(name, moduleOrFactory);
return;
}
global.RN$registerCallableModule(name, () => moduleOrFactory);
};
}
const BatchedBridge = require('../BatchedBridge/BatchedBridge').default;
return (name, moduleOrFactory) => {
if (typeof moduleOrFactory === 'function') {
BatchedBridge.registerLazyCallableModule(name, moduleOrFactory);
return;
}
BatchedBridge.registerCallableModule(name, moduleOrFactory);
};
})();
export default registerCallableModule;

23
node_modules/react-native/Libraries/Core/setUpAlert.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
/**
* Set up alert().
* You can use this module directly, or just require InitializeCore.
*/
if (!global.alert) {
global.alert = function (text: string) {
// Require Alert on demand. Requiring it too early can lead to issues
// with things like Platform not being fully initialized.
require('../Alert/Alert').default.alert('Alert', '' + text);
};
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
import registerModule from './registerCallableModule';
registerModule('Systrace', () => require('../Performance/Systrace'));
if (!(global.RN$Bridgeless === true)) {
registerModule('JSTimers', () => require('./Timers/JSTimers').default);
}
registerModule('RCTLog', () => require('../Utilities/RCTLog').default);
registerModule(
'RCTDeviceEventEmitter',
() => require('../EventEmitter/RCTDeviceEventEmitter').default,
);
registerModule(
'RCTNativeAppEventEmitter',
() => require('../EventEmitter/RCTNativeAppEventEmitter').default,
);
registerModule(
'GlobalPerformanceLogger',
() => require('../Utilities/GlobalPerformanceLogger').default,
);
if (__DEV__) {
registerModule('HMRClient', () => require('../Utilities/HMRClient').default);
} else {
registerModule(
'HMRClient',
() => require('../Utilities/HMRClientProdShim').default,
);
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import Platform from '../Utilities/Platform';
declare var console: {[string]: $FlowFixMe};
/**
* Sets up developer tools for React Native.
* You can use this module directly, or just require InitializeCore.
*/
if (__DEV__) {
if (!Platform.isTesting) {
const HMRClient = require('../Utilities/HMRClient').default;
// TODO(T214991636): Remove legacy Metro log forwarding
if (console._isPolyfilled) {
// We assume full control over the console and send JavaScript logs to Metro.
(
[
'trace',
'info',
'warn',
'error',
'log',
'group',
'groupCollapsed',
'groupEnd',
'debug',
] as const
).forEach(level => {
const originalFunction = console[level];
console[level] = function (...args: $ReadOnlyArray<mixed>) {
HMRClient.log(level, args);
originalFunction.apply(console, args);
};
});
}
}
require('./setUpReactRefresh');
global[`${global.__METRO_GLOBAL_PREFIX__ ?? ''}__loadBundleAsync`] =
require('./Devtools/loadBundleFromServer').default;
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
if (global.RN$useAlwaysAvailableJSErrorHandling !== true) {
/**
* Sets up the console and exception handling (redbox) for React Native.
* You can use this module directly, or just require InitializeCore.
*/
const ExceptionsManager = require('./ExceptionsManager').default;
ExceptionsManager.installConsoleErrorReporter();
// Set up error handler
if (!global.__fbDisableExceptionsManager) {
const handleError = (e: mixed, isFatal: boolean) => {
try {
ExceptionsManager.handleException(e, isFatal);
} catch (ee) {
console.log('Failed to print error: ', ee.message);
throw e;
}
};
const ErrorUtils = require('../vendor/core/ErrorUtils').default;
ErrorUtils.setGlobalHandler(handleError);
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use client';
'use strict';
/**
* Sets up global variables for React Native.
* You can use this module directly, or just require InitializeCore.
*/
if (global.window === undefined) {
// $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it.
global.window = global;
}
if (global.self === undefined) {
// $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it.
global.self = global;
}
// Set up process
// $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it.
global.process = global.process || {};
// $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it.
global.process.env = global.process.env || {};
if (!global.process.env.NODE_ENV) {
// $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it.
global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production';
}

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
const {polyfillObjectProperty} = require('../Utilities/PolyfillFunctions');
const navigator = global.navigator;
if (navigator === undefined) {
// $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it.
global.navigator = {product: 'ReactNative'};
} else {
// see https://github.com/facebook/react-native/issues/10881
polyfillObjectProperty(navigator, 'product', () => 'ReactNative');
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import setUpPerformanceModern from '../../src/private/setup/setUpPerformanceModern';
import NativePerformance from '../../src/private/webapis/performance/specs/NativePerformance';
// In case if the native implementation of the Performance API is available, use it,
// otherwise fall back to the legacy/default one, which only defines 'Performance.now()'
if (NativePerformance) {
setUpPerformanceModern();
} else {
if (!global.performance) {
// $FlowExpectedError[cannot-write]
global.performance = {
mark: () => {},
clearMarks: () => {},
measure: () => {},
clearMeasures: () => {},
now: () => {
const performanceNow = global.nativePerformanceNow || Date.now;
return performanceNow();
},
};
}
}

View File

@@ -0,0 +1,278 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {Domain} from '../../src/private/devsupport/rndevtools/setUpFuseboxReactDevToolsDispatcher';
import type {Spec as NativeReactDevToolsRuntimeSettingsModuleSpec} from '../../src/private/devsupport/rndevtools/specs/NativeReactDevToolsRuntimeSettingsModule';
if (__DEV__) {
if (typeof global.queueMicrotask !== 'function') {
console.error(
'queueMicrotask should exist before setting up React DevTools.',
);
}
// Keep in sync with ExceptionsManager/installConsoleErrorReporter
// $FlowExpectedError[prop-missing]
if (console._errorOriginal != null) {
console.error(
'ExceptionsManager should be set up after React DevTools to avoid console.error arguments mutation',
);
}
}
if (__DEV__) {
// Register dispatcher on global, which can be used later by Chrome DevTools frontend
require('../../src/private/devsupport/rndevtools/setUpFuseboxReactDevToolsDispatcher');
const {
initialize,
connectToDevTools,
connectWithCustomMessagingProtocol,
} = require('react-devtools-core');
const reactDevToolsSettingsManager = require('../../src/private/devsupport/rndevtools/ReactDevToolsSettingsManager');
const serializedHookSettings =
reactDevToolsSettingsManager.getGlobalHookSettings();
const maybeReactDevToolsRuntimeSettingsModuleModule =
require('../../src/private/devsupport/rndevtools/specs/NativeReactDevToolsRuntimeSettingsModule').default;
let hookSettings = null;
if (serializedHookSettings != null) {
try {
const parsedSettings = JSON.parse(serializedHookSettings);
hookSettings = parsedSettings;
} catch {
console.error(
'Failed to parse persisted React DevTools hook settings. React DevTools will be initialized with default settings.',
);
}
}
const {
isProfiling: shouldStartProfilingNow,
profilingSettings: initialProfilingSettings,
} = readReloadAndProfileConfig(maybeReactDevToolsRuntimeSettingsModuleModule);
// Install hook before React is loaded.
initialize(hookSettings, shouldStartProfilingNow, initialProfilingSettings);
// This should be defined in DEV, otherwise error is expected.
const fuseboxReactDevToolsDispatcher =
global.__FUSEBOX_REACT_DEVTOOLS_DISPATCHER__;
const reactDevToolsFuseboxGlobalBindingName =
fuseboxReactDevToolsDispatcher.BINDING_NAME;
const ReactNativeStyleAttributes =
require('../Components/View/ReactNativeStyleAttributes').default;
const resolveRNStyle = require('../StyleSheet/flattenStyle').default;
function handleReactDevToolsSettingsUpdate(settings: Object) {
reactDevToolsSettingsManager.setGlobalHookSettings(
JSON.stringify(settings),
);
}
let disconnect = null;
function disconnectBackendFromReactDevToolsInFuseboxIfNeeded() {
if (disconnect != null) {
disconnect();
disconnect = null;
}
}
function connectToReactDevToolsInFusebox(domain: Domain) {
const {
isReloadAndProfileSupported,
isProfiling,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
} = readReloadAndProfileConfig(
maybeReactDevToolsRuntimeSettingsModuleModule,
);
disconnect = connectWithCustomMessagingProtocol({
onSubscribe: listener => {
domain.onMessage.addEventListener(listener);
},
onUnsubscribe: listener => {
domain.onMessage.removeEventListener(listener);
},
onMessage: (event, payload) => {
domain.sendMessage({event, payload});
},
nativeStyleEditorValidAttributes: Object.keys(ReactNativeStyleAttributes),
resolveRNStyle,
onSettingsUpdated: handleReactDevToolsSettingsUpdate,
isReloadAndProfileSupported,
isProfiling,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
});
}
let isWebSocketOpen = false;
let ws = null;
function connectToWSBasedReactDevToolsFrontend() {
if (ws !== null && isWebSocketOpen) {
// If the DevTools backend is already connected, don't recreate the WebSocket.
// This would break the connection.
// If there isn't an active connection, a backend may be waiting to connect,
// in which case it's okay to make a new one.
return;
}
// not when debugging in chrome
// TODO(t12832058) This check is broken
if (!window.document) {
const AppState = require('../AppState/AppState').default;
const getDevServer = require('./Devtools/getDevServer').default;
// Don't steal the DevTools from currently active app.
// Note: if you add any AppState subscriptions to this file,
// you will also need to guard against `AppState.isAvailable`,
// or the code will throw for bundles that don't have it.
const isAppActive = () => AppState.currentState !== 'background';
// Get hostname from development server (packager)
const devServer = getDevServer();
const host = devServer.bundleLoadedFromServer
? guessHostFromDevServerUrl(devServer.url)
: 'localhost';
// Read the optional global variable for backward compatibility.
// It was added in https://github.com/facebook/react-native/commit/bf2b435322e89d0aeee8792b1c6e04656c2719a0.
const port =
// $FlowFixMe[prop-missing]
// $FlowFixMe[incompatible-use]
window.__REACT_DEVTOOLS_PORT__ != null
? window.__REACT_DEVTOOLS_PORT__
: 8097;
const WebSocket = require('../WebSocket/WebSocket').default;
ws = new WebSocket('ws://' + host + ':' + port);
ws.addEventListener('close', event => {
isWebSocketOpen = false;
});
ws.addEventListener('open', event => {
isWebSocketOpen = true;
});
const {
isReloadAndProfileSupported,
isProfiling,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
} = readReloadAndProfileConfig(
maybeReactDevToolsRuntimeSettingsModuleModule,
);
connectToDevTools({
isAppActive,
resolveRNStyle,
nativeStyleEditorValidAttributes: Object.keys(
ReactNativeStyleAttributes,
),
websocket: ws,
onSettingsUpdated: handleReactDevToolsSettingsUpdate,
isReloadAndProfileSupported,
isProfiling,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
});
}
}
// 1. If React DevTools has already been opened and initialized in Fusebox, bindings survive reloads
if (global[reactDevToolsFuseboxGlobalBindingName] != null) {
disconnectBackendFromReactDevToolsInFuseboxIfNeeded();
const domain =
fuseboxReactDevToolsDispatcher.initializeDomain('react-devtools');
connectToReactDevToolsInFusebox(domain);
}
// 2. If React DevTools panel in Fusebox was opened for the first time after the runtime has been created
// 2. OR if React DevTools frontend was re-initialized: Chrome DevTools was closed and then re-opened
global.__FUSEBOX_REACT_DEVTOOLS_DISPATCHER__.onDomainInitialization.addEventListener(
(domain: Domain) => {
if (domain.name === 'react-devtools') {
disconnectBackendFromReactDevToolsInFuseboxIfNeeded();
connectToReactDevToolsInFusebox(domain);
}
},
);
// 3. Fallback to attempting to connect WS-based RDT frontend
const RCTNativeAppEventEmitter =
require('../EventEmitter/RCTNativeAppEventEmitter').default;
RCTNativeAppEventEmitter.addListener(
'RCTDevMenuShown',
connectToWSBasedReactDevToolsFrontend,
);
connectToWSBasedReactDevToolsFrontend(); // Try connecting once on load
}
function readReloadAndProfileConfig(
maybeModule: ?NativeReactDevToolsRuntimeSettingsModuleSpec,
) {
const isReloadAndProfileSupported = maybeModule != null;
const config = maybeModule?.getReloadAndProfileConfig();
const isProfiling = config?.shouldReloadAndProfile === true;
const profilingSettings = {
recordChangeDescriptions: config?.recordChangeDescriptions === true,
recordTimeline: false,
};
const onReloadAndProfile = (recordChangeDescriptions: boolean) => {
if (maybeModule == null) {
return;
}
maybeModule.setReloadAndProfileConfig({
shouldReloadAndProfile: true,
recordChangeDescriptions,
});
};
const onReloadAndProfileFlagsReset = () => {
if (maybeModule == null) {
return;
}
maybeModule.setReloadAndProfileConfig({
shouldReloadAndProfile: false,
recordChangeDescriptions: false,
});
};
return {
isReloadAndProfileSupported,
isProfiling,
profilingSettings,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
};
}
/**
* This is a bad, no good, broken hack to get the host from a dev server URL for the purposes
* of connecting to the legacy React DevTools socket (for the standalone react-devtools package).
* It has too many bugs to list. Please don't use it in new code.
*
* The correct implementation would just be `return new URL(url).host`, but React Native does not
* ship with a spec-compliant `URL` class yet. Alternatively, this can be deleted when we delete
* `connectToWSBasedReactDevToolsFrontend`.
*/
function guessHostFromDevServerUrl(url: string): string {
const hopefullyHostAndPort = url
.replace(/https?:\/\//, '')
.replace(/\/$/, '');
// IPv6 addresses contain colons, so the split(':') below will return garbage.
if (hopefullyHostAndPort.includes(']')) {
return hopefullyHostAndPort.split(']')[0] + ']';
}
return hopefullyHostAndPort.split(':')[0];
}

View File

@@ -0,0 +1,47 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
if (__DEV__) {
const DevSettings = require('../Utilities/DevSettings').default;
if (typeof DevSettings.reload !== 'function') {
throw new Error('Could not find the reload() implementation.');
}
// This needs to run before the renderer initializes.
const ReactRefreshRuntime = require('react-refresh/runtime');
ReactRefreshRuntime.injectIntoGlobalHook(global);
const Refresh = {
performFullRefresh(reason: string) {
DevSettings.reload(reason);
},
createSignatureFunctionForTransform:
ReactRefreshRuntime.createSignatureFunctionForTransform,
isLikelyComponentType: ReactRefreshRuntime.isLikelyComponentType,
getFamilyByType: ReactRefreshRuntime.getFamilyByType,
register: ReactRefreshRuntime.register,
performReactRefresh() {
ReactRefreshRuntime.performReactRefresh();
DevSettings.onFastRefresh();
},
};
// The metro require polyfill can not have dependencies (applies for all polyfills).
// Expose `Refresh` by assigning it to global to make it available in the polyfill.
global[(global.__METRO_GLOBAL_PREFIX__ || '') + '__ReactRefresh'] = Refresh;
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
const {hasNativeConstructor} = require('../Utilities/FeatureDetection');
const {polyfillGlobal} = require('../Utilities/PolyfillFunctions');
/**
* Set up regenerator.
* You can use this module directly, or just require InitializeCore.
*/
let hasNativeGenerator;
try {
// If this function was lowered by regenerator-transform, it will try to
// access `global.regeneratorRuntime` which doesn't exist yet and will throw.
hasNativeGenerator = hasNativeConstructor(
function* () {},
'GeneratorFunction',
);
} catch {
// In this case, we know generators are not provided natively.
hasNativeGenerator = false;
}
// If generators are provided natively, which suggests that there was no
// regenerator-transform, then there is no need to set up the runtime.
if (!hasNativeGenerator) {
polyfillGlobal('regeneratorRuntime', () => {
// The require just sets up the global, so make sure when we first
// invoke it the global does not exist
delete global.regeneratorRuntime;
// regenerator-runtime/runtime exports the regeneratorRuntime object, so we
// can return it safely.
return require('regenerator-runtime/runtime'); // flowlint-line untyped-import:off
});
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
export type FetchSegmentFunction = typeof __fetchSegment;
/**
* Set up SegmentFetcher.
* You can use this module directly, or just require InitializeCore.
*/
function __fetchSegment(
segmentId: number,
options: $ReadOnly<{
otaBuildNumber: ?string,
requestedModuleName: string,
segmentHash: string,
}>,
callback: (?Error) => void,
) {
const SegmentFetcher =
require('./SegmentFetcher/NativeSegmentFetcher').default;
SegmentFetcher.fetchSegment(
segmentId,
options,
(
errorObject: ?{
message: string,
code: string,
...
},
) => {
if (errorObject) {
const error = new Error(errorObject.message);
(error: any).code = errorObject.code; // flowlint-line unclear-type: off
callback(error);
return;
}
callback(null);
},
);
}
global.__fetchSegment = __fetchSegment;

104
node_modules/react-native/Libraries/Core/setUpTimers.js generated vendored Normal file
View File

@@ -0,0 +1,104 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
const {polyfillGlobal} = require('../Utilities/PolyfillFunctions');
if (__DEV__) {
if (typeof global.Promise !== 'function') {
console.error('Promise should exist before setting up timers.');
}
}
// In bridgeless mode, timers are host functions installed from cpp.
if (global.RN$Bridgeless === true) {
// This is the flag that tells React to use `queueMicrotask` to batch state
// updates, instead of using the scheduler to schedule a regular task.
// We use a global variable because we don't currently have any other
// mechanism to pass feature flags from RN to React in OSS.
global.RN$enableMicrotasksInReact = true;
polyfillGlobal(
'queueMicrotask',
() =>
require('../../src/private/webapis/microtasks/specs/NativeMicrotasks')
.default.queueMicrotask,
);
// We shim the immediate APIs via `queueMicrotask` to maintain the backward
// compatibility.
polyfillGlobal(
'setImmediate',
() => require('./Timers/immediateShim').setImmediate,
);
polyfillGlobal(
'clearImmediate',
() => require('./Timers/immediateShim').clearImmediate,
);
polyfillGlobal(
'requestIdleCallback',
() =>
require('../../src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks')
.default.requestIdleCallback,
);
polyfillGlobal(
'cancelIdleCallback',
() =>
require('../../src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks')
.default.cancelIdleCallback,
);
} else {
/**
* Set up timers.
* You can use this module directly, or just require InitializeCore.
*/
const defineLazyTimer = (
name:
| 'cancelAnimationFrame'
| 'cancelIdleCallback'
| 'clearInterval'
| 'clearTimeout'
| 'requestAnimationFrame'
| 'requestIdleCallback'
| 'setInterval'
| 'setTimeout',
) => {
polyfillGlobal(name, () => require('./Timers/JSTimers').default[name]);
};
defineLazyTimer('setTimeout');
defineLazyTimer('clearTimeout');
defineLazyTimer('setInterval');
defineLazyTimer('clearInterval');
defineLazyTimer('requestAnimationFrame');
defineLazyTimer('cancelAnimationFrame');
defineLazyTimer('requestIdleCallback');
defineLazyTimer('cancelIdleCallback');
// Polyfill it with promise (regardless it's polyfilled or native) otherwise.
polyfillGlobal(
'queueMicrotask',
() => require('./Timers/queueMicrotask.js').default,
);
// When promise was polyfilled hence is queued to the RN microtask queue,
// we polyfill the immediate APIs as aliases to the ReactNativeMicrotask APIs.
// Note that in bridgeless mode, immediate APIs are installed from cpp.
polyfillGlobal(
'setImmediate',
() => require('./Timers/JSTimers').default.queueReactNativeMicrotask,
);
polyfillGlobal(
'clearImmediate',
() => require('./Timers/JSTimers').default.clearReactNativeMicrotask,
);
}

44
node_modules/react-native/Libraries/Core/setUpXHR.js generated vendored Normal file
View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
const {polyfillGlobal} = require('../Utilities/PolyfillFunctions');
/**
* Set up XMLHttpRequest. The native XMLHttpRequest in Chrome dev tools is CORS
* aware and won't let you fetch anything from the internet.
*
* You can use this module directly, or just require InitializeCore.
*/
polyfillGlobal(
'XMLHttpRequest',
() => require('../Network/XMLHttpRequest').default,
);
polyfillGlobal('FormData', () => require('../Network/FormData').default);
polyfillGlobal('fetch', () => require('../Network/fetch').fetch);
polyfillGlobal('Headers', () => require('../Network/fetch').Headers);
polyfillGlobal('Request', () => require('../Network/fetch').Request);
polyfillGlobal('Response', () => require('../Network/fetch').Response);
polyfillGlobal('WebSocket', () => require('../WebSocket/WebSocket').default);
polyfillGlobal('Blob', () => require('../Blob/Blob').default);
polyfillGlobal('File', () => require('../Blob/File').default);
polyfillGlobal('FileReader', () => require('../Blob/FileReader').default);
polyfillGlobal('URL', () => require('../Blob/URL').URL);
polyfillGlobal('URLSearchParams', () => require('../Blob/URL').URLSearchParams);
polyfillGlobal(
'AbortController',
() => require('abort-controller/dist/abort-controller').AbortController, // flowlint-line untyped-import:off
);
polyfillGlobal(
'AbortSignal',
() => require('abort-controller/dist/abort-controller').AbortSignal, // flowlint-line untyped-import:off
);