From 4a5a4aaff2ef4ecb05a610d3e6b3e93ff67d2b8f Mon Sep 17 00:00:00 2001 From: owl352 Date: Sat, 28 Feb 2026 14:55:08 +0300 Subject: [PATCH 1/5] add napiDependencies field support --- packages/host/src/node/path-utils.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/host/src/node/path-utils.ts b/packages/host/src/node/path-utils.ts index a2a954a6..3d759411 100644 --- a/packages/host/src/node/path-utils.ts +++ b/packages/host/src/node/path-utils.ts @@ -308,14 +308,19 @@ export function findPackageDependencyPaths( path.join(packageRoot, "noop.js"), ); - const { dependencies = {} } = readPackageSync({ cwd: packageRoot }); + const { dependencies = {}, napiDependencies = [] } = readPackageSync({ cwd: packageRoot }); + + const safeNApiDependencies: string[] = Array.isArray(napiDependencies) + ? napiDependencies.map(String) + : []; return Object.fromEntries( - Object.keys(dependencies).flatMap((dependencyName) => { + Object.keys(dependencies).concat(safeNApiDependencies).flatMap((dependencyName) => { const resolvedDependencyRoot = resolvePackageRoot( requireFromPackageRoot, dependencyName, ); + return resolvedDependencyRoot ? [[dependencyName, resolvedDependencyRoot]] : []; From bb184f0d2fdfdcea4435d5347d437315473748bb Mon Sep 17 00:00:00 2001 From: owl352 Date: Sat, 28 Feb 2026 16:23:45 +0300 Subject: [PATCH 2/5] update package-lock.json --- package-lock.json | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b4f113c..980e5e7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -137,7 +137,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2334,6 +2333,16 @@ "tslib": "^2.4.0" } }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", @@ -4832,7 +4841,6 @@ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.4.tgz", "integrity": "sha512-jOT8V1Ba5BdC79sKrRWDdMT5l1R+XNHTPR6CPWzUP2EcfAcvIHZWF0eAbmRcpOOP5gVIwnqNg0C4nvh6Abc3OA==", "license": "MIT", - "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.1", @@ -6017,7 +6025,6 @@ "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.81.4.tgz", "integrity": "sha512-aEXhRMsz6yN5X63Zk+cdKByQ0j3dsKv+ETRP9lLARdZ82fBOCMuK6IfmZMwK3A/3bI7gSvt2MFPn3QHy3WnByw==", "license": "MIT", - "peer": true, "dependencies": { "@react-native/js-polyfills": "0.81.4", "@react-native/metro-babel-transformer": "0.81.4", @@ -6641,7 +6648,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -6735,7 +6741,6 @@ "integrity": "sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.44.0", "@typescript-eslint/types": "8.44.0", @@ -7076,7 +7081,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7670,7 +7674,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001741", @@ -9071,7 +9074,6 @@ "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -12264,8 +12266,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/node-api-headers/-/node-api-headers-1.5.0.tgz", "integrity": "sha512-Yi/FgnN8IU/Cd6KeLxyHkylBUvDTsSScT0Tna2zTrz8klmc8qF2ppj6Q1LHsmOueJWhigQwR4cO2p0XBGW5IaQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/node-int64": { "version": "0.4.0", @@ -13115,7 +13116,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13162,7 +13162,6 @@ "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.4.tgz", "integrity": "sha512-bt5bz3A/+Cv46KcjV0VQa+fo7MKxs17RCcpzjftINlen4ZDUl0I6Ut+brQ2FToa5oD0IB0xvQHfmsg2EDqsZdQ==", "license": "MIT", - "peer": true, "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.4", @@ -14600,7 +14599,6 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15179,7 +15177,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", "license": "MIT", - "peer": true, "engines": { "node": ">=20" } From 09693494e36a72ed209a806aa3428936d7f813ec Mon Sep 17 00:00:00 2001 From: owl352 Date: Sat, 28 Feb 2026 16:27:47 +0300 Subject: [PATCH 3/5] lint --- packages/host/src/node/path-utils.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/host/src/node/path-utils.ts b/packages/host/src/node/path-utils.ts index 3d759411..584eecef 100644 --- a/packages/host/src/node/path-utils.ts +++ b/packages/host/src/node/path-utils.ts @@ -308,23 +308,27 @@ export function findPackageDependencyPaths( path.join(packageRoot, "noop.js"), ); - const { dependencies = {}, napiDependencies = [] } = readPackageSync({ cwd: packageRoot }); + const { dependencies = {}, napiDependencies = [] } = readPackageSync({ + cwd: packageRoot, + }); const safeNApiDependencies: string[] = Array.isArray(napiDependencies) ? napiDependencies.map(String) : []; return Object.fromEntries( - Object.keys(dependencies).concat(safeNApiDependencies).flatMap((dependencyName) => { - const resolvedDependencyRoot = resolvePackageRoot( - requireFromPackageRoot, - dependencyName, - ); + Object.keys(dependencies) + .concat(safeNApiDependencies) + .flatMap((dependencyName) => { + const resolvedDependencyRoot = resolvePackageRoot( + requireFromPackageRoot, + dependencyName, + ); - return resolvedDependencyRoot - ? [[dependencyName, resolvedDependencyRoot]] - : []; - }), + return resolvedDependencyRoot + ? [[dependencyName, resolvedDependencyRoot]] + : []; + }), ); } From 001884f6e6b4cafd4d0c702814a7044438ebf345 Mon Sep 17 00:00:00 2001 From: owl352 Date: Mon, 2 Mar 2026 01:11:12 +0300 Subject: [PATCH 4/5] add ReactNativeNodeAPIConfiguration and reading configuration from dependencies --- packages/host/src/node/path-utils.ts | 76 ++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/packages/host/src/node/path-utils.ts b/packages/host/src/node/path-utils.ts index 584eecef..dbec71da 100644 --- a/packages/host/src/node/path-utils.ts +++ b/packages/host/src/node/path-utils.ts @@ -2,7 +2,7 @@ import assert from "node:assert/strict"; import path from "node:path"; import fs from "node:fs"; import { packageDirectorySync } from "pkg-dir"; -import { readPackageSync } from "read-pkg"; +import { NormalizedPackageJson, readPackageSync } from "read-pkg"; import { createRequire } from "node:module"; import { chalk, prettyPath } from "@react-native-node-api/cli-utils"; @@ -294,9 +294,36 @@ export function visualizeLibraryMap(libraryMap: LibraryMap) { return result.join("\n"); } +export function findPackageConfigurationByPath( + fromPath: string, +): ReactNativeNodeAPIConfiguration { + const packageRoot = packageDirectorySync({ cwd: fromPath }); + assert(packageRoot, `Could not find package root from ${fromPath}`); + + const { + reactNativeNodeApi, + }: NormalizedPackageJson & ReactNativeNodeAPIConfiguration = readPackageSync({ + cwd: packageRoot, + }); + + return { reactNativeNodeApi }; +} + +export interface ReactNativeNodeAPIConfiguration { + reactNativeNodeApi?: { + scan?: { + dependencies?: string[]; + }; + }; +} + +type PackageJsonWithNodeApi = NormalizedPackageJson & + ReactNativeNodeAPIConfiguration; + /** * Search upwards from a directory to find a package.json and - * return a record mapping from each dependencies of that package to their path on disk. + * return a record mapping from each dependency of that package to their path on disk. + * Also checks all dependencies from reactNativeNodeApi field in dependencies package.json */ export function findPackageDependencyPaths( fromPath: string, @@ -304,31 +331,36 @@ export function findPackageDependencyPaths( const packageRoot = packageDirectorySync({ cwd: fromPath }); assert(packageRoot, `Could not find package root from ${fromPath}`); - const requireFromPackageRoot = createRequire( - path.join(packageRoot, "noop.js"), - ); + const requireFromRoot = createRequire(path.join(packageRoot, "noop.js")); - const { dependencies = {}, napiDependencies = [] } = readPackageSync({ + const { dependencies = {}, reactNativeNodeApi } = readPackageSync({ cwd: packageRoot, - }); + }) as PackageJsonWithNodeApi; - const safeNApiDependencies: string[] = Array.isArray(napiDependencies) - ? napiDependencies.map(String) - : []; + const initialDeps = Object.keys(dependencies).concat( + reactNativeNodeApi?.scan?.dependencies ?? [], + ); return Object.fromEntries( - Object.keys(dependencies) - .concat(safeNApiDependencies) - .flatMap((dependencyName) => { - const resolvedDependencyRoot = resolvePackageRoot( - requireFromPackageRoot, - dependencyName, - ); - - return resolvedDependencyRoot - ? [[dependencyName, resolvedDependencyRoot]] - : []; - }), + initialDeps.flatMap((name) => { + const root = resolvePackageRoot(requireFromRoot, name); + if (!root) return []; + + const nested = + findPackageConfigurationByPath(root)?.reactNativeNodeApi?.scan + ?.dependencies ?? []; + + const nestedEntries = nested + .map((nestedName) => { + const nestedRoot = resolvePackageRoot(requireFromRoot, nestedName); + return nestedRoot + ? ([nestedName, nestedRoot] as [string, string]) + : null; + }) + .filter((entry): entry is [string, string] => entry !== null); + + return [[name, root] as [string, string], ...nestedEntries]; + }), ); } From 7676e1ddd7e96bc51457d8dc7de65b514e9ba6ed Mon Sep 17 00:00:00 2001 From: owl352 Date: Mon, 2 Mar 2026 18:50:24 +0300 Subject: [PATCH 5/5] add zod schema for package.json --- packages/host/src/node/path-utils.ts | 53 +++++++++++++++++++--------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/packages/host/src/node/path-utils.ts b/packages/host/src/node/path-utils.ts index dbec71da..f20c655d 100644 --- a/packages/host/src/node/path-utils.ts +++ b/packages/host/src/node/path-utils.ts @@ -2,8 +2,9 @@ import assert from "node:assert/strict"; import path from "node:path"; import fs from "node:fs"; import { packageDirectorySync } from "pkg-dir"; -import { NormalizedPackageJson, readPackageSync } from "read-pkg"; +import { readPackageSync } from "read-pkg"; import { createRequire } from "node:module"; +import * as zod from "zod"; import { chalk, prettyPath } from "@react-native-node-api/cli-utils"; @@ -294,32 +295,45 @@ export function visualizeLibraryMap(libraryMap: LibraryMap) { return result.join("\n"); } +export const ReactNativeNodeAPIConfigurationSchema = zod.object({ + reactNativeNodeApi: zod + .object({ + scan: zod + .object({ + dependencies: zod.array(zod.string()).optional(), + }) + .optional(), + }) + .optional(), +}); + +export const PackageJsonDependenciesSchema = zod.object({ + dependencies: zod.record(zod.string(), zod.string()).optional(), +}); + +export type ReactNativeNodeAPIConfiguration = zod.infer< + typeof ReactNativeNodeAPIConfigurationSchema +>; +export type PackageJsonDependencies = zod.infer< + typeof PackageJsonDependenciesSchema +>; + +type PackageJsonWithNodeApi = PackageJsonDependencies & + ReactNativeNodeAPIConfiguration; + export function findPackageConfigurationByPath( fromPath: string, ): ReactNativeNodeAPIConfiguration { const packageRoot = packageDirectorySync({ cwd: fromPath }); assert(packageRoot, `Could not find package root from ${fromPath}`); - const { - reactNativeNodeApi, - }: NormalizedPackageJson & ReactNativeNodeAPIConfiguration = readPackageSync({ + const packageJson = readPackageSync({ cwd: packageRoot, }); - return { reactNativeNodeApi }; + return ReactNativeNodeAPIConfigurationSchema.parse(packageJson); } -export interface ReactNativeNodeAPIConfiguration { - reactNativeNodeApi?: { - scan?: { - dependencies?: string[]; - }; - }; -} - -type PackageJsonWithNodeApi = NormalizedPackageJson & - ReactNativeNodeAPIConfiguration; - /** * Search upwards from a directory to find a package.json and * return a record mapping from each dependency of that package to their path on disk. @@ -333,10 +347,15 @@ export function findPackageDependencyPaths( const requireFromRoot = createRequire(path.join(packageRoot, "noop.js")); - const { dependencies = {}, reactNativeNodeApi } = readPackageSync({ + const packageJson = readPackageSync({ cwd: packageRoot, }) as PackageJsonWithNodeApi; + const { dependencies = {} } = + PackageJsonDependenciesSchema.parse(packageJson); + const { reactNativeNodeApi } = + ReactNativeNodeAPIConfigurationSchema.parse(packageJson); + const initialDeps = Object.keys(dependencies).concat( reactNativeNodeApi?.scan?.dependencies ?? [], );