brick-module 0.3.1 → 0.4.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.
- package/BrickModule.podspec +1 -1
- package/android/brick_modules.gradle +34 -2
- package/android/src/main/java/com/brickmodule/BrickModuleBase.kt +39 -2
- package/dist/BrickError.d.ts +29 -0
- package/dist/BrickError.js +49 -0
- package/dist/BrickModule.js +9 -4
- package/dist/index.d.ts +2 -10
- package/dist/index.js +2 -16
- package/ios/BrickModule/BrickCoreModule.swift +59 -25
- package/package.json +2 -2
- package/podfile_helper.rb +26 -3
- package/src/BrickError.ts +78 -0
- package/src/BrickModule.ts +22 -7
- package/src/index.ts +1 -14
package/BrickModule.podspec
CHANGED
|
@@ -68,6 +68,29 @@ ext.getBrickAndroidPath = { projectRoot ->
|
|
|
68
68
|
return new File(projectRoot, 'android/.brick').canonicalPath
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
ext.getBrickAndroidAppPath = { projectRoot ->
|
|
72
|
+
// Read brick.json from explicit project root
|
|
73
|
+
try {
|
|
74
|
+
def brickConfigFile = new File(projectRoot, 'brick.json')
|
|
75
|
+
if (brickConfigFile.exists()) {
|
|
76
|
+
def config = new JsonSlurper().parse(brickConfigFile)
|
|
77
|
+
def androidAppPath = config?.output?.androidAppPath
|
|
78
|
+
if (androidAppPath && !androidAppPath.isEmpty()) {
|
|
79
|
+
if (new File(androidAppPath).isAbsolute()) {
|
|
80
|
+
println("[Brick] Warning: Using absolute path for Android app path is not recommended: ${androidAppPath}")
|
|
81
|
+
return androidAppPath
|
|
82
|
+
}
|
|
83
|
+
return new File(projectRoot, androidAppPath).canonicalPath
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch (Exception e) {
|
|
87
|
+
println("[Brick] Warning: Failed to read brick.json from ${projectRoot}: ${e.message}")
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Default: android/app in project root
|
|
91
|
+
return new File(projectRoot, 'android/app').canonicalPath
|
|
92
|
+
}
|
|
93
|
+
|
|
71
94
|
ext.getAllDependencies = { packageJson ->
|
|
72
95
|
def deps = []
|
|
73
96
|
deps.addAll(packageJson.dependencies?.keySet() ?: [])
|
|
@@ -402,7 +425,12 @@ ${moduleNames}
|
|
|
402
425
|
// which contains package-aware-r.txt needed by dependent modules
|
|
403
426
|
def brickOutputDir = getBrickAndroidPath(workingDir)
|
|
404
427
|
def generatedMarker = new File(brickOutputDir, "src/main/kotlin/BrickModule.kt")
|
|
405
|
-
|
|
428
|
+
def androidAppPath = getBrickAndroidAppPath(workingDir)
|
|
429
|
+
def jniDir = new File(androidAppPath, "build/generated/autolinking/src/main/jni")
|
|
430
|
+
def hasJniOutputs = new File(jniDir, "BrickModuleSpec-generated.cpp").exists() &&
|
|
431
|
+
new File(jniDir, "BrickModuleSpec.h").exists() &&
|
|
432
|
+
new File(jniDir, "CMakeLists.txt").exists()
|
|
433
|
+
if (generatedMarker.exists() && hasJniOutputs) {
|
|
406
434
|
// Already generated, skip to preserve build outputs
|
|
407
435
|
return
|
|
408
436
|
}
|
|
@@ -419,7 +447,11 @@ ${moduleNames}
|
|
|
419
447
|
def codegenPath = new File(brickModuleDir, "bin/brick-codegen.js")
|
|
420
448
|
|
|
421
449
|
if (codegenPath.exists()) {
|
|
422
|
-
def
|
|
450
|
+
def codegenArgs = ['node', codegenPath.absolutePath, '--platform', 'android', '--projectRoot', workingDir.absolutePath]
|
|
451
|
+
if (generatedMarker.exists()) {
|
|
452
|
+
codegenArgs.add('--no-clean')
|
|
453
|
+
}
|
|
454
|
+
def codegenProc = codegenArgs.execute(null, workingDir)
|
|
423
455
|
codegenProc.waitFor()
|
|
424
456
|
}
|
|
425
457
|
}
|
|
@@ -58,8 +58,45 @@ abstract class BrickModuleSpec(private val reactContext: ReactContext) : BrickMo
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
// MARK: - BrickError Interface
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Error interface for Brick modules.
|
|
65
|
+
* Implement this interface to propagate all error properties to JavaScript.
|
|
66
|
+
* Follows the same pattern as iOS BrickError protocol.
|
|
67
|
+
*
|
|
68
|
+
* Note: message is inherited from Throwable, so it's not defined in this interface.
|
|
69
|
+
* Classes implementing BrickError must extend Exception/Throwable.
|
|
70
|
+
*/
|
|
71
|
+
interface BrickError {
|
|
72
|
+
/** Error code (accessed as error.name in JS) */
|
|
73
|
+
val code: String
|
|
74
|
+
|
|
75
|
+
/** Additional properties (accessed as error.userInfo.xxx in JS) */
|
|
76
|
+
val userInfo: Map<String, Any>?
|
|
77
|
+
get() = null
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Default implementation of BrickError.
|
|
82
|
+
* Extend this class to create custom errors.
|
|
83
|
+
*/
|
|
84
|
+
open class BrickException(
|
|
85
|
+
override val code: String,
|
|
86
|
+
message: String,
|
|
87
|
+
override val userInfo: Map<String, Any>? = null,
|
|
88
|
+
cause: Throwable? = null
|
|
89
|
+
) : Exception(message, cause), BrickError
|
|
90
|
+
|
|
91
|
+
/** Error types for Brick modules - implements BrickError interface */
|
|
92
|
+
open class BrickModuleError(
|
|
93
|
+
message: String,
|
|
94
|
+
override val code: String
|
|
95
|
+
) : Exception(message), BrickError {
|
|
96
|
+
|
|
97
|
+
override val userInfo: Map<String, Any>?
|
|
98
|
+
get() = null
|
|
99
|
+
|
|
63
100
|
class TypeMismatch(message: String) : BrickModuleError("Type mismatch: $message", "TYPE_ERROR")
|
|
64
101
|
class ExecutionError(message: String) :
|
|
65
102
|
BrickModuleError("Execution error: $message", "EXECUTION_ERROR")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/BrickError.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* BrickError - Type-safe class for custom errors from native modules.
|
|
4
|
+
* Matches the structure of iOS/Android BrickError.
|
|
5
|
+
*/
|
|
6
|
+
declare class BrickError extends Error {
|
|
7
|
+
/** Error code (same as error.name) */
|
|
8
|
+
readonly code: string;
|
|
9
|
+
/** Additional properties (e.g., amount, currency) */
|
|
10
|
+
readonly userInfo: Record<string, unknown>;
|
|
11
|
+
/** Name of the module where the error occurred */
|
|
12
|
+
readonly moduleName?: string;
|
|
13
|
+
constructor(message: string, code: string, userInfo?: Record<string, unknown>, moduleName?: string);
|
|
14
|
+
/**
|
|
15
|
+
* Type guard to check if an error object is a BrickError.
|
|
16
|
+
* @param error - The error object to check
|
|
17
|
+
* @returns true if the error is a BrickError
|
|
18
|
+
*/
|
|
19
|
+
static isBrickError(error: unknown): error is BrickError;
|
|
20
|
+
/**
|
|
21
|
+
* Converts a general error object to a BrickError.
|
|
22
|
+
* @param error - The error object to convert
|
|
23
|
+
* @param moduleName - Name of the module where the error occurred
|
|
24
|
+
* @returns A BrickError instance
|
|
25
|
+
*/
|
|
26
|
+
static from(error: unknown, moduleName?: string): BrickError;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { BrickError };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/BrickError.ts
|
|
2
|
+
/**
|
|
3
|
+
* BrickError - Type-safe class for custom errors from native modules.
|
|
4
|
+
* Matches the structure of iOS/Android BrickError.
|
|
5
|
+
*/
|
|
6
|
+
var BrickError = class BrickError extends Error {
|
|
7
|
+
/** Error code (same as error.name) */
|
|
8
|
+
code;
|
|
9
|
+
/** Additional properties (e.g., amount, currency) */
|
|
10
|
+
userInfo;
|
|
11
|
+
/** Name of the module where the error occurred */
|
|
12
|
+
moduleName;
|
|
13
|
+
constructor(message, code, userInfo = {}, moduleName) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = code;
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.userInfo = userInfo;
|
|
18
|
+
this.moduleName = moduleName;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Type guard to check if an error object is a BrickError.
|
|
22
|
+
* @param error - The error object to check
|
|
23
|
+
* @returns true if the error is a BrickError
|
|
24
|
+
*/
|
|
25
|
+
static isBrickError(error) {
|
|
26
|
+
return error instanceof Error && typeof error.code === "string" && typeof error.userInfo === "object" && error.userInfo !== null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Converts a general error object to a BrickError.
|
|
30
|
+
* @param error - The error object to convert
|
|
31
|
+
* @param moduleName - Name of the module where the error occurred
|
|
32
|
+
* @returns A BrickError instance
|
|
33
|
+
*/
|
|
34
|
+
static from(error, moduleName) {
|
|
35
|
+
if (error instanceof BrickError) {
|
|
36
|
+
if (moduleName && !error.moduleName) return new BrickError(error.message, error.code, error.userInfo, moduleName);
|
|
37
|
+
return error;
|
|
38
|
+
}
|
|
39
|
+
if (BrickError.isBrickError(error)) return new BrickError(error.message, error.code, error.userInfo, moduleName || error.moduleName);
|
|
40
|
+
if (error instanceof Error) {
|
|
41
|
+
const anyError = error;
|
|
42
|
+
return new BrickError(error.message, anyError.code || anyError.name || "UNKNOWN_ERROR", anyError.userInfo || {}, moduleName || anyError.moduleName);
|
|
43
|
+
}
|
|
44
|
+
return new BrickError(String(error), "UNKNOWN_ERROR", {}, moduleName);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
export { BrickError };
|
package/dist/BrickModule.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BrickError } from "./BrickError.js";
|
|
1
2
|
import { TurboModuleRegistry } from "react-native";
|
|
2
3
|
|
|
3
4
|
//#region src/BrickModule.ts
|
|
@@ -49,11 +50,15 @@ function get(moduleName) {
|
|
|
49
50
|
if (result && typeof result === "object" && result["~sync"] === true) if (result.success === true) return result.value;
|
|
50
51
|
else {
|
|
51
52
|
const errorInfo = result.error || {};
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
const message = errorInfo.message || errorInfo.errorMessage || "Unknown error";
|
|
54
|
+
const code = errorInfo.code || errorInfo.errorCode || "BRICK_ERROR";
|
|
55
|
+
const userInfo = { code };
|
|
56
|
+
for (const key of Object.keys(errorInfo)) if (key !== "code" && key !== "message" && key !== "errorCode" && key !== "errorMessage") userInfo[key] = errorInfo[key];
|
|
57
|
+
throw new BrickError(message, code, userInfo, moduleName);
|
|
56
58
|
}
|
|
59
|
+
if (result && typeof result.then === "function") return result.catch((error) => {
|
|
60
|
+
throw BrickError.from(error, moduleName);
|
|
61
|
+
});
|
|
57
62
|
return result;
|
|
58
63
|
}
|
|
59
64
|
throw new Error(`Method ${methodKey} not found`);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import { BrickModule, BrickModuleInterface, BrickModuleSpec } from "./BrickModule.js";
|
|
2
|
+
import { BrickError } from "./BrickError.js";
|
|
2
3
|
import { Any, AnyObject } from "./types.js";
|
|
3
4
|
|
|
4
5
|
//#region src/index.d.ts
|
|
5
6
|
|
|
6
|
-
/**
|
|
7
|
-
* Error types for Brick modules
|
|
8
|
-
*/
|
|
9
|
-
declare class BrickModuleError extends Error {
|
|
10
|
-
code: string;
|
|
11
|
-
moduleName?: string | undefined;
|
|
12
|
-
methodName?: string | undefined;
|
|
13
|
-
constructor(message: string, code?: string, moduleName?: string | undefined, methodName?: string | undefined);
|
|
14
|
-
}
|
|
15
7
|
/**
|
|
16
8
|
* Configuration interface for brick-codegen
|
|
17
9
|
*/
|
|
@@ -29,4 +21,4 @@ interface BrickCodegenConfig {
|
|
|
29
21
|
dev?: boolean;
|
|
30
22
|
}
|
|
31
23
|
//#endregion
|
|
32
|
-
export { Any, AnyObject, BrickCodegenConfig,
|
|
24
|
+
export { Any, AnyObject, BrickCodegenConfig, BrickError, BrickModule, type BrickModuleInterface, type BrickModuleSpec };
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
|
+
import { BrickError } from "./BrickError.js";
|
|
1
2
|
import BrickModule_default from "./BrickModule.js";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Error types for Brick modules
|
|
6
|
-
*/
|
|
7
|
-
var BrickModuleError = class extends Error {
|
|
8
|
-
constructor(message, code = "BRICK_ERROR", moduleName, methodName) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.code = code;
|
|
11
|
-
this.moduleName = moduleName;
|
|
12
|
-
this.methodName = methodName;
|
|
13
|
-
this.name = "BrickModuleError";
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
//#endregion
|
|
18
|
-
export { BrickModule_default as BrickModule, BrickModuleError };
|
|
4
|
+
export { BrickError, BrickModule_default as BrickModule };
|
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import React
|
|
3
3
|
|
|
4
|
+
// MARK: - BrickError Protocol
|
|
5
|
+
|
|
6
|
+
/// Error protocol for Brick modules.
|
|
7
|
+
/// Conforming to this protocol propagates all error properties to JavaScript.
|
|
8
|
+
public protocol BrickError: Error {
|
|
9
|
+
/// Error message (accessed as error.message in JS)
|
|
10
|
+
var message: String { get }
|
|
11
|
+
|
|
12
|
+
/// Error code (accessed as error.code in JS, optional)
|
|
13
|
+
var code: String? { get }
|
|
14
|
+
|
|
15
|
+
/// Additional properties (accessed as error.userInfo.xxx in JS)
|
|
16
|
+
var userInfo: [String: Any]? { get }
|
|
17
|
+
|
|
18
|
+
/// Convert to NSError (for React Native reject)
|
|
19
|
+
func asNSError() -> NSError
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public extension BrickError {
|
|
23
|
+
/// Default code implementation
|
|
24
|
+
var code: String? { nil }
|
|
25
|
+
|
|
26
|
+
/// Default userInfo implementation
|
|
27
|
+
var userInfo: [String: Any]? { nil }
|
|
28
|
+
|
|
29
|
+
/// Default NSError conversion implementation
|
|
30
|
+
func asNSError() -> NSError {
|
|
31
|
+
var info: [String: Any] = userInfo ?? [:]
|
|
32
|
+
info["code"] = code ?? "EXECUTION_ERROR"
|
|
33
|
+
info["message"] = message
|
|
34
|
+
info[NSLocalizedDescriptionKey] = message
|
|
35
|
+
return NSError(domain: "BrickModule", code: 0, userInfo: info)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Error code to use when calling reject
|
|
39
|
+
var rejectCode: String {
|
|
40
|
+
code ?? "EXECUTION_ERROR"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// MARK: - BrickModuleBase
|
|
45
|
+
|
|
4
46
|
/**
|
|
5
47
|
* Base class for all Brick modules
|
|
6
48
|
* Provides common functionality including event emission
|
|
@@ -30,43 +72,35 @@ open class BrickModuleBase: NSObject {
|
|
|
30
72
|
}
|
|
31
73
|
}
|
|
32
74
|
|
|
75
|
+
// MARK: - BrickModuleError
|
|
76
|
+
|
|
33
77
|
/**
|
|
34
78
|
* Error types for Brick modules
|
|
35
79
|
*/
|
|
36
|
-
public enum BrickModuleError:
|
|
80
|
+
public enum BrickModuleError: BrickError {
|
|
37
81
|
case typeMismatch(String)
|
|
38
82
|
case executionError(String)
|
|
39
83
|
case invalidDefinition(String)
|
|
40
84
|
case methodNotFound(String)
|
|
41
85
|
case moduleNotFound(String)
|
|
42
|
-
|
|
43
|
-
public var
|
|
86
|
+
|
|
87
|
+
public var code: String? {
|
|
44
88
|
switch self {
|
|
45
|
-
case .typeMismatch
|
|
46
|
-
|
|
47
|
-
case .
|
|
48
|
-
|
|
49
|
-
case .
|
|
50
|
-
return "Invalid definition: \(message)"
|
|
51
|
-
case .methodNotFound(let message):
|
|
52
|
-
return "Method not found: \(message)"
|
|
53
|
-
case .moduleNotFound(let message):
|
|
54
|
-
return "Module not found: \(message)"
|
|
89
|
+
case .typeMismatch: return "TYPE_ERROR"
|
|
90
|
+
case .executionError: return "EXECUTION_ERROR"
|
|
91
|
+
case .invalidDefinition: return "DEFINITION_ERROR"
|
|
92
|
+
case .methodNotFound: return "METHOD_NOT_FOUND"
|
|
93
|
+
case .moduleNotFound: return "MODULE_NOT_FOUND"
|
|
55
94
|
}
|
|
56
95
|
}
|
|
57
|
-
|
|
58
|
-
public var
|
|
96
|
+
|
|
97
|
+
public var message: String {
|
|
59
98
|
switch self {
|
|
60
|
-
case .typeMismatch:
|
|
61
|
-
|
|
62
|
-
case .
|
|
63
|
-
|
|
64
|
-
case .
|
|
65
|
-
return "DEFINITION_ERROR"
|
|
66
|
-
case .methodNotFound:
|
|
67
|
-
return "METHOD_NOT_FOUND"
|
|
68
|
-
case .moduleNotFound:
|
|
69
|
-
return "MODULE_NOT_FOUND"
|
|
99
|
+
case .typeMismatch(let msg): return "Type mismatch: \(msg)"
|
|
100
|
+
case .executionError(let msg): return "Execution error: \(msg)"
|
|
101
|
+
case .invalidDefinition(let msg): return "Invalid definition: \(msg)"
|
|
102
|
+
case .methodNotFound(let msg): return "Method not found: \(msg)"
|
|
103
|
+
case .moduleNotFound(let msg): return "Module not found: \(msg)"
|
|
70
104
|
}
|
|
71
105
|
}
|
|
72
106
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brick-module",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Better React Native native module development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"brick-codegen": "./bin/brick-codegen.js"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"brick-codegen": "0.
|
|
61
|
+
"brick-codegen": "0.4.0"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"react": ">=18.2.0",
|
package/podfile_helper.rb
CHANGED
|
@@ -27,7 +27,14 @@ def use_brick_modules!(app_path: nil)
|
|
|
27
27
|
else
|
|
28
28
|
File.expand_path(File.join(brick_root, ios_brick_path))
|
|
29
29
|
end
|
|
30
|
-
brick_codegen_podspec_path = File.join(
|
|
30
|
+
brick_codegen_podspec_path = File.join(
|
|
31
|
+
brick_codegen_pod_path,
|
|
32
|
+
'BrickCodegen.podspec'
|
|
33
|
+
)
|
|
34
|
+
brick_codegen_pod_relative_path = relative_pod_path(
|
|
35
|
+
brick_codegen_pod_path,
|
|
36
|
+
podfile_dir
|
|
37
|
+
)
|
|
31
38
|
|
|
32
39
|
# Run brick-codegen with real-time output and colors (iOS only)
|
|
33
40
|
exit_status = system("cd #{brick_root} && FORCE_COLOR=1 npx brick-codegen --platform ios --projectRoot \"#{brick_root}\"")
|
|
@@ -42,8 +49,8 @@ def use_brick_modules!(app_path: nil)
|
|
|
42
49
|
end
|
|
43
50
|
|
|
44
51
|
# Link generated BrickCodegen pod
|
|
45
|
-
pod 'BrickCodegen', :path =>
|
|
46
|
-
Pod::UI.puts "[Brick] Linked BrickCodegen from #{
|
|
52
|
+
pod 'BrickCodegen', :path => brick_codegen_pod_relative_path
|
|
53
|
+
Pod::UI.puts "[Brick] Linked BrickCodegen from #{brick_codegen_pod_relative_path}"
|
|
47
54
|
rescue => e
|
|
48
55
|
# Re-raise so CocoaPods fails the install
|
|
49
56
|
raise e
|
|
@@ -74,3 +81,19 @@ def get_brick_ios_path(project_root)
|
|
|
74
81
|
|
|
75
82
|
return File.expand_path(File.join(project_root, 'ios/.brick'))
|
|
76
83
|
end
|
|
84
|
+
|
|
85
|
+
def podfile_dir
|
|
86
|
+
podfile_path = Pod::Config.instance.podfile_path
|
|
87
|
+
return Pathname.new(Dir.pwd).expand_path if podfile_path.nil?
|
|
88
|
+
|
|
89
|
+
podfile_path.dirname.expand_path
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def relative_pod_path(target_path, base_dir)
|
|
93
|
+
Pathname.new(target_path)
|
|
94
|
+
.expand_path
|
|
95
|
+
.relative_path_from(base_dir)
|
|
96
|
+
.to_s
|
|
97
|
+
rescue ArgumentError
|
|
98
|
+
target_path
|
|
99
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BrickError - Type-safe class for custom errors from native modules.
|
|
3
|
+
* Matches the structure of iOS/Android BrickError.
|
|
4
|
+
*/
|
|
5
|
+
export class BrickError extends Error {
|
|
6
|
+
/** Error code (same as error.name) */
|
|
7
|
+
readonly code: string;
|
|
8
|
+
|
|
9
|
+
/** Additional properties (e.g., amount, currency) */
|
|
10
|
+
readonly userInfo: Record<string, unknown>;
|
|
11
|
+
|
|
12
|
+
/** Name of the module where the error occurred */
|
|
13
|
+
readonly moduleName?: string;
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
message: string,
|
|
17
|
+
code: string,
|
|
18
|
+
userInfo: Record<string, unknown> = {},
|
|
19
|
+
moduleName?: string
|
|
20
|
+
) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = code;
|
|
23
|
+
this.code = code;
|
|
24
|
+
this.userInfo = userInfo;
|
|
25
|
+
this.moduleName = moduleName;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Type guard to check if an error object is a BrickError.
|
|
30
|
+
* @param error - The error object to check
|
|
31
|
+
* @returns true if the error is a BrickError
|
|
32
|
+
*/
|
|
33
|
+
static isBrickError(error: unknown): error is BrickError {
|
|
34
|
+
return (
|
|
35
|
+
error instanceof Error &&
|
|
36
|
+
typeof (error as any).code === "string" &&
|
|
37
|
+
typeof (error as any).userInfo === "object" &&
|
|
38
|
+
(error as any).userInfo !== null
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Converts a general error object to a BrickError.
|
|
44
|
+
* @param error - The error object to convert
|
|
45
|
+
* @param moduleName - Name of the module where the error occurred
|
|
46
|
+
* @returns A BrickError instance
|
|
47
|
+
*/
|
|
48
|
+
static from(error: unknown, moduleName?: string): BrickError {
|
|
49
|
+
if (error instanceof BrickError) {
|
|
50
|
+
// Update moduleName if provided
|
|
51
|
+
if (moduleName && !error.moduleName) {
|
|
52
|
+
return new BrickError(error.message, error.code, error.userInfo, moduleName);
|
|
53
|
+
}
|
|
54
|
+
return error;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (BrickError.isBrickError(error)) {
|
|
58
|
+
return new BrickError(
|
|
59
|
+
error.message,
|
|
60
|
+
error.code,
|
|
61
|
+
error.userInfo,
|
|
62
|
+
moduleName || (error as any).moduleName
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (error instanceof Error) {
|
|
67
|
+
const anyError = error as any;
|
|
68
|
+
return new BrickError(
|
|
69
|
+
error.message,
|
|
70
|
+
anyError.code || anyError.name || "UNKNOWN_ERROR",
|
|
71
|
+
anyError.userInfo || {},
|
|
72
|
+
moduleName || anyError.moduleName
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return new BrickError(String(error), "UNKNOWN_ERROR", {}, moduleName);
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/BrickModule.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { TurboModule } from "react-native";
|
|
7
7
|
import { TurboModuleRegistry } from "react-native";
|
|
8
|
+
import { BrickError } from "./BrickError";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Base interface that all Brick module specs must extend
|
|
@@ -133,18 +134,32 @@ function get<T extends BrickModuleInterface>(
|
|
|
133
134
|
// Success: return the unwrapped value
|
|
134
135
|
return result.value;
|
|
135
136
|
} else {
|
|
136
|
-
// Failure: throw
|
|
137
|
+
// Failure: throw a BrickError with all properties from error object
|
|
137
138
|
const errorInfo = result.error || {};
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
const message = errorInfo.message || errorInfo.errorMessage || "Unknown error";
|
|
140
|
+
const code = errorInfo.code || errorInfo.errorCode || "BRICK_ERROR";
|
|
141
|
+
|
|
142
|
+
// Build userInfo from additional properties
|
|
143
|
+
const userInfo: Record<string, unknown> = { code };
|
|
144
|
+
for (const key of Object.keys(errorInfo)) {
|
|
145
|
+
if (key !== "code" && key !== "message" && key !== "errorCode" && key !== "errorMessage") {
|
|
146
|
+
userInfo[key] = errorInfo[key];
|
|
147
|
+
}
|
|
142
148
|
}
|
|
143
|
-
|
|
149
|
+
|
|
150
|
+
throw new BrickError(message, code, userInfo, moduleName);
|
|
144
151
|
}
|
|
145
152
|
}
|
|
146
153
|
|
|
147
|
-
//
|
|
154
|
+
// Async method: wrap Promise and convert to BrickError
|
|
155
|
+
if (result && typeof result.then === "function") {
|
|
156
|
+
return result.catch((error: unknown) => {
|
|
157
|
+
// Convert to BrickError with moduleName for type-safe error handling
|
|
158
|
+
throw BrickError.from(error, moduleName);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Not wrapped: return as-is
|
|
148
163
|
return result;
|
|
149
164
|
}
|
|
150
165
|
|
package/src/index.ts
CHANGED
|
@@ -4,20 +4,7 @@
|
|
|
4
4
|
export type { BrickModuleInterface, BrickModuleSpec } from "./BrickModule";
|
|
5
5
|
// Main API exports
|
|
6
6
|
export { default as BrickModule } from "./BrickModule";
|
|
7
|
-
|
|
8
|
-
* Error types for Brick modules
|
|
9
|
-
*/
|
|
10
|
-
export class BrickModuleError extends Error {
|
|
11
|
-
constructor(
|
|
12
|
-
message: string,
|
|
13
|
-
public code: string = "BRICK_ERROR",
|
|
14
|
-
public moduleName?: string,
|
|
15
|
-
public methodName?: string
|
|
16
|
-
) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.name = "BrickModuleError";
|
|
19
|
-
}
|
|
20
|
-
}
|
|
7
|
+
export { BrickError } from "./BrickError";
|
|
21
8
|
|
|
22
9
|
/**
|
|
23
10
|
* Configuration interface for brick-codegen
|