From 1f4f616ac7bb3876727e1fb806717893501cd388 Mon Sep 17 00:00:00 2001 From: song <> Date: Sun, 23 Nov 2025 12:27:33 +0700 Subject: [PATCH 1/2] newArch2 --- .../main/java/com/prisma/PrismaModule.java | 12 +- cpp/QueryEngineHostObject.h | 7 +- ios/Prisma.mm | 115 ++++++++++++++---- 3 files changed, 108 insertions(+), 26 deletions(-) diff --git a/android/src/main/java/com/prisma/PrismaModule.java b/android/src/main/java/com/prisma/PrismaModule.java index 97d5d43d..2b858092 100644 --- a/android/src/main/java/com/prisma/PrismaModule.java +++ b/android/src/main/java/com/prisma/PrismaModule.java @@ -122,7 +122,17 @@ public void createDir(File dir) throws IOException public void install() { ReactApplicationContext context = this.getReactApplicationContext(); long jsContextPointer = context.getJavaScriptContextHolder().get(); - CallInvokerHolderImpl jsCallInvokerHolder = (CallInvokerHolderImpl)context.getCatalystInstance().getJSCallInvokerHolder(); + if (jsContextPointer == 0) { + throw new RuntimeException("JSI runtime pointer is null. Make sure Hermes is enabled and the runtime is initialized before calling install()."); + } + CallInvokerHolderImpl jsCallInvokerHolder; + if (context.getJSCallInvokerHolder() != null) { + jsCallInvokerHolder = (CallInvokerHolderImpl) context.getJSCallInvokerHolder(); + } else if (context.getCatalystInstance() != null) { + jsCallInvokerHolder = (CallInvokerHolderImpl) context.getCatalystInstance().getJSCallInvokerHolder(); + } else { + throw new RuntimeException("JSCallInvokerHolder is not available yet."); + } String dbPath = context.getDatabasePath("defaultDatabase").getAbsolutePath().replace("defaultDatabase", ""); String migrationsPath; try { diff --git a/cpp/QueryEngineHostObject.h b/cpp/QueryEngineHostObject.h index ec18d023..fa78dada 100644 --- a/cpp/QueryEngineHostObject.h +++ b/cpp/QueryEngineHostObject.h @@ -2,7 +2,12 @@ #ifndef query_engine_host_object_h #define query_engine_host_object_h -#include "query_engine.h" +#include +#if TARGET_OS_SIMULATOR +#include "../engines/ios/QueryEngine.xcframework/ios-arm64_x86_64-simulator/Headers/query_engine.h" +#else +#include "../engines/ios/QueryEngine.xcframework/ios-arm64/Headers/query_engine.h" +#endif #include #include #include diff --git a/ios/Prisma.mm b/ios/Prisma.mm index 5898a16b..1bdd2331 100644 --- a/ios/Prisma.mm +++ b/ios/Prisma.mm @@ -1,52 +1,119 @@ #import "Prisma.h" #import +#import #import +#import +#import #import +#import #import +#ifdef RCT_NEW_ARCH_ENABLED +#import "RNPrismaSpecJSI.h" +#endif + +// Forward declare runtimeExecutor to silence selector warnings on older headers +@interface RCTBridge (RuntimeExecutorForwardDecl) +- (facebook::react::RuntimeExecutor)runtimeExecutor; +@end + +static NSString *PrismaLibraryPath() { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, true); + return [paths objectAtIndex:0]; +} + +static NSString *PrismaMigrationsPath() { + auto bundleURL = NSBundle.mainBundle.bundleURL; + auto migrations_path_absolute = [NSString stringWithFormat:@"%@%@", bundleURL.absoluteString, @"migrations"]; + return [migrations_path_absolute stringByReplacingOccurrencesOfString:@"file://" withString:@""]; +} + +static inline void InstallInRuntime(facebook::jsi::Runtime &runtime, + std::shared_ptr callInvoker) { + NSString *libraryPath = PrismaLibraryPath(); + NSString *migrationsPath = PrismaMigrationsPath(); + prisma::install_cxx(runtime, callInvoker, [libraryPath UTF8String], [migrationsPath UTF8String]); +} + +static RCTBridge *ResolveBridge(id module) { + RCTBridge *bridge = nil; + if ([module respondsToSelector:@selector(bridge)]) { + bridge = ((id)module).bridge; + } + if (bridge == nil) { + bridge = [RCTBridge currentBridge]; + } + return bridge; +} + @implementation Prisma @synthesize bridge=_bridge; RCT_EXPORT_MODULE() +// Old-arch sync install for classic bridge +#if !RCT_NEW_ARCH_ENABLED RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) { - RCTCxxBridge *cxxBridge = (RCTCxxBridge *)_bridge; - if (cxxBridge == nil) { - return @false; +#if DEBUG + std::cout << "▲ NSHomeDirectory:\n" << [NSHomeDirectory() UTF8String] << std::endl; + std::cout << "▲ Library Path:\n" << [PrismaLibraryPath() UTF8String] << std::endl; + std::cout << "▲ Migrations Path:\n" << [PrismaMigrationsPath() UTF8String] << std::endl; +#endif + + BOOL ok = NO; + auto okPtr = &ok; + RCTBridge *bridge = ResolveBridge(self); + + // Try new-arch path first if runtimeExecutor is available + if (bridge && [bridge respondsToSelector:@selector(runtimeExecutor)]) { + facebook::react::RuntimeExecutor executor = RCTRuntimeExecutorFromBridge(bridge); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + executor([&](facebook::jsi::Runtime &runtime) { + InstallInRuntime(runtime, bridge.jsCallInvoker); + *okPtr = YES; + dispatch_semaphore_signal(sema); + }); + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + return @(ok); } - - auto jsiRuntime = (facebook::jsi::Runtime *)cxxBridge.runtime; - if (jsiRuntime == nil) { + + // Fallback to old-arch bridge access + RCTBridge *legacyBridge = _bridge ?: bridge; + RCTCxxBridge *cxxBridge = (RCTCxxBridge *)legacyBridge; + if (cxxBridge == nil || cxxBridge.runtime == nil) { + NSLog(@"[Prisma] no runtime available to install cxx"); return @false; } + + auto jsiRuntime = (facebook::jsi::Runtime *)cxxBridge.runtime; auto &runtime = *jsiRuntime; - auto callInvoker = _bridge.jsCallInvoker; - - // get migrations folder - auto bundleURL = NSBundle.mainBundle.bundleURL; - auto migrations_path_absolute = [NSString stringWithFormat:@"%@%@", bundleURL.absoluteString, @"migrations"]; - auto migrations_path = [migrations_path_absolute stringByReplacingOccurrencesOfString:@"file://" withString:@""]; - - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, true); - NSString *libraryPath = [paths objectAtIndex:0]; - -#if DEBUG - std::cout << "▲ NSHomeDirectory:\n" << [NSHomeDirectory() UTF8String] << std::endl; - std::cout << "▲ Library Path:\n" << [libraryPath UTF8String] << std::endl; - std::cout << "▲ Migrations Path:\n" << [migrations_path UTF8String] << std::endl; -#endif + auto callInvoker = _bridge ? _bridge.jsCallInvoker : legacyBridge.jsCallInvoker; - prisma::install_cxx(runtime, callInvoker, [libraryPath UTF8String], [migrations_path UTF8String]); - return nil; + InstallInRuntime(runtime, callInvoker); + return @true; } +#else +// Required by NativePrismaSpec protocol in new-arch; TurboModule path uses C++ spec below. +- (void)install {} +#endif #ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + class PrismaCxxTurboModule final : public facebook::react::NativePrismaCxxSpec { + public: + explicit PrismaCxxTurboModule(std::shared_ptr jsInvoker) + : NativePrismaCxxSpec(std::move(jsInvoker)) {} + + void install(facebook::jsi::Runtime &rt) { + InstallInRuntime(rt, this->jsInvoker_); + } + }; + + return std::make_shared(params.jsInvoker); } #endif From 8909194eaecf671aaf27136ec4a6cb7d3b3710a1 Mon Sep 17 00:00:00 2001 From: song <> Date: Mon, 24 Nov 2025 11:44:48 +0700 Subject: [PATCH 2/2] fix: migration form /prisma/migrations by default --- copy-migrations.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/copy-migrations.sh b/copy-migrations.sh index 43205c26..e97a21dd 100755 --- a/copy-migrations.sh +++ b/copy-migrations.sh @@ -5,7 +5,6 @@ echo "Copying prisma migration files..." MIGRATIONS_TARGET=${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} rm -rf "$MIGRATIONS_TARGET/migrations" -mkdir "$MIGRATIONS_TARGET/migrations" -cp -r ${SRCROOT}/../migrations ${MIGRATIONS_TARGET} +cp -r ${SRCROOT}/../prisma/migrations "${MIGRATIONS_TARGET}/migrations" echo "migration files copied ✅" \ No newline at end of file