diff --git a/.gitignore b/.gitignore index 67f3212..1134bfe 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,9 @@ android/keystores/debug.keystore # generated by bob lib/ +# Polyfills build output +packages/polyfills/dist/ + # React Native Codegen ios/generated android/generated diff --git a/cpp/Polyfills.h b/cpp/Polyfills.h new file mode 100644 index 0000000..1e343d5 --- /dev/null +++ b/cpp/Polyfills.h @@ -0,0 +1,35 @@ +// Auto-generated file - DO NOT EDIT +// Generated by: packages/polyfills/scripts/generate-header.js + +#pragma once + +namespace webworker { + +constexpr const char* kPolyfillScript = R"POLYFILL( +var __BUNDLE_START_TIME__=globalThis.nativePerformanceNow?nativePerformanceNow():Date.now(),__DEV__=false,process=globalThis.process||{},__METRO_GLOBAL_PREFIX__='';process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||"production"; +!(function(e){"use strict";e.__r=i,e[`${__METRO_GLOBAL_PREFIX__}__d`]=function(e,o,n){if(r.has(o))return;var i={dependencyMap:n,factory:e,hasError:!1,importedAll:t,importedDefault:t,isInitialized:!1,publicModule:{exports:{}}};r.set(o,i)},e.__c=n,e.__registerSegment=function(e,t,o){s[e]=t,o&&o.forEach(t=>{r.has(t)||v.has(t)||v.set(t,e)})};var r=n(),t={},o={}.hasOwnProperty;function n(){return r=new Map}function i(e,t){if(null===e)throw new Error("Cannot find module");var o=e,n=r.get(o);return n&&n.isInitialized?n.publicModule.exports:d(o,n)}function a(e){var o=e,n=r.get(o);if(n&&n.importedDefault!==t)return n.importedDefault;var a=i(o),l=a&&a.__esModule?a.default:a;return r.get(o).importedDefault=l}function l(e){var n=e,a=r.get(n);if(a&&a.importedAll!==t)return a.importedAll;var l,u=i(n);if(u&&u.__esModule)l=u;else{if(l={},u)for(var d in u)o.call(u,d)&&(l[d]=u[d]);l.default=u}return r.get(n).importedAll=l}i.importDefault=a,i.importAll=l,i.context=function(){throw new Error("The experimental Metro feature `require.context` is not enabled in your project.")},i.resolveWeak=function(){throw new Error("require.resolveWeak cannot be called dynamically.")};var u=!1;function d(r,t){if(!u&&e.ErrorUtils){var o;u=!0;try{o=h(r,t)}catch(r){e.ErrorUtils.reportFatalError(r)}return u=!1,o}return h(r,t)}var f=16,c=65535;function p(e){return{segmentId:e>>>f,localId:e&c}}i.unpackModuleId=p,i.packModuleId=function(e){return(e.segmentId<0){var n=v.get(t)??0,u=s[n];null!=u&&(u(t),o=r.get(t),v.delete(t))}var d=e.nativeRequire;if(!o&&d){var f=p(t),c=f.segmentId;d(f.localId,c),o=r.get(t)}if(!o)throw Error('Requiring unknown module "'+t+'".');if(o.hasError)throw o.error;o.isInitialized=!0;var h=o,g=h.factory,m=h.dependencyMap;try{var _=o.publicModule;return _.id=t,g(e,i,a,l,_,_.exports,m),o.factory=void 0,o.dependencyMap=void 0,_.exports}catch(e){throw o.hasError=!0,o.error=e,o.isInitialized=!1,o.publicModule.exports=void 0,e}}})('undefined'!=typeof globalThis?globalThis:'undefined'!=typeof global?global:'undefined'!=typeof window?window:this); +__d(function(g,r,i,a,m,e,d){r(d[0])},0,[1]); +__d(function(_g,r,i,a,m,e,d){"use strict";var o=r(d[0]),n="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==_g?_g:void 0;n&&(void 0===n.AbortController&&(n.AbortController=o.AbortController),void 0===n.AbortSignal&&(n.AbortSignal=o.AbortSignal))},1,[2]); +__d(function(g,r,i,a,m,_e,d){'use strict';var t=r(d[0]),e=t(r(d[1])),o=t(r(d[2])),n=t(r(d[3])),l=t(r(d[4])),u=t(r(d[5]));function c(){try{var t=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(t){}return(c=function(){return!!t})()}Object.defineProperty(_e,'__esModule',{value:!0});var f=r(d[6]),b=(function(t){function f(){var t,o,u;throw(0,e.default)(this,f),t=this,o=f,o=(0,l.default)(o),(0,n.default)(t,c()?Reflect.construct(o,u||[],(0,l.default)(t).constructor):o.apply(t,u)),new TypeError("AbortSignal cannot be constructed directly")}return(0,u.default)(f,t),(0,o.default)(f,[{key:"aborted",get:function(){var t=p.get(this);if("boolean"!=typeof t)throw new TypeError("Expected 'this' to be an 'AbortSignal' object, but got "+(null===this?"null":typeof this));return t}}])})(f.EventTarget);f.defineEventAttribute(b.prototype,"abort");var p=new WeakMap;Object.defineProperties(b.prototype,{aborted:{enumerable:!0}}),"function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag&&Object.defineProperty(b.prototype,Symbol.toStringTag,{configurable:!0,value:"AbortSignal"});var y=(function(){return(0,o.default)(function t(){var o;(0,e.default)(this,t),s.set(this,(o=Object.create(b.prototype),f.EventTarget.call(o),p.set(o,!1),o))},[{key:"signal",get:function(){return v(this)}},{key:"abort",value:function(){var t;t=v(this),!1===p.get(t)&&(p.set(t,!0),t.dispatchEvent({type:"abort"}))}}])})(),s=new WeakMap;function v(t){var e=s.get(t);if(null==e)throw new TypeError("Expected 'this' to be an 'AbortController' object, but got "+(null===t?"null":typeof t));return e}Object.defineProperties(y.prototype,{signal:{enumerable:!0},abort:{enumerable:!0}}),"function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag&&Object.defineProperty(y.prototype,Symbol.toStringTag,{configurable:!0,value:"AbortController"}),_e.AbortController=y,_e.AbortSignal=b,_e.default=y,m.exports=y,m.exports.AbortController=m.exports.default=y,m.exports.AbortSignal=b},2,[3,4,5,9,11,12,14]); +__d(function(g,r,i,a,m,_e,d){m.exports=function(e){return e&&e.__esModule?e:{default:e}},m.exports.__esModule=!0,m.exports.default=m.exports},3,[]); +__d(function(g,r,i,_a,m,e,d){m.exports=function(o,n){if(!(o instanceof n))throw new TypeError("Cannot call a class as a function")},m.exports.__esModule=!0,m.exports.default=m.exports},4,[]); +__d(function(g,_r,i,a,m,_e,d){var e=_r(d[0]);function r(r,t){for(var o=0;o + * @copyright 2015 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict';Object.defineProperty(e,'__esModule',{value:!0});var t=new WeakMap,n=new WeakMap;function o(n){var o=t.get(n);return console.assert(null!=o,"'this' is expected an Event object, but got",n),o}function i(t){null==t.passiveListener?t.event.cancelable&&(t.canceled=!0,"function"==typeof t.event.preventDefault&&t.event.preventDefault()):"undefined"!=typeof console&&"function"==typeof console.error&&console.error("Unable to preventDefault inside passive event listener invocation.",t.passiveListener)}function l(n,o){t.set(this,{eventTarget:n,event:o,eventPhase:2,currentTarget:n,canceled:!1,stopped:!1,immediateStopped:!1,passiveListener:null,timeStamp:o.timeStamp||Date.now()}),Object.defineProperty(this,"isTrusted",{value:!1,enumerable:!0});for(var i=Object.keys(o),l=0;l0){for(var t=new Array(arguments.length),n=0;n #include @@ -304,6 +305,12 @@ void WorkerRuntime::setupGlobalScope() { try { Runtime& runtime = *hermesRuntime_; + // Execute polyfills first (TextEncoder, URL, AbortController, etc.) + runtime.evaluateJavaScript( + std::make_shared(kPolyfillScript), + "polyfills.js" + ); + std::string initScript = R"( var self = this; var global = this; diff --git a/docs/POLYFILLS.md b/docs/POLYFILLS.md new file mode 100644 index 0000000..9f81ee4 --- /dev/null +++ b/docs/POLYFILLS.md @@ -0,0 +1,42 @@ +# Polyfills in web workers + +The `react-native-webworker` library includes built-in polyfills to provide essential web APIs that are missing from Hermes. Every worker automatically gets these polyfills loaded before your code runs. + +## What it does + +Every worker comes with polyfills for APIs that Hermes doesn't implement but that web developers expect. Behind the scenes, it uses proven polyfill libraries to provide: + +- **AbortController** - Cancel asynchronous operations +- *(Room for future polyfills)* + +This ensures your worker code can use modern JavaScript APIs without worrying about Hermes compatibility. + +## Adding new polyfills + +You can easily extend the polyfill bundle by adding new APIs: + +### Adding a polyfill + +1. Install the polyfill package: + +```bash +cd packages/polyfills +yarn add text-encoding-polyfill +``` + +2. Import it in the source file: + +```javascript +// packages/polyfills/src/index.js +import 'abort-controller/polyfill'; +import 'text-encoding-polyfill'; // New polyfill +``` + +3. Rebuild the polyfills: + +```bash +cd packages/polyfills +yarn build +``` + +The new polyfill will be automatically available in all workers. diff --git a/example/src/__tests__/polyfills.harness.ts b/example/src/__tests__/polyfills.harness.ts new file mode 100644 index 0000000..03c1e2d --- /dev/null +++ b/example/src/__tests__/polyfills.harness.ts @@ -0,0 +1,52 @@ +import { afterEach, describe, it, expect } from 'react-native-harness'; +import { Worker } from 'react-native-webworker'; + +// Helper to prevent tests from hanging indefinitely +function withTimeout( + promise: Promise, + ms: number = 2000, + msg: string = 'Operation timed out' +): Promise { + return Promise.race([ + promise, + new Promise((_, reject) => setTimeout(() => reject(new Error(msg)), ms)), + ]); +} + +describe('Polyfills', () => { + let worker: Worker; + + afterEach(() => { + worker.terminate(); + }); + + it('should add AbortController to the global object', async () => { + worker = new Worker({ + script: ` + self.onmessage = function(event) { + self.postMessage(typeof AbortController); + }; + `, + name: 'test-worker', + }); + + const responsePromise = new Promise((resolve, reject) => { + worker.onmessage = (event) => { + resolve(event.data as string); + }; + worker.onerror = (err) => { + reject(err); + }; + }); + + await worker.postMessage('start'); + + const result = await withTimeout( + responsePromise, + 2000, + 'Worker did not respond with AbortController type' + ); + + expect(result).toBe('function'); + }); +}); diff --git a/package.json b/package.json index 77de0d0..dfe0ffe 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,8 @@ "react-native": "*" }, "workspaces": [ - "example" + "example", + "packages/*" ], "packageManager": "yarn@4.11.0", "react-native-builder-bob": { diff --git a/packages/polyfills/babel.config.js b/packages/polyfills/babel.config.js new file mode 100644 index 0000000..3282daa --- /dev/null +++ b/packages/polyfills/babel.config.js @@ -0,0 +1,11 @@ +module.exports = { + presets: [ + [ + '@react-native/babel-preset', + { + // Use hermes-stable profile to ensure all incompatible constructs are transformed + unstable_transformProfile: 'hermes-stable', + }, + ], + ], +}; diff --git a/packages/polyfills/metro.config.js b/packages/polyfills/metro.config.js new file mode 100644 index 0000000..7fae7e3 --- /dev/null +++ b/packages/polyfills/metro.config.js @@ -0,0 +1,13 @@ +const path = require('path'); + +module.exports = { + // Project configuration + projectRoot: __dirname, + watchFolders: [__dirname], + + // Resolver configuration + resolver: { + sourceExts: ['js', 'mjs', 'cjs', 'json'], + nodeModulesPaths: [path.join(__dirname, 'node_modules')], + }, +}; diff --git a/packages/polyfills/package.json b/packages/polyfills/package.json new file mode 100644 index 0000000..2d68470 --- /dev/null +++ b/packages/polyfills/package.json @@ -0,0 +1,31 @@ +{ + "name": "@react-native-webworker/polyfills", + "description": "Polyfills for React Native WebWorker", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "node scripts/build.js && node scripts/generate-header.js" + }, + "devDependencies": { + "@babel/core": "^7.20.0", + "@react-native/babel-preset": "^0.83.0", + "metro": "^0.83.0", + "metro-babel-transformer": "^0.83.0", + "metro-minify-terser": "^0.83.0", + "metro-resolver": "^0.83.0", + "abort-controller": "3.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/V3RON/react-native-webworker.git" + }, + "author": "Szymon Chmal (https://github.com/V3RON)", + "license": "MIT", + "bugs": { + "url": "https://github.com/V3RON/react-native-webworker/issues" + }, + "homepage": "https://github.com/V3RON/react-native-webworker#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + } +} diff --git a/packages/polyfills/scripts/build.js b/packages/polyfills/scripts/build.js new file mode 100644 index 0000000..c466f5c --- /dev/null +++ b/packages/polyfills/scripts/build.js @@ -0,0 +1,31 @@ +const Metro = require('metro'); +const path = require('path'); +const fs = require('fs'); + +async function build() { + const projectRoot = path.join(__dirname, '..'); + const distDir = path.join(projectRoot, 'dist'); + + if (!fs.existsSync(distDir)) { + fs.mkdirSync(distDir, { recursive: true }); + } + + const config = await Metro.loadConfig({ + config: path.join(projectRoot, 'metro.config.js'), + }); + + await Metro.runBuild(config, { + entry: path.join(projectRoot, 'src/index.js'), + out: path.join(distDir, 'polyfills.bundle.js'), + platform: 'ios', + minify: true, + dev: false, + }); + + console.log('Bundle created: dist/polyfills.bundle.js'); +} + +build().catch((error) => { + console.error('Build failed:', error); + process.exit(1); +}); diff --git a/packages/polyfills/scripts/generate-header.js b/packages/polyfills/scripts/generate-header.js new file mode 100644 index 0000000..40ec1d9 --- /dev/null +++ b/packages/polyfills/scripts/generate-header.js @@ -0,0 +1,45 @@ +const fs = require('fs'); +const path = require('path'); + +const bundlePath = path.join(__dirname, '..', 'dist', 'polyfills.bundle.js'); +const headerPath = path.join(__dirname, '..', 'dist', 'Polyfills.h'); +const cppTargetPath = path.join( + __dirname, + '..', + '..', + '..', + 'cpp', + 'Polyfills.h' +); + +const bundleContent = fs.readFileSync(bundlePath, 'utf-8'); + +// Use a delimiter that won't appear in the minified JS bundle +// R"POLYFILL(...)POLYFILL" allows the content to contain )" sequences +const header = `// Auto-generated file - DO NOT EDIT +// Generated by: packages/polyfills/scripts/generate-header.js + +#pragma once + +namespace webworker { + +constexpr const char* kPolyfillScript = R"POLYFILL( +${bundleContent} +)POLYFILL"; + +} // namespace webworker +`; + +// Ensure dist directory exists +const distDir = path.dirname(headerPath); +if (!fs.existsSync(distDir)) { + fs.mkdirSync(distDir, { recursive: true }); +} + +// Write to dist/ +fs.writeFileSync(headerPath, header); +console.log('Header created: dist/Polyfills.h'); + +// Copy to cpp/ +fs.copyFileSync(headerPath, cppTargetPath); +console.log('Header copied to: cpp/Polyfills.h'); diff --git a/packages/polyfills/src/index.js b/packages/polyfills/src/index.js new file mode 100644 index 0000000..75ba527 --- /dev/null +++ b/packages/polyfills/src/index.js @@ -0,0 +1,9 @@ +/** + * Polyfills for Hermes WebWorker environment + * + * This file imports and installs polyfills for APIs that are missing in Hermes. + * It is bundled into a single file and executed before any user code in workers. + */ + +// AbortController polyfill +import 'abort-controller/polyfill'; diff --git a/turbo.json b/turbo.json index 8b2bf08..df01a91 100644 --- a/turbo.json +++ b/turbo.json @@ -3,12 +3,27 @@ "globalDependencies": [".nvmrc", ".yarnrc.yml"], "globalEnv": ["NODE_ENV"], "tasks": { + "build:polyfills": { + "inputs": [ + "packages/polyfills/src/**", + "packages/polyfills/package.json", + "packages/polyfills/babel.config.js", + "packages/polyfills/scripts/**" + ], + "outputs": [ + "packages/polyfills/dist/**", + "cpp/Polyfills.h" + ], + "cache": true + }, "build:android": { + "dependsOn": ["build:polyfills"], "env": ["ANDROID_HOME", "ORG_GRADLE_PROJECT_newArchEnabled"], "inputs": [ "package.json", "android", "!android/build", + "cpp", "src/*.ts", "src/*.tsx", "example/package.json", @@ -20,6 +35,7 @@ "outputs": [] }, "build:ios": { + "dependsOn": ["build:polyfills"], "env": [ "RCT_NEW_ARCH_ENABLED", "RCT_REMOVE_LEGACY_ARCH", @@ -30,6 +46,7 @@ "package.json", "*.podspec", "ios", + "cpp", "src/*.ts", "src/*.tsx", "example/package.json", diff --git a/yarn.lock b/yarn.lock index 71cbbb7..6a1181f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,7 +39,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.4, @babel/core@npm:^7.25.2": +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.20.0, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.4, @babel/core@npm:^7.25.2": version: 7.28.5 resolution: "@babel/core@npm:7.28.5" dependencies: @@ -3126,6 +3126,20 @@ __metadata: languageName: node linkType: hard +"@react-native-webworker/polyfills@workspace:packages/polyfills": + version: 0.0.0-use.local + resolution: "@react-native-webworker/polyfills@workspace:packages/polyfills" + dependencies: + "@babel/core": "npm:^7.20.0" + "@react-native/babel-preset": "npm:^0.83.0" + abort-controller: "npm:3.0.0" + metro: "npm:^0.83.0" + metro-babel-transformer: "npm:^0.83.0" + metro-minify-terser: "npm:^0.83.0" + metro-resolver: "npm:^0.83.0" + languageName: unknown + linkType: soft + "@react-native/assets-registry@npm:0.83.0": version: 0.83.0 resolution: "@react-native/assets-registry@npm:0.83.0" @@ -3143,6 +3157,16 @@ __metadata: languageName: node linkType: hard +"@react-native/babel-plugin-codegen@npm:0.83.1": + version: 0.83.1 + resolution: "@react-native/babel-plugin-codegen@npm:0.83.1" + dependencies: + "@babel/traverse": "npm:^7.25.3" + "@react-native/codegen": "npm:0.83.1" + checksum: 10c0/fa08bf71cf4f4f70d8a0167ad8f91b47e270ab2879e745d63ce599406f9bb92b38100b9e0cea42dff8f8f17a5ea64826921f73f04535b4f09b77e53376cc043d + languageName: node + linkType: hard + "@react-native/babel-preset@npm:0.83.0": version: 0.83.0 resolution: "@react-native/babel-preset@npm:0.83.0" @@ -3198,6 +3222,61 @@ __metadata: languageName: node linkType: hard +"@react-native/babel-preset@npm:^0.83.0": + version: 0.83.1 + resolution: "@react-native/babel-preset@npm:0.83.1" + dependencies: + "@babel/core": "npm:^7.25.2" + "@babel/plugin-proposal-export-default-from": "npm:^7.24.7" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + "@babel/plugin-syntax-export-default-from": "npm:^7.24.7" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + "@babel/plugin-transform-arrow-functions": "npm:^7.24.7" + "@babel/plugin-transform-async-generator-functions": "npm:^7.25.4" + "@babel/plugin-transform-async-to-generator": "npm:^7.24.7" + "@babel/plugin-transform-block-scoping": "npm:^7.25.0" + "@babel/plugin-transform-class-properties": "npm:^7.25.4" + "@babel/plugin-transform-classes": "npm:^7.25.4" + "@babel/plugin-transform-computed-properties": "npm:^7.24.7" + "@babel/plugin-transform-destructuring": "npm:^7.24.8" + "@babel/plugin-transform-flow-strip-types": "npm:^7.25.2" + "@babel/plugin-transform-for-of": "npm:^7.24.7" + "@babel/plugin-transform-function-name": "npm:^7.25.1" + "@babel/plugin-transform-literals": "npm:^7.25.2" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.7" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.8" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.7" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.7" + "@babel/plugin-transform-numeric-separator": "npm:^7.24.7" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.7" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.7" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.8" + "@babel/plugin-transform-parameters": "npm:^7.24.7" + "@babel/plugin-transform-private-methods": "npm:^7.24.7" + "@babel/plugin-transform-private-property-in-object": "npm:^7.24.7" + "@babel/plugin-transform-react-display-name": "npm:^7.24.7" + "@babel/plugin-transform-react-jsx": "npm:^7.25.2" + "@babel/plugin-transform-react-jsx-self": "npm:^7.24.7" + "@babel/plugin-transform-react-jsx-source": "npm:^7.24.7" + "@babel/plugin-transform-regenerator": "npm:^7.24.7" + "@babel/plugin-transform-runtime": "npm:^7.24.7" + "@babel/plugin-transform-shorthand-properties": "npm:^7.24.7" + "@babel/plugin-transform-spread": "npm:^7.24.7" + "@babel/plugin-transform-sticky-regex": "npm:^7.24.7" + "@babel/plugin-transform-typescript": "npm:^7.25.2" + "@babel/plugin-transform-unicode-regex": "npm:^7.24.7" + "@babel/template": "npm:^7.25.0" + "@react-native/babel-plugin-codegen": "npm:0.83.1" + babel-plugin-syntax-hermes-parser: "npm:0.32.0" + babel-plugin-transform-flow-enums: "npm:^0.0.2" + react-refresh: "npm:^0.14.0" + peerDependencies: + "@babel/core": "*" + checksum: 10c0/6662b4b427c7c95eae069e1395e92a2cd618926e22c515bb9f088ac1dde1c9c1ee707334658be68db4da5fd2e17a5d8735f9dbe455e5b454e73cca846e44050a + languageName: node + linkType: hard + "@react-native/codegen@npm:0.83.0": version: 0.83.0 resolution: "@react-native/codegen@npm:0.83.0" @@ -3215,6 +3294,23 @@ __metadata: languageName: node linkType: hard +"@react-native/codegen@npm:0.83.1": + version: 0.83.1 + resolution: "@react-native/codegen@npm:0.83.1" + dependencies: + "@babel/core": "npm:^7.25.2" + "@babel/parser": "npm:^7.25.3" + glob: "npm:^7.1.1" + hermes-parser: "npm:0.32.0" + invariant: "npm:^2.2.4" + nullthrows: "npm:^1.1.1" + yargs: "npm:^17.6.2" + peerDependencies: + "@babel/core": "*" + checksum: 10c0/8c9846ff210adc38fdc87dee3a1eff62d6e29781e3aea678069e73b27c50710c5ee38083cc4168c631118f0f4c98bd5343825e270b44a189845b358e86e1395b + languageName: node + linkType: hard + "@react-native/community-cli-plugin@npm:0.83.0": version: 0.83.0 resolution: "@react-native/community-cli-plugin@npm:0.83.0" @@ -3878,7 +3974,7 @@ __metadata: languageName: node linkType: hard -"abort-controller@npm:^3.0.0": +"abort-controller@npm:3.0.0, abort-controller@npm:^3.0.0": version: 3.0.0 resolution: "abort-controller@npm:3.0.0" dependencies: @@ -9007,7 +9103,7 @@ __metadata: languageName: node linkType: hard -"metro-babel-transformer@npm:0.83.3": +"metro-babel-transformer@npm:0.83.3, metro-babel-transformer@npm:^0.83.0": version: 0.83.3 resolution: "metro-babel-transformer@npm:0.83.3" dependencies: @@ -9084,7 +9180,7 @@ __metadata: languageName: node linkType: hard -"metro-minify-terser@npm:0.83.3": +"metro-minify-terser@npm:0.83.3, metro-minify-terser@npm:^0.83.0": version: 0.83.3 resolution: "metro-minify-terser@npm:0.83.3" dependencies: @@ -9094,7 +9190,7 @@ __metadata: languageName: node linkType: hard -"metro-resolver@npm:0.83.3": +"metro-resolver@npm:0.83.3, metro-resolver@npm:^0.83.0": version: 0.83.3 resolution: "metro-resolver@npm:0.83.3" dependencies: @@ -9182,7 +9278,7 @@ __metadata: languageName: node linkType: hard -"metro@npm:0.83.3, metro@npm:^0.83.3": +"metro@npm:0.83.3, metro@npm:^0.83.0, metro@npm:^0.83.3": version: 0.83.3 resolution: "metro@npm:0.83.3" dependencies: