@react-native-native/nativ-fabric 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/NativFabric.podspec +41 -0
  2. package/android/build.gradle +128 -0
  3. package/android/src/main/AndroidManifest.xml +2 -0
  4. package/android/src/main/cpp/CMakeLists.txt +59 -0
  5. package/android/src/main/cpp/NativBindingsInstaller.cpp +393 -0
  6. package/android/src/main/cpp/NativRuntime.cpp +508 -0
  7. package/android/src/main/java/com/nativfabric/ComposeHost.kt +26 -0
  8. package/android/src/main/java/com/nativfabric/NativContainerPackage.kt +35 -0
  9. package/android/src/main/java/com/nativfabric/NativContainerView.kt +51 -0
  10. package/android/src/main/java/com/nativfabric/NativContainerViewManager.kt +62 -0
  11. package/android/src/main/java/com/nativfabric/NativRuntime.kt +201 -0
  12. package/android/src/main/java/com/nativfabric/NativRuntimeModule.kt +37 -0
  13. package/android/src/main/java/com/nativfabric/compose/ComposeWrappers.kt +45 -0
  14. package/app.plugin.js +159 -0
  15. package/expo-module.config.json +6 -0
  16. package/ios/NativContainerComponentView.mm +137 -0
  17. package/ios/NativRuntime.h +36 -0
  18. package/ios/NativRuntime.mm +549 -0
  19. package/metro/Nativ.h +126 -0
  20. package/metro/compilers/android-compiler.js +339 -0
  21. package/metro/compilers/dylib-compiler.js +474 -0
  22. package/metro/compilers/kotlin-compiler.js +632 -0
  23. package/metro/compilers/rust-compiler.js +722 -0
  24. package/metro/compilers/static-compiler.js +1118 -0
  25. package/metro/compilers/swift-compiler.js +363 -0
  26. package/metro/extractors/cpp-ast-extractor.js +126 -0
  27. package/metro/extractors/kotlin-extractor.js +125 -0
  28. package/metro/extractors/rust-extractor.js +118 -0
  29. package/metro/index.js +236 -0
  30. package/metro/transformer.js +649 -0
  31. package/metro/utils/bridge-generator.js +50 -0
  32. package/metro/utils/compile-commands.js +104 -0
  33. package/metro/utils/cpp-daemon.js +344 -0
  34. package/metro/utils/dts-generator.js +32 -0
  35. package/metro/utils/include-resolver.js +73 -0
  36. package/metro/utils/kotlin-daemon.js +394 -0
  37. package/metro/utils/type-mapper.js +63 -0
  38. package/package.json +43 -0
  39. package/react-native.config.js +13 -0
  40. package/src/NativContainerNativeComponent.ts +9 -0
  41. package/src/NativeNativRuntime.ts +8 -0
  42. package/src/index.ts +4 -0
@@ -0,0 +1,394 @@
1
+ /**
2
+ * kotlin-daemon.js — persistent Kotlin compiler daemon.
3
+ *
4
+ * Starts a long-running JVM with the Kotlin compiler warm in memory.
5
+ * Communication via a simple TCP socket (sync-friendly from Node).
6
+ * First compile: ~3-5s (class loading). Subsequent compiles: ~1-2s.
7
+ */
8
+
9
+ const { spawn, execSync } = require('child_process');
10
+ const net = require('net');
11
+ const path = require('path');
12
+ const fs = require('fs');
13
+
14
+ let _daemon = null;
15
+ let _port = null;
16
+
17
+ const DAEMON_PORT_FILE = '/tmp/nativ-kotlin-daemon.port';
18
+
19
+ /**
20
+ * Start the Kotlin compiler daemon. Called once when Metro starts.
21
+ */
22
+ function startDaemon(projectRoot) {
23
+ if (_daemon) return;
24
+
25
+ const gradleCache = path.join(process.env.HOME || '', '.gradle/caches/modules-2/files-2.1');
26
+ const localCache = path.join(projectRoot, '.nativ/kotlin-cache');
27
+ const findJar = (group, artifact) => {
28
+ // Check Gradle cache first
29
+ try {
30
+ const result = execSync(
31
+ `find "${gradleCache}/${group}/${artifact}" -name "*.jar" -not -name "*sources*" -not -name "*javadoc*" 2>/dev/null | sort -V | tail -1`,
32
+ { encoding: 'utf8' }
33
+ ).trim();
34
+ if (result) return result;
35
+ } catch {}
36
+ // Fall back to local cache (populated by setup-kotlin)
37
+ try {
38
+ const files = fs.readdirSync(localCache).filter(f => f.startsWith(artifact) && f.endsWith('.jar'));
39
+ if (files.length > 0) return path.join(localCache, files[0]);
40
+ } catch {}
41
+ return '';
42
+ };
43
+
44
+ const embeddableJars = [
45
+ findJar('org.jetbrains.kotlin', 'kotlin-compiler-embeddable'),
46
+ findJar('org.jetbrains.kotlin', 'kotlin-stdlib'),
47
+ findJar('org.jetbrains.kotlin', 'kotlin-script-runtime'),
48
+ findJar('org.jetbrains.kotlinx', 'kotlinx-coroutines-core-jvm'),
49
+ findJar('org.jetbrains.intellij.deps', 'trove4j'),
50
+ findJar('org.jetbrains', 'annotations'),
51
+ ].filter(Boolean);
52
+
53
+ if (embeddableJars.length < 3) {
54
+ console.warn('[nativ] Kotlin JARs not found — daemon not started');
55
+ return;
56
+ }
57
+
58
+ // Find d8.jar to include in daemon (avoids separate JVM for dex conversion)
59
+ const androidHome = process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT
60
+ || path.join(process.env.HOME || '', 'Library/Android/sdk');
61
+ let d8Jar = null;
62
+ try {
63
+ const btDir = path.join(androidHome, 'build-tools');
64
+ const versions = fs.readdirSync(btDir).sort();
65
+ if (versions.length > 0) {
66
+ const candidate = path.join(btDir, versions[versions.length - 1], 'lib/d8.jar');
67
+ if (fs.existsSync(candidate)) d8Jar = candidate;
68
+ }
69
+ } catch {}
70
+
71
+ // Write the daemon Java source
72
+ const daemonDir = path.join(projectRoot, '.nativ/daemon');
73
+ fs.mkdirSync(daemonDir, { recursive: true });
74
+ const srcPath = path.join(daemonDir, 'KotlinDaemon.java');
75
+ fs.writeFileSync(srcPath, DAEMON_JAVA);
76
+
77
+ // Use the full (non-embeddable) compiler if available — needed for compiler API
78
+ // (KotlinCoreEnvironment uses un-shaded com.intellij.* classes)
79
+ // Read Kotlin version from config, fall back to scanning
80
+ let _ktVer = null;
81
+ try {
82
+ const cfg = JSON.parse(fs.readFileSync(path.join(projectRoot, '.nativ/nativ.config.json'), 'utf8'));
83
+ _ktVer = cfg.kotlin?.version;
84
+ } catch {}
85
+ const fullCompiler = _ktVer
86
+ ? path.join(projectRoot, `.nativ/compose-pretransform/kotlin-compiler-${_ktVer}.jar`)
87
+ : (() => {
88
+ try {
89
+ const files = fs.readdirSync(path.join(projectRoot, '.nativ/compose-pretransform'));
90
+ const match = files.find(f => f.startsWith('kotlin-compiler-') && f.endsWith('.jar'));
91
+ return match ? path.join(projectRoot, '.nativ/compose-pretransform', match) : '';
92
+ } catch { return ''; }
93
+ })();
94
+ const compilerJars = fs.existsSync(fullCompiler)
95
+ ? [daemonDir, fullCompiler, ...embeddableJars.filter(j => !j.includes('kotlin-compiler-embeddable'))]
96
+ : [daemonDir, ...embeddableJars];
97
+ if (d8Jar) compilerJars.push(d8Jar);
98
+ const jvmCp = compilerJars.join(':');
99
+
100
+ // Compile + start in background — doesn't block Metro startup
101
+ const classFile = path.join(daemonDir, 'KotlinDaemon.class');
102
+ const needsCompile = !fs.existsSync(classFile) ||
103
+ fs.statSync(srcPath).mtimeMs > fs.statSync(classFile).mtimeMs;
104
+
105
+ const launch = () => {
106
+ console.log('[nativ] Starting Kotlin compiler daemon...');
107
+ _daemon = spawn('java', [
108
+ '-Xmx1g',
109
+ '-XX:+UseG1GC',
110
+ '-XX:ReservedCodeCacheSize=256m',
111
+ '-cp', jvmCp,
112
+ 'KotlinDaemon',
113
+ ], {
114
+ stdio: ['pipe', 'pipe', 'pipe'],
115
+ detached: false,
116
+ });
117
+ wireUpDaemon();
118
+ };
119
+
120
+ if (needsCompile) {
121
+ // Compile async, then launch
122
+ const javacCp = fs.existsSync(fullCompiler) ? fullCompiler : embeddableJars[0];
123
+ const javac = spawn('javac', ['-cp', javacCp, srcPath, '-d', daemonDir], {
124
+ stdio: 'pipe',
125
+ });
126
+ javac.on('close', (code) => {
127
+ if (code === 0) launch();
128
+ else console.error('[nativ] Failed to compile Kotlin daemon');
129
+ });
130
+ } else {
131
+ // Already compiled — launch immediately (still async via spawn)
132
+ launch();
133
+ }
134
+
135
+ function wireUpDaemon() {
136
+ _daemon.stderr.on('data', (d) => {
137
+ const s = d.toString().trim();
138
+ if (s) console.error('[kotlin-daemon]', s.slice(0, 200));
139
+ });
140
+ _daemon.stdout.on('data', (d) => {
141
+ const s = d.toString().trim();
142
+ if (s.startsWith('PORT:')) {
143
+ _port = parseInt(s.split(':')[1]);
144
+ fs.writeFileSync(DAEMON_PORT_FILE, String(_port));
145
+ console.log(`[nativ] Kotlin daemon ready on port ${_port}`);
146
+ }
147
+ });
148
+ _daemon.on('exit', (code) => {
149
+ console.log(`[nativ] Kotlin daemon exited (${code})`);
150
+ _daemon = null;
151
+ _port = null;
152
+ try { fs.unlinkSync(DAEMON_PORT_FILE); } catch {}
153
+ });
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Compile a .kt file via the daemon. SYNCHRONOUS (for Metro transformer).
159
+ * @param {Object} request - { sourceFile, outputDir, classpath, plugin? }
160
+ * @returns {{ success: boolean, error?: string }}
161
+ */
162
+ function compileSyncViaDaemon(request) {
163
+ if (!_port) {
164
+ // Try reading port from file (in case daemon started in parent process)
165
+ try {
166
+ _port = parseInt(fs.readFileSync(DAEMON_PORT_FILE, 'utf8'));
167
+ } catch {}
168
+ }
169
+ if (!_port) return null;
170
+
171
+ const reqJson = JSON.stringify(request);
172
+
173
+ // Write request to temp file, send via nc (netcat)
174
+ const reqFile = `/tmp/nativ-kt-req-${process.pid}.json`;
175
+ fs.writeFileSync(reqFile, reqJson + '\n');
176
+
177
+ try {
178
+ const result = execSync(
179
+ `nc -w 120 127.0.0.1 ${_port} < "${reqFile}"`,
180
+ { encoding: 'utf8', timeout: 120000, stdio: ['pipe', 'pipe', 'pipe'] }
181
+ ).trim();
182
+ try { fs.unlinkSync(reqFile); } catch {}
183
+ return JSON.parse(result);
184
+ } catch (e) {
185
+ try { fs.unlinkSync(reqFile); } catch {}
186
+ return { success: false, error: e.message?.slice(0, 200) };
187
+ }
188
+ }
189
+
190
+ function stopDaemon() {
191
+ if (_daemon) {
192
+ try { _daemon.kill(); } catch {}
193
+ _daemon = null;
194
+ _port = null;
195
+ try { fs.unlinkSync(DAEMON_PORT_FILE); } catch {}
196
+ }
197
+ }
198
+
199
+ function isDaemonReady() {
200
+ if (_port) return true;
201
+ // Check port file (daemon started in main process, we're in a worker)
202
+ try {
203
+ _port = parseInt(fs.readFileSync(DAEMON_PORT_FILE, 'utf8'));
204
+ return _port > 0;
205
+ } catch { return false; }
206
+ }
207
+
208
+ // ─── Daemon Java source (TCP server) ──────────────────────────────────
209
+
210
+ const DAEMON_JAVA = String.raw`
211
+ import java.io.*;
212
+ import java.net.*;
213
+ import java.util.*;
214
+
215
+ public class KotlinDaemon {
216
+ public static void main(String[] args) throws Exception {
217
+ ServerSocket server = new ServerSocket(0); // random port
218
+ int port = server.getLocalPort();
219
+ System.out.println("PORT:" + port);
220
+ System.out.flush();
221
+
222
+ // Pre-warm: compile with FULL classpath (android.jar + stdlib) to warm
223
+ // the JIT for classpath scanning, type resolution, and IR lowering.
224
+ // A trivial warmup doesn't help — need android imports to exercise real codepaths.
225
+ try {
226
+ java.io.File warmup = java.io.File.createTempFile("warmup", ".kt");
227
+ warmup.deleteOnExit();
228
+ java.io.FileWriter fw = new java.io.FileWriter(warmup);
229
+ fw.write("import android.view.View\nimport android.widget.TextView\n" +
230
+ "import android.widget.FrameLayout\nimport android.graphics.Color\n" +
231
+ "fun _warmup(ctx: android.content.Context) {\n" +
232
+ " val tv = TextView(ctx); tv.text = \"hi\"; tv.setTextColor(Color.WHITE)\n" +
233
+ " val fl = FrameLayout(ctx); fl.addView(tv)\n}\n");
234
+ fw.close();
235
+ java.io.File warmupOut = java.io.File.createTempFile("warmup-out", "");
236
+ warmupOut.delete(); warmupOut.mkdirs(); warmupOut.deleteOnExit();
237
+
238
+ // Build classpath: find android.jar and kotlin-stdlib from JVM classpath
239
+ String fullCp = System.getProperty("java.class.path");
240
+ String androidJar = "", stdlibJar = "";
241
+ for (String p : fullCp.split(":")) {
242
+ if (p.contains("android.jar") || p.contains("platforms/android")) androidJar = p;
243
+ if (p.contains("kotlin-stdlib") && !p.contains("script")) stdlibJar = p;
244
+ }
245
+ // If no android.jar on daemon classpath, try common location
246
+ if (androidJar.isEmpty()) {
247
+ String home = System.getProperty("user.home");
248
+ java.io.File aj = new java.io.File(home + "/Library/Android/sdk/platforms/android-36/android.jar");
249
+ if (aj.exists()) androidJar = aj.getAbsolutePath();
250
+ }
251
+ String warmupCp = androidJar + ":" + stdlibJar;
252
+
253
+ long t = System.currentTimeMillis();
254
+ for (int i = 0; i < 3; i++) {
255
+ var c = new org.jetbrains.kotlin.cli.jvm.K2JVMCompiler();
256
+ org.jetbrains.kotlin.cli.common.CLICompiler.doMainNoExit(c, new String[]{
257
+ warmup.getAbsolutePath(), "-d", warmupOut.getAbsolutePath(),
258
+ "-classpath", warmupCp, "-no-reflect", "-jvm-target", "17"
259
+ });
260
+ }
261
+ System.err.println("Kotlin daemon: JIT warmup done in " +
262
+ (System.currentTimeMillis() - t) + "ms (3 compiles with android.jar)");
263
+
264
+ // Also warm d8 if available
265
+ try {
266
+ Class.forName("com.android.tools.r8.D8");
267
+ System.err.println("Kotlin daemon: d8 class loaded");
268
+ } catch (Exception ignore) {}
269
+ } catch (Exception e) {
270
+ System.err.println("Warmup failed: " + e.getMessage());
271
+ }
272
+
273
+ while (true) {
274
+ try {
275
+ Socket client = server.accept();
276
+ BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
277
+ PrintWriter out = new PrintWriter(client.getOutputStream(), true);
278
+
279
+ String line = in.readLine();
280
+ if (line == null || line.isEmpty()) { client.close(); continue; }
281
+
282
+ String result = compile(line);
283
+ out.println(result);
284
+ client.close();
285
+ } catch (Exception e) {
286
+ // keep running
287
+ }
288
+ }
289
+ }
290
+
291
+ // Reuse compiler instance — internal caches may persist
292
+ static final org.jetbrains.kotlin.cli.jvm.K2JVMCompiler sharedCompiler =
293
+ new org.jetbrains.kotlin.cli.jvm.K2JVMCompiler();
294
+
295
+ // ─── Compile ───────────────────────────────────────────────────────
296
+ static String compile(String json) {
297
+ try {
298
+ String sourceFile = extract(json, "sourceFile");
299
+ String outputDir = extract(json, "outputDir");
300
+ String classpath = extract(json, "classpath");
301
+ String plugin = extract(json, "plugin");
302
+ String dexOutput = extract(json, "dexOutput");
303
+ String androidJar = extract(json, "androidJar");
304
+
305
+ long t0 = System.currentTimeMillis();
306
+
307
+ // Build compiler args
308
+ List<String> argList = new ArrayList<>();
309
+ argList.add(sourceFile);
310
+ argList.add("-d"); argList.add(outputDir);
311
+ argList.add("-classpath"); argList.add(classpath);
312
+ argList.add("-no-reflect"); argList.add("-jvm-target"); argList.add("17");
313
+ if (plugin != null && !plugin.isEmpty()) {
314
+ argList.add("-Xplugin=" + plugin);
315
+ }
316
+
317
+ PrintStream oldErr = System.err;
318
+ ByteArrayOutputStream errBuf = new ByteArrayOutputStream();
319
+ System.setErr(new PrintStream(errBuf));
320
+
321
+ var compiler = new org.jetbrains.kotlin.cli.jvm.K2JVMCompiler();
322
+ var exit = org.jetbrains.kotlin.cli.common.CLICompiler.doMainNoExit(
323
+ compiler, argList.toArray(new String[0]));
324
+ long kotlincMs = System.currentTimeMillis() - t0;
325
+
326
+ System.setErr(oldErr);
327
+
328
+ if (exit != org.jetbrains.kotlin.cli.common.ExitCode.OK) {
329
+ String err = errBuf.toString().replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "");
330
+ return "{\"success\":false,\"error\":\"" + err + "\"}";
331
+ }
332
+
333
+ // Step 2: d8 → .dex
334
+ long d8Ms = 0;
335
+ if (dexOutput != null && !dexOutput.isEmpty()) {
336
+ try {
337
+ long t1 = System.currentTimeMillis();
338
+ List<String> classFiles = new ArrayList<>();
339
+ findClassFiles(new java.io.File(outputDir), classFiles);
340
+
341
+ List<String> d8Args = new ArrayList<>();
342
+ d8Args.add("--output");
343
+ d8Args.add(new java.io.File(dexOutput).getParent());
344
+ d8Args.add("--min-api"); d8Args.add("24");
345
+ d8Args.add("--no-desugaring");
346
+ if (androidJar != null && !androidJar.isEmpty()) {
347
+ d8Args.add("--lib"); d8Args.add(androidJar);
348
+ }
349
+ d8Args.addAll(classFiles);
350
+
351
+ Class<?> d8Class = Class.forName("com.android.tools.r8.D8");
352
+ d8Class.getMethod("main", String[].class)
353
+ .invoke(null, (Object) d8Args.toArray(new String[0]));
354
+
355
+ java.io.File classesDex = new java.io.File(
356
+ new java.io.File(dexOutput).getParent(), "classes.dex");
357
+ if (classesDex.exists()) classesDex.renameTo(new java.io.File(dexOutput));
358
+
359
+ d8Ms = System.currentTimeMillis() - t1;
360
+ } catch (Exception e) {
361
+ return "{\"success\":false,\"error\":\"d8: " +
362
+ (e.getMessage() != null ? e.getMessage().replace("\"", "\\\"") : "unknown") + "\"}";
363
+ }
364
+ }
365
+
366
+ return "{\"success\":true,\"kotlincMs\":" + kotlincMs + ",\"d8Ms\":" + d8Ms + "}";
367
+ } catch (Exception e) {
368
+ String msg = e.getMessage() != null ? e.getMessage().replace("\"", "\\\"") : "unknown";
369
+ return "{\"success\":false,\"error\":\"" + msg + "\"}";
370
+ }
371
+ }
372
+
373
+ static void findClassFiles(java.io.File dir, List<String> result) {
374
+ java.io.File[] files = dir.listFiles();
375
+ if (files == null) return;
376
+ for (java.io.File f : files) {
377
+ if (f.isDirectory()) findClassFiles(f, result);
378
+ else if (f.getName().endsWith(".class")) result.add(f.getAbsolutePath());
379
+ }
380
+ }
381
+
382
+ static String extract(String json, String key) {
383
+ String search = "\"" + key + "\":\"";
384
+ int start = json.indexOf(search);
385
+ if (start < 0) return null;
386
+ start += search.length();
387
+ int end = json.indexOf("\"", start);
388
+ if (end < 0) return null;
389
+ return json.substring(start, end).replace("\\\\", "\\").replace("\\\"", "\"");
390
+ }
391
+ }
392
+ `;
393
+
394
+ module.exports = { startDaemon, compileSyncViaDaemon, stopDaemon, isDaemonReady };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Maps C++ types to TypeScript types for .d.ts generation.
3
+ */
4
+
5
+ const CPP_TO_TS = {
6
+ // Primitives
7
+ 'int': 'number',
8
+ 'int32_t': 'number',
9
+ 'int64_t': 'number',
10
+ 'uint32_t': 'number',
11
+ 'uint64_t': 'number',
12
+ 'size_t': 'number',
13
+ 'float': 'number',
14
+ 'double': 'number',
15
+ 'bool': 'boolean',
16
+ 'void': 'void',
17
+
18
+ // Strings
19
+ 'std::string': 'string',
20
+ 'const std::string &': 'string',
21
+ 'const std::string&': 'string',
22
+ 'const char *': 'string',
23
+ 'const char*': 'string',
24
+
25
+ // Buffers
26
+ 'std::vector<uint8_t>': 'Uint8Array',
27
+ 'std::vector<float>': 'Float32Array',
28
+
29
+ // Collections
30
+ 'std::vector<std::string>': 'string[]',
31
+ 'std::vector<int>': 'number[]',
32
+ 'std::vector<double>': 'number[]',
33
+
34
+ // Optional
35
+ 'std::optional<std::string>': 'string | null',
36
+ 'std::optional<int>': 'number | null',
37
+ 'std::optional<double>': 'number | null',
38
+ };
39
+
40
+ function cppTypeToTS(cppType, customTypes = {}) {
41
+ const trimmed = cppType.trim()
42
+ .replace(/\s+/g, ' ') // normalize whitespace
43
+ .replace(/\s*&\s*$/, '') // strip trailing reference
44
+ .replace(/^const\s+/, 'const ') // normalize const prefix
45
+ .trim();
46
+
47
+ // Check custom NATIV_TYPE mappings first
48
+ if (customTypes[trimmed]) return customTypes[trimmed];
49
+
50
+ // Check built-in mapping (try with and without const/ref)
51
+ if (CPP_TO_TS[trimmed]) return CPP_TO_TS[trimmed];
52
+
53
+ // Try stripping const and reference
54
+ const stripped = trimmed
55
+ .replace(/^const\s+/, '')
56
+ .replace(/\s*[&*]\s*$/, '')
57
+ .trim();
58
+ if (CPP_TO_TS[stripped]) return CPP_TO_TS[stripped];
59
+
60
+ return 'unknown';
61
+ }
62
+
63
+ module.exports = { cppTypeToTS, CPP_TO_TS };
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@react-native-native/nativ-fabric",
3
+ "description": "Write native code directly in your React Native project. Import like any Javascript module.",
4
+ "version": "0.1.0",
5
+ "main": "src/index.ts",
6
+ "codegenConfig": {
7
+ "name": "NativFabricSpec",
8
+ "type": "all",
9
+ "jsSrcsDir": "src"
10
+ },
11
+ "dependencies": {
12
+ "@expo/config-plugins": ">=9.0.0",
13
+ "@react-native-native/cli": "^0.1.0"
14
+ },
15
+ "peerDependencies": {
16
+ "react": "*",
17
+ "react-native": ">=0.83"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/react-native-native/react-native-native.git"
22
+ },
23
+ "keywords": [
24
+ "react-native",
25
+ "native",
26
+ "c++",
27
+ "rust",
28
+ "ffi",
29
+ "jni",
30
+ "ndk",
31
+ "objc",
32
+ "swift",
33
+ "performance",
34
+ "native-modules",
35
+ "expo"
36
+ ],
37
+ "author": "Kim Brandwijk <kim.brandwijk@gmail.com>",
38
+ "license": "MIT",
39
+ "bugs": {
40
+ "url": "https://github.com/react-native-native/react-native-native/issues"
41
+ },
42
+ "homepage": "https://react-native-native.github.io"
43
+ }
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ dependency: {
3
+ platforms: {
4
+ ios: {
5
+ podspecPath: __dirname + '/NativFabric.podspec',
6
+ },
7
+ android: {
8
+ packageImportPath: 'import com.nativfabric.NativContainerPackage;',
9
+ packageInstance: 'new NativContainerPackage()',
10
+ },
11
+ },
12
+ },
13
+ };
@@ -0,0 +1,9 @@
1
+ import type { ViewProps } from "react-native";
2
+ import { codegenNativeComponent } from "react-native";
3
+
4
+ interface NativContainerProps extends ViewProps {
5
+ componentId: string;
6
+ propsJson?: string;
7
+ }
8
+
9
+ export default codegenNativeComponent<NativContainerProps>("NativContainer");
@@ -0,0 +1,8 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+
4
+ export interface Spec extends TurboModule {
5
+ getConstants(): {};
6
+ }
7
+
8
+ export default TurboModuleRegistry.getEnforcing<Spec>('NativRuntime');
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ // Trigger TurboModule load → installJSIBindingsWithRuntime → global.__nativ
2
+ import './NativeNativRuntime';
3
+
4
+ export { default as NativContainer } from './NativContainerNativeComponent';