@bananalink-sdk/protocol 1.2.7
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/README.md +604 -0
- package/dist/chunk-32OWUOZ3.js +308 -0
- package/dist/chunk-32OWUOZ3.js.map +1 -0
- package/dist/chunk-65HNHRJK.cjs +123 -0
- package/dist/chunk-65HNHRJK.cjs.map +1 -0
- package/dist/chunk-7KYDLL3B.js +480 -0
- package/dist/chunk-7KYDLL3B.js.map +1 -0
- package/dist/chunk-A6FLEJ7R.cjs +62 -0
- package/dist/chunk-A6FLEJ7R.cjs.map +1 -0
- package/dist/chunk-CUJK7ZTS.js +217 -0
- package/dist/chunk-CUJK7ZTS.js.map +1 -0
- package/dist/chunk-GI3BUPIH.cjs +236 -0
- package/dist/chunk-GI3BUPIH.cjs.map +1 -0
- package/dist/chunk-JXHV66Q4.js +106 -0
- package/dist/chunk-JXHV66Q4.js.map +1 -0
- package/dist/chunk-KNGZKGRS.cjs +552 -0
- package/dist/chunk-KNGZKGRS.cjs.map +1 -0
- package/dist/chunk-LELPCIE7.js +840 -0
- package/dist/chunk-LELPCIE7.js.map +1 -0
- package/dist/chunk-MCZG7QEM.cjs +310 -0
- package/dist/chunk-MCZG7QEM.cjs.map +1 -0
- package/dist/chunk-TCVKC227.js +56 -0
- package/dist/chunk-TCVKC227.js.map +1 -0
- package/dist/chunk-VXLUSU5B.cjs +856 -0
- package/dist/chunk-VXLUSU5B.cjs.map +1 -0
- package/dist/chunk-WCQVDF3K.js +12 -0
- package/dist/chunk-WCQVDF3K.js.map +1 -0
- package/dist/chunk-WGEGR3DF.cjs +15 -0
- package/dist/chunk-WGEGR3DF.cjs.map +1 -0
- package/dist/client-session-claim-3QF3noOr.d.ts +197 -0
- package/dist/client-session-claim-C4lUik3b.d.cts +197 -0
- package/dist/core-DMhuNfoz.d.cts +62 -0
- package/dist/core-DMhuNfoz.d.ts +62 -0
- package/dist/crypto/providers/noble-provider.cjs +14 -0
- package/dist/crypto/providers/noble-provider.cjs.map +1 -0
- package/dist/crypto/providers/noble-provider.d.cts +30 -0
- package/dist/crypto/providers/noble-provider.d.ts +30 -0
- package/dist/crypto/providers/noble-provider.js +5 -0
- package/dist/crypto/providers/noble-provider.js.map +1 -0
- package/dist/crypto/providers/node-provider.cjs +308 -0
- package/dist/crypto/providers/node-provider.cjs.map +1 -0
- package/dist/crypto/providers/node-provider.d.cts +32 -0
- package/dist/crypto/providers/node-provider.d.ts +32 -0
- package/dist/crypto/providers/node-provider.js +306 -0
- package/dist/crypto/providers/node-provider.js.map +1 -0
- package/dist/crypto/providers/quickcrypto-provider.cjs +339 -0
- package/dist/crypto/providers/quickcrypto-provider.cjs.map +1 -0
- package/dist/crypto/providers/quickcrypto-provider.d.cts +34 -0
- package/dist/crypto/providers/quickcrypto-provider.d.ts +34 -0
- package/dist/crypto/providers/quickcrypto-provider.js +337 -0
- package/dist/crypto/providers/quickcrypto-provider.js.map +1 -0
- package/dist/crypto/providers/webcrypto-provider.cjs +310 -0
- package/dist/crypto/providers/webcrypto-provider.cjs.map +1 -0
- package/dist/crypto/providers/webcrypto-provider.d.cts +30 -0
- package/dist/crypto/providers/webcrypto-provider.d.ts +30 -0
- package/dist/crypto/providers/webcrypto-provider.js +308 -0
- package/dist/crypto/providers/webcrypto-provider.js.map +1 -0
- package/dist/crypto-BUS06Qz-.d.cts +40 -0
- package/dist/crypto-BUS06Qz-.d.ts +40 -0
- package/dist/crypto-export.cjs +790 -0
- package/dist/crypto-export.cjs.map +1 -0
- package/dist/crypto-export.d.cts +257 -0
- package/dist/crypto-export.d.ts +257 -0
- package/dist/crypto-export.js +709 -0
- package/dist/crypto-export.js.map +1 -0
- package/dist/crypto-provider-deYoVIxi.d.cts +36 -0
- package/dist/crypto-provider-deYoVIxi.d.ts +36 -0
- package/dist/index.cjs +615 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +379 -0
- package/dist/index.d.ts +379 -0
- package/dist/index.js +504 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas-export.cjs +294 -0
- package/dist/schemas-export.cjs.map +1 -0
- package/dist/schemas-export.d.cts +1598 -0
- package/dist/schemas-export.d.ts +1598 -0
- package/dist/schemas-export.js +5 -0
- package/dist/schemas-export.js.map +1 -0
- package/dist/siwe-export.cjs +237 -0
- package/dist/siwe-export.cjs.map +1 -0
- package/dist/siwe-export.d.cts +27 -0
- package/dist/siwe-export.d.ts +27 -0
- package/dist/siwe-export.js +228 -0
- package/dist/siwe-export.js.map +1 -0
- package/dist/testing.cjs +54 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +20 -0
- package/dist/testing.d.ts +20 -0
- package/dist/testing.js +51 -0
- package/dist/testing.js.map +1 -0
- package/dist/validation-export.cjs +359 -0
- package/dist/validation-export.cjs.map +1 -0
- package/dist/validation-export.d.cts +3 -0
- package/dist/validation-export.d.ts +3 -0
- package/dist/validation-export.js +6 -0
- package/dist/validation-export.js.map +1 -0
- package/dist/validators-export.cjs +73 -0
- package/dist/validators-export.cjs.map +1 -0
- package/dist/validators-export.d.cts +37 -0
- package/dist/validators-export.d.ts +37 -0
- package/dist/validators-export.js +4 -0
- package/dist/validators-export.js.map +1 -0
- package/package.json +140 -0
- package/src/constants/index.ts +205 -0
- package/src/crypto/context.ts +228 -0
- package/src/crypto/diagnostics.ts +772 -0
- package/src/crypto/errors.ts +114 -0
- package/src/crypto/index.ts +89 -0
- package/src/crypto/payload-handler.ts +102 -0
- package/src/crypto/providers/compliance-provider.ts +579 -0
- package/src/crypto/providers/factory.ts +204 -0
- package/src/crypto/providers/index.ts +44 -0
- package/src/crypto/providers/noble-provider.ts +392 -0
- package/src/crypto/providers/node-provider.ts +433 -0
- package/src/crypto/providers/quickcrypto-provider.ts +483 -0
- package/src/crypto/providers/registry.ts +129 -0
- package/src/crypto/providers/webcrypto-provider.ts +364 -0
- package/src/crypto/session-security.ts +185 -0
- package/src/crypto/types.ts +93 -0
- package/src/crypto/utils.ts +190 -0
- package/src/crypto-export.ts +21 -0
- package/src/index.ts +38 -0
- package/src/schemas/auth.ts +60 -0
- package/src/schemas/client-messages.ts +57 -0
- package/src/schemas/core.ts +144 -0
- package/src/schemas/crypto.ts +65 -0
- package/src/schemas/discovery.ts +79 -0
- package/src/schemas/index.ts +239 -0
- package/src/schemas/relay-messages.ts +45 -0
- package/src/schemas/wallet-messages.ts +177 -0
- package/src/schemas-export.ts +23 -0
- package/src/siwe-export.ts +27 -0
- package/src/testing.ts +71 -0
- package/src/types/auth.ts +60 -0
- package/src/types/client-messages.ts +84 -0
- package/src/types/core.ts +131 -0
- package/src/types/crypto-provider.ts +264 -0
- package/src/types/crypto.ts +90 -0
- package/src/types/discovery.ts +50 -0
- package/src/types/errors.ts +87 -0
- package/src/types/index.ts +197 -0
- package/src/types/post-auth-operations.ts +363 -0
- package/src/types/providers.ts +72 -0
- package/src/types/relay-messages.ts +60 -0
- package/src/types/request-lifecycle.ts +161 -0
- package/src/types/signing-operations.ts +99 -0
- package/src/types/wallet-messages.ts +251 -0
- package/src/utils/client-session-claim.ts +188 -0
- package/src/utils/index.ts +54 -0
- package/src/utils/public-keys.ts +49 -0
- package/src/utils/siwe.ts +362 -0
- package/src/utils/url-decoding.ts +126 -0
- package/src/utils/url-encoding.ts +144 -0
- package/src/utils/wallet-session-claim.ts +188 -0
- package/src/validation-export.ts +32 -0
- package/src/validators/index.ts +222 -0
- package/src/validators-export.ts +8 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
declare function isValidAddress(address: unknown): address is string;
|
|
2
|
+
declare function isValidUrl(url: unknown): url is string;
|
|
3
|
+
declare function isValidTimestamp(timestamp: unknown): timestamp is string;
|
|
4
|
+
declare function isValidChainId(chainId: unknown): chainId is number;
|
|
5
|
+
declare function isValidNonce(nonce: unknown): nonce is string;
|
|
6
|
+
declare function isValidSessionId(sessionId: unknown): sessionId is string;
|
|
7
|
+
declare function isValidBase64(str: unknown): str is string;
|
|
8
|
+
declare function isValidHex(hex: unknown): hex is string;
|
|
9
|
+
interface ValidationResult<T = unknown> {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
data?: T;
|
|
13
|
+
}
|
|
14
|
+
declare function isValidMessageType(type: unknown): type is 'auth' | 'tx' | 'sign';
|
|
15
|
+
declare function isValidEncryptionAlgorithm(algo: unknown): algo is 'AES-GCM' | 'plaintext';
|
|
16
|
+
declare function isValidDomain(domain: unknown): domain is string;
|
|
17
|
+
declare function isValidPublicKey(publicKey: unknown): publicKey is string;
|
|
18
|
+
interface EncryptedPayload {
|
|
19
|
+
iv: string;
|
|
20
|
+
ciphertext: string;
|
|
21
|
+
mac: string;
|
|
22
|
+
}
|
|
23
|
+
declare function isValidEncryptedPayload(payload: unknown): payload is EncryptedPayload;
|
|
24
|
+
declare function createValidationResult<T = unknown>(valid: boolean, data?: T, error?: string): ValidationResult<T>;
|
|
25
|
+
declare function hasRequiredFields<T extends object>(obj: unknown, fields: (keyof T)[]): obj is T;
|
|
26
|
+
interface SIWEMessage {
|
|
27
|
+
domain: string;
|
|
28
|
+
address: string;
|
|
29
|
+
uri: string;
|
|
30
|
+
version: string;
|
|
31
|
+
chainId: number;
|
|
32
|
+
nonce: string;
|
|
33
|
+
issuedAt: string;
|
|
34
|
+
}
|
|
35
|
+
declare function isValidSIWEMessage(message: unknown): message is SIWEMessage;
|
|
36
|
+
|
|
37
|
+
export { type EncryptedPayload, type SIWEMessage, type ValidationResult, createValidationResult, hasRequiredFields, isValidAddress, isValidBase64, isValidChainId, isValidDomain, isValidEncryptedPayload, isValidEncryptionAlgorithm, isValidHex, isValidMessageType, isValidNonce, isValidPublicKey, isValidSIWEMessage, isValidSessionId, isValidTimestamp, isValidUrl };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
declare function isValidAddress(address: unknown): address is string;
|
|
2
|
+
declare function isValidUrl(url: unknown): url is string;
|
|
3
|
+
declare function isValidTimestamp(timestamp: unknown): timestamp is string;
|
|
4
|
+
declare function isValidChainId(chainId: unknown): chainId is number;
|
|
5
|
+
declare function isValidNonce(nonce: unknown): nonce is string;
|
|
6
|
+
declare function isValidSessionId(sessionId: unknown): sessionId is string;
|
|
7
|
+
declare function isValidBase64(str: unknown): str is string;
|
|
8
|
+
declare function isValidHex(hex: unknown): hex is string;
|
|
9
|
+
interface ValidationResult<T = unknown> {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
data?: T;
|
|
13
|
+
}
|
|
14
|
+
declare function isValidMessageType(type: unknown): type is 'auth' | 'tx' | 'sign';
|
|
15
|
+
declare function isValidEncryptionAlgorithm(algo: unknown): algo is 'AES-GCM' | 'plaintext';
|
|
16
|
+
declare function isValidDomain(domain: unknown): domain is string;
|
|
17
|
+
declare function isValidPublicKey(publicKey: unknown): publicKey is string;
|
|
18
|
+
interface EncryptedPayload {
|
|
19
|
+
iv: string;
|
|
20
|
+
ciphertext: string;
|
|
21
|
+
mac: string;
|
|
22
|
+
}
|
|
23
|
+
declare function isValidEncryptedPayload(payload: unknown): payload is EncryptedPayload;
|
|
24
|
+
declare function createValidationResult<T = unknown>(valid: boolean, data?: T, error?: string): ValidationResult<T>;
|
|
25
|
+
declare function hasRequiredFields<T extends object>(obj: unknown, fields: (keyof T)[]): obj is T;
|
|
26
|
+
interface SIWEMessage {
|
|
27
|
+
domain: string;
|
|
28
|
+
address: string;
|
|
29
|
+
uri: string;
|
|
30
|
+
version: string;
|
|
31
|
+
chainId: number;
|
|
32
|
+
nonce: string;
|
|
33
|
+
issuedAt: string;
|
|
34
|
+
}
|
|
35
|
+
declare function isValidSIWEMessage(message: unknown): message is SIWEMessage;
|
|
36
|
+
|
|
37
|
+
export { type EncryptedPayload, type SIWEMessage, type ValidationResult, createValidationResult, hasRequiredFields, isValidAddress, isValidBase64, isValidChainId, isValidDomain, isValidEncryptedPayload, isValidEncryptionAlgorithm, isValidHex, isValidMessageType, isValidNonce, isValidPublicKey, isValidSIWEMessage, isValidSessionId, isValidTimestamp, isValidUrl };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createValidationResult, hasRequiredFields, isValidAddress, isValidBase64, isValidChainId, isValidDomain, isValidEncryptedPayload, isValidEncryptionAlgorithm, isValidHex, isValidMessageType, isValidNonce, isValidPublicKey, isValidSIWEMessage, isValidSessionId, isValidTimestamp, isValidUrl } from './chunk-JXHV66Q4.js';
|
|
2
|
+
import './chunk-WCQVDF3K.js';
|
|
3
|
+
//# sourceMappingURL=validators-export.js.map
|
|
4
|
+
//# sourceMappingURL=validators-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"validators-export.js"}
|
package/package.json
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bananalink-sdk/protocol",
|
|
3
|
+
"version": "1.2.7",
|
|
4
|
+
"description": "Core protocol definitions for BananaLink. Provides TypeScript types, Zod validation schemas, cryptographic utilities, and shared constants for wallet connections.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"bananalink",
|
|
8
|
+
"protocol",
|
|
9
|
+
"types",
|
|
10
|
+
"schemas",
|
|
11
|
+
"validation",
|
|
12
|
+
"cryptography",
|
|
13
|
+
"web3"
|
|
14
|
+
],
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/bananalink/bananalink/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/bananalink/bananalink.git",
|
|
21
|
+
"directory": "packages/protocol"
|
|
22
|
+
},
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"author": "BananaLink Team <team@banana.link>",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"react-native": "./dist/index.js",
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"require": "./dist/index.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./schemas": {
|
|
33
|
+
"types": "./dist/schemas-export.d.ts",
|
|
34
|
+
"react-native": "./dist/schemas-export.js",
|
|
35
|
+
"import": "./dist/schemas-export.js",
|
|
36
|
+
"require": "./dist/schemas-export.cjs"
|
|
37
|
+
},
|
|
38
|
+
"./validators": {
|
|
39
|
+
"types": "./dist/validators-export.d.ts",
|
|
40
|
+
"react-native": "./dist/validators-export.js",
|
|
41
|
+
"import": "./dist/validators-export.js",
|
|
42
|
+
"require": "./dist/validators-export.cjs"
|
|
43
|
+
},
|
|
44
|
+
"./validation": {
|
|
45
|
+
"types": "./dist/validation-export.d.ts",
|
|
46
|
+
"react-native": "./dist/validation-export.js",
|
|
47
|
+
"import": "./dist/validation-export.js",
|
|
48
|
+
"require": "./dist/validation-export.cjs"
|
|
49
|
+
},
|
|
50
|
+
"./siwe": {
|
|
51
|
+
"types": "./dist/siwe-export.d.ts",
|
|
52
|
+
"react-native": "./dist/siwe-export.js",
|
|
53
|
+
"import": "./dist/siwe-export.js",
|
|
54
|
+
"require": "./dist/siwe-export.cjs"
|
|
55
|
+
},
|
|
56
|
+
"./crypto": {
|
|
57
|
+
"types": "./dist/crypto-export.d.ts",
|
|
58
|
+
"react-native": "./dist/crypto-export.js",
|
|
59
|
+
"import": "./dist/crypto-export.js",
|
|
60
|
+
"require": "./dist/crypto-export.cjs"
|
|
61
|
+
},
|
|
62
|
+
"./crypto/provider/webcrypto": {
|
|
63
|
+
"types": "./dist/crypto/providers/webcrypto-provider.d.ts",
|
|
64
|
+
"react-native": "./dist/crypto/providers/webcrypto-provider.js",
|
|
65
|
+
"import": "./dist/crypto/providers/webcrypto-provider.js",
|
|
66
|
+
"require": "./dist/crypto/providers/webcrypto-provider.cjs"
|
|
67
|
+
},
|
|
68
|
+
"./crypto/provider/node": {
|
|
69
|
+
"types": "./dist/crypto/providers/node-provider.d.ts",
|
|
70
|
+
"react-native": "./dist/crypto/providers/node-provider.js",
|
|
71
|
+
"import": "./dist/crypto/providers/node-provider.js",
|
|
72
|
+
"require": "./dist/crypto/providers/node-provider.cjs"
|
|
73
|
+
},
|
|
74
|
+
"./crypto/provider/noble": {
|
|
75
|
+
"types": "./dist/crypto/providers/noble-provider.d.ts",
|
|
76
|
+
"react-native": "./dist/crypto/providers/noble-provider.js",
|
|
77
|
+
"import": "./dist/crypto/providers/noble-provider.js",
|
|
78
|
+
"require": "./dist/crypto/providers/noble-provider.cjs"
|
|
79
|
+
},
|
|
80
|
+
"./crypto/provider/quickcrypto": {
|
|
81
|
+
"types": "./dist/crypto/providers/quickcrypto-provider.d.ts",
|
|
82
|
+
"react-native": "./dist/crypto/providers/quickcrypto-provider.js",
|
|
83
|
+
"import": "./dist/crypto/providers/quickcrypto-provider.js",
|
|
84
|
+
"require": "./dist/crypto/providers/quickcrypto-provider.cjs"
|
|
85
|
+
},
|
|
86
|
+
"./testing": {
|
|
87
|
+
"types": "./dist/testing.d.ts",
|
|
88
|
+
"react-native": "./dist/testing.js",
|
|
89
|
+
"import": "./dist/testing.js",
|
|
90
|
+
"require": "./dist/testing.cjs"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"main": "./dist/index.cjs",
|
|
94
|
+
"module": "./dist/index.js",
|
|
95
|
+
"types": "./dist/index.d.ts",
|
|
96
|
+
"files": [
|
|
97
|
+
"dist",
|
|
98
|
+
"src",
|
|
99
|
+
"!src/__tests__"
|
|
100
|
+
],
|
|
101
|
+
"publishConfig": {
|
|
102
|
+
"access": "restricted"
|
|
103
|
+
},
|
|
104
|
+
"scripts": {
|
|
105
|
+
"build": "tsup",
|
|
106
|
+
"clean": "rm -rf dist node_modules",
|
|
107
|
+
"dev": "tsup --watch",
|
|
108
|
+
"lint": "eslint src --ext .ts",
|
|
109
|
+
"test": "vitest run",
|
|
110
|
+
"test:watch": "vitest",
|
|
111
|
+
"test:coverage": "vitest run --coverage",
|
|
112
|
+
"typecheck": "tsc --noEmit"
|
|
113
|
+
},
|
|
114
|
+
"dependencies": {
|
|
115
|
+
"@bananalink-sdk/logger": "workspace:*",
|
|
116
|
+
"@noble/ciphers": "^2.0.0",
|
|
117
|
+
"@noble/curves": "^2.0.0",
|
|
118
|
+
"@noble/hashes": "^2.0.0",
|
|
119
|
+
"zod": "^3.25.67"
|
|
120
|
+
},
|
|
121
|
+
"devDependencies": {
|
|
122
|
+
"@bananalink-sdk/eslint-config": "workspace:*",
|
|
123
|
+
"@bananalink-sdk/typescript-config": "workspace:*",
|
|
124
|
+
"@types/node": "^24.1.0",
|
|
125
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
126
|
+
"eslint": "^9.29.0",
|
|
127
|
+
"tsup": "^8.5.0",
|
|
128
|
+
"typescript": "^5.8.3",
|
|
129
|
+
"vitest": "^3.2.4"
|
|
130
|
+
},
|
|
131
|
+
"peerDependencies": {
|
|
132
|
+
"react-native-quick-crypto": "^0.7.0"
|
|
133
|
+
},
|
|
134
|
+
"peerDependenciesMeta": {
|
|
135
|
+
"react-native-quick-crypto": {
|
|
136
|
+
"optional": true
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"packageManager": "pnpm@10.15.1"
|
|
140
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for the BananaLink protocol
|
|
3
|
+
* Contains protocol version, URLs, timeouts, and other configuration values
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Protocol version and identification
|
|
7
|
+
export const PROTOCOL_VERSION = 1;
|
|
8
|
+
export const PACKAGE_NAME = '@bananalink-sdk/protocol';
|
|
9
|
+
export const DEEPLINK_SCHEME = 'bananalink';
|
|
10
|
+
|
|
11
|
+
// Default relay server configuration
|
|
12
|
+
export const DEFAULT_RELAY_URL = 'wss://relay.banana.link/v1';
|
|
13
|
+
|
|
14
|
+
// FrutiLink emoji set (16 fruits for 4 bits each)
|
|
15
|
+
export const FRUITS = [
|
|
16
|
+
'🍌', '🍎', '🍊', '🍇', '🍓', '🍑', '🍒', '🍉',
|
|
17
|
+
'🥝', '🍍', '🥭', '🥥', '🫐', '🍈', '🍋', '🥑'
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
// Timeout configurations (in milliseconds)
|
|
21
|
+
export const DEFAULT_TIMEOUTS = {
|
|
22
|
+
sessionTimeout: 24 * 60 * 60 * 1000, // 24 hours
|
|
23
|
+
requestTimeout: 5 * 60 * 1000, // 5 minutes
|
|
24
|
+
connectionTimeout: 30 * 1000, // 30 seconds
|
|
25
|
+
qrCodeTimeout: 2 * 60 * 1000, // 2 minutes
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
// Protocol v2.0 specific timeouts (in milliseconds)
|
|
29
|
+
// Based on PROTOCOL.md specification
|
|
30
|
+
export const PROTOCOL_V2_TIMEOUTS = {
|
|
31
|
+
sessionCreation: 5 * 1000, // 5 seconds - API Gateway response
|
|
32
|
+
claimSession: 10 * 1000, // 10 seconds - Wallet claims ownership
|
|
33
|
+
prefetchMetadata: 5 * 1000, // 5 seconds - Fetch dApp info
|
|
34
|
+
userApproval: 5 * 60 * 1000, // 5 minutes - User decision time
|
|
35
|
+
authentication: 30 * 1000, // 30 seconds - Sign and send
|
|
36
|
+
sessionTTL: 10800 * 1000, // 10800 seconds (3 hours) - Max session lifetime
|
|
37
|
+
reconnectionWindow: 10800 * 1000, // 10800 seconds (3 hours) - Same as session TTL
|
|
38
|
+
messageQueueRetention: 10800 * 1000, // 10800 seconds (3 hours) - Matches session TTL
|
|
39
|
+
websocketHeartbeat: 30 * 1000, // 30 seconds - Keep-alive ping
|
|
40
|
+
gracefulCloseTimeout: 5 * 1000, // 5 seconds - close_session ack wait
|
|
41
|
+
// Post-authentication operation timeouts (v2.1+)
|
|
42
|
+
signMessage: 60 * 1000, // 60 seconds - personal_sign operation
|
|
43
|
+
signTypedData: 90 * 1000, // 90 seconds - eth_signTypedData_v4 operation
|
|
44
|
+
signTransaction: 120 * 1000, // 120 seconds - Transaction signing
|
|
45
|
+
} as const;
|
|
46
|
+
|
|
47
|
+
// Message queue configuration
|
|
48
|
+
export const MESSAGE_QUEUE_CONFIG = {
|
|
49
|
+
maxQueueSize: 100, // Maximum messages per direction
|
|
50
|
+
retentionTime: 10800 * 1000, // 10800 seconds (3 hours) - Matches session TTL
|
|
51
|
+
overflowStrategy: 'drop_oldest', // Drop oldest messages when queue is full
|
|
52
|
+
} as const;
|
|
53
|
+
|
|
54
|
+
// Security limits and constraints
|
|
55
|
+
export const SECURITY_LIMITS = {
|
|
56
|
+
maxConcurrentSessions: 5,
|
|
57
|
+
maxSessionAge: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
58
|
+
minNonceLength: 8,
|
|
59
|
+
maxMessageSize: 64 * 1024, // 64KB
|
|
60
|
+
maxResourcesCount: 10,
|
|
61
|
+
rateLimit: {
|
|
62
|
+
requestsPerMinute: 60,
|
|
63
|
+
sessionsPerHour: 100,
|
|
64
|
+
},
|
|
65
|
+
} as const;
|
|
66
|
+
|
|
67
|
+
// Cryptographic constants
|
|
68
|
+
export const CRYPTO_CONSTANTS = {
|
|
69
|
+
keyLength: 256, // AES-256
|
|
70
|
+
ivLength: 12, // GCM IV length
|
|
71
|
+
tagLength: 16, // GCM tag length
|
|
72
|
+
curve: 'P-256', // ECDH curve
|
|
73
|
+
algorithm: 'AES-GCM', // Encryption algorithm
|
|
74
|
+
hashAlgorithm: 'SHA-256', // Hash algorithm
|
|
75
|
+
} as const;
|
|
76
|
+
|
|
77
|
+
// Message format constants
|
|
78
|
+
export const MESSAGE_FORMAT = {
|
|
79
|
+
version: '1',
|
|
80
|
+
encoding: 'utf8',
|
|
81
|
+
lineBreak: '\n',
|
|
82
|
+
resourcePrefix: '- ',
|
|
83
|
+
} as const;
|
|
84
|
+
|
|
85
|
+
// WebSocket message types
|
|
86
|
+
export const WS_MESSAGE_TYPES = {
|
|
87
|
+
subscribe: 'sub',
|
|
88
|
+
publish: 'pub',
|
|
89
|
+
acknowledge: 'ack',
|
|
90
|
+
error: 'error',
|
|
91
|
+
} as const;
|
|
92
|
+
|
|
93
|
+
// HTTP endpoints for fallback
|
|
94
|
+
export const HTTP_ENDPOINTS = {
|
|
95
|
+
messages: '/v1/messages',
|
|
96
|
+
session: '/v1/session',
|
|
97
|
+
health: '/v1/health',
|
|
98
|
+
} as const;
|
|
99
|
+
|
|
100
|
+
// Error messages (organized hierarchically)
|
|
101
|
+
export const ERROR_MESSAGES = {
|
|
102
|
+
// Session errors
|
|
103
|
+
SESSION_EXPIRED: 'Session has expired',
|
|
104
|
+
SESSION_NOT_FOUND: 'Session ID invalid or expired',
|
|
105
|
+
SESSION_ALREADY_CLAIMED: 'Session already claimed by another wallet',
|
|
106
|
+
INVALID_SESSION_CLAIM: 'Wallet does not own this session',
|
|
107
|
+
INVALID_CLIENT_CLAIM: 'Client session claim does not match',
|
|
108
|
+
SESSION_TOKEN_EXPIRED: 'Session token TTL exceeded',
|
|
109
|
+
SESSION_CLOSED: 'Session has been closed',
|
|
110
|
+
|
|
111
|
+
// Encryption errors
|
|
112
|
+
ENCRYPTION_FAILED: 'Message encryption failed',
|
|
113
|
+
DECRYPTION_FAILED: 'Cannot decrypt message',
|
|
114
|
+
INVALID_SIGNATURE: 'Invalid signature',
|
|
115
|
+
|
|
116
|
+
// Network errors
|
|
117
|
+
NETWORK_ERROR: 'Network connection error',
|
|
118
|
+
RELAY_ERROR: 'Internal relay server error',
|
|
119
|
+
MESSAGE_QUEUE_FULL: 'Too many queued messages (>100)',
|
|
120
|
+
RATE_LIMIT_EXCEEDED: 'Rate limit exceeded',
|
|
121
|
+
ORIGIN_MISMATCH: 'Origin verification failed',
|
|
122
|
+
|
|
123
|
+
// Request lifecycle errors (v2.1+)
|
|
124
|
+
REQUEST_PENDING: 'Another signing request is already pending',
|
|
125
|
+
REQUEST_NOT_FOUND: 'Request ID not found or already processed',
|
|
126
|
+
REQUEST_EXPIRED: 'Request expired before completion',
|
|
127
|
+
REQUEST_INVALID: 'Request data is invalid or malformed',
|
|
128
|
+
REQUEST_TIMEOUT: 'Request timed out waiting for wallet response',
|
|
129
|
+
|
|
130
|
+
// Operation-specific errors (v2.1+)
|
|
131
|
+
SIGNING_FAILED: 'Cryptographic signing operation failed',
|
|
132
|
+
SIGNING_REJECTED: 'User rejected the signing request',
|
|
133
|
+
TRANSACTION_INVALID: 'Transaction parameters validation failed',
|
|
134
|
+
CHAIN_MISMATCH: 'Requested chain ID does not match wallet chain',
|
|
135
|
+
} as const;
|
|
136
|
+
|
|
137
|
+
// QR code configuration
|
|
138
|
+
export const QR_CONFIG = {
|
|
139
|
+
size: 256,
|
|
140
|
+
margin: 4,
|
|
141
|
+
errorCorrectionLevel: 'M',
|
|
142
|
+
type: 'image/png',
|
|
143
|
+
} as const;
|
|
144
|
+
|
|
145
|
+
// Deep link configuration
|
|
146
|
+
export const DEEP_LINK_CONFIG = {
|
|
147
|
+
scheme: DEEPLINK_SCHEME,
|
|
148
|
+
host: 'connect',
|
|
149
|
+
universal: 'https://bananalink.app',
|
|
150
|
+
} as const;
|
|
151
|
+
|
|
152
|
+
// Network configuration
|
|
153
|
+
export const NETWORK_CONFIG = {
|
|
154
|
+
SUPPORTED_CHAINS: [
|
|
155
|
+
1, // Ethereum Mainnet
|
|
156
|
+
5, // Goerli Testnet
|
|
157
|
+
137, // Polygon Mainnet
|
|
158
|
+
80001, // Polygon Mumbai Testnet
|
|
159
|
+
42161, // Arbitrum One
|
|
160
|
+
421613, // Arbitrum Goerli
|
|
161
|
+
10, // Optimism
|
|
162
|
+
420, // Optimism Goerli
|
|
163
|
+
],
|
|
164
|
+
DEFAULT_CHAIN_ID: 1,
|
|
165
|
+
CHAIN_NAMES: {
|
|
166
|
+
1: 'Ethereum Mainnet',
|
|
167
|
+
5: 'Goerli Testnet',
|
|
168
|
+
137: 'Polygon Mainnet',
|
|
169
|
+
80001: 'Polygon Mumbai',
|
|
170
|
+
42161: 'Arbitrum One',
|
|
171
|
+
421613: 'Arbitrum Goerli',
|
|
172
|
+
10: 'Optimism',
|
|
173
|
+
420: 'Optimism Goerli',
|
|
174
|
+
} as const,
|
|
175
|
+
} as const;
|
|
176
|
+
|
|
177
|
+
// Development configuration
|
|
178
|
+
export const DEV_CONFIG = {
|
|
179
|
+
logLevel: 'debug',
|
|
180
|
+
enableMocks: false,
|
|
181
|
+
skipValidation: false,
|
|
182
|
+
allowLocalhost: true,
|
|
183
|
+
} as const;
|
|
184
|
+
|
|
185
|
+
// Export all constants as a single object for convenience
|
|
186
|
+
export const BANANALINK_CONSTANTS = {
|
|
187
|
+
PROTOCOL_VERSION,
|
|
188
|
+
PACKAGE_NAME,
|
|
189
|
+
DEEPLINK_SCHEME,
|
|
190
|
+
DEFAULT_RELAY_URL,
|
|
191
|
+
FRUITS,
|
|
192
|
+
DEFAULT_TIMEOUTS,
|
|
193
|
+
PROTOCOL_V2_TIMEOUTS,
|
|
194
|
+
MESSAGE_QUEUE_CONFIG,
|
|
195
|
+
SECURITY_LIMITS,
|
|
196
|
+
CRYPTO_CONSTANTS,
|
|
197
|
+
MESSAGE_FORMAT,
|
|
198
|
+
WS_MESSAGE_TYPES,
|
|
199
|
+
HTTP_ENDPOINTS,
|
|
200
|
+
ERROR_MESSAGES,
|
|
201
|
+
QR_CONFIG,
|
|
202
|
+
DEEP_LINK_CONFIG,
|
|
203
|
+
NETWORK_CONFIG,
|
|
204
|
+
DEV_CONFIG,
|
|
205
|
+
} as const;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CryptoContext - Singleton manager for the active crypto provider
|
|
3
|
+
*
|
|
4
|
+
* Provides a global context for crypto operations while maintaining
|
|
5
|
+
* the ability to use custom providers when needed.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Automatic initialization with best available provider
|
|
9
|
+
* const bytes = randomBytes(32);
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Explicit provider configuration
|
|
13
|
+
* CryptoContext.initialize({ type: 'noble' });
|
|
14
|
+
* const bytes = randomBytes(32);
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Custom provider instance
|
|
18
|
+
* const provider = new NobleCryptoProvider();
|
|
19
|
+
* CryptoContext.setProvider(provider);
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { Logger } from '@bananalink-sdk/logger';
|
|
23
|
+
import type { CryptoProvider, CryptoProviderType } from '../types/crypto-provider';
|
|
24
|
+
import { createCryptoProvider, getRegisteredCryptoProviders } from './providers';
|
|
25
|
+
import { ComplianceCryptoProvider } from './providers/compliance-provider';
|
|
26
|
+
import type { ComplianceConfig } from './providers/compliance-provider';
|
|
27
|
+
import { CryptoProviderUnavailableError } from './errors';
|
|
28
|
+
import { detectPlatform } from './utils';
|
|
29
|
+
|
|
30
|
+
export interface CryptoContextConfig {
|
|
31
|
+
/** Provider type to use (auto-detects if not specified) */
|
|
32
|
+
type?: CryptoProviderType;
|
|
33
|
+
/** Strict mode - throw if preferred provider unavailable (default: false) */
|
|
34
|
+
strict?: boolean;
|
|
35
|
+
/** Compliance configuration (wraps provider if enabled) */
|
|
36
|
+
compliance?: ComplianceConfig;
|
|
37
|
+
/** Logger instance for debug output */
|
|
38
|
+
logger?: Logger;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Singleton context for managing the active crypto provider
|
|
43
|
+
*
|
|
44
|
+
* Design rationale:
|
|
45
|
+
* - Provides convenient global access to crypto operations
|
|
46
|
+
* - Maintains lazy initialization for tree-shaking
|
|
47
|
+
* - Allows explicit provider configuration when needed
|
|
48
|
+
* - Supports both automatic and manual provider selection
|
|
49
|
+
*/
|
|
50
|
+
class CryptoContextManager {
|
|
51
|
+
private provider: CryptoProvider | null = null;
|
|
52
|
+
private config: CryptoContextConfig | null = null;
|
|
53
|
+
private initialized = false;
|
|
54
|
+
private initializing = false;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Initialize the crypto context with specific configuration
|
|
58
|
+
*
|
|
59
|
+
* @param config - Provider configuration options
|
|
60
|
+
* @throws Error if already initialized (call reset() first)
|
|
61
|
+
* @throws CryptoProviderUnavailableError if strict mode enabled and provider unavailable
|
|
62
|
+
*/
|
|
63
|
+
initialize(config: CryptoContextConfig = {}): void {
|
|
64
|
+
if (this.initialized && this.provider) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
'CryptoContext already initialized. Call CryptoContext.reset() first to reconfigure.'
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Strict mode validation - check if provider is registered
|
|
71
|
+
if (config.strict && config.type) {
|
|
72
|
+
const availableProviders = getRegisteredCryptoProviders();
|
|
73
|
+
if (!availableProviders.includes(config.type)) {
|
|
74
|
+
const platform = detectPlatform();
|
|
75
|
+
const recommendations: string[] = [
|
|
76
|
+
`Import the provider: import '@bananalink-sdk/protocol/crypto/provider/${config.type}'`,
|
|
77
|
+
'Ensure the provider package is installed',
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
// Add platform-specific recommendations
|
|
81
|
+
if (config.type === 'quickcrypto' && !platform.isReactNative) {
|
|
82
|
+
recommendations.push('QuickCrypto requires React Native environment');
|
|
83
|
+
if (platform.isNode) {
|
|
84
|
+
recommendations.push("Try 'node' provider for Node.js");
|
|
85
|
+
} else if (platform.isBrowser) {
|
|
86
|
+
recommendations.push("Try 'webcrypto' provider for browsers");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Add universal fallback recommendation
|
|
91
|
+
if (availableProviders.includes('noble')) {
|
|
92
|
+
recommendations.push("'noble' provider works in all environments as a fallback");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
throw new CryptoProviderUnavailableError(
|
|
96
|
+
`Strict mode: Crypto provider '${config.type}' is not registered. Did you forget to import it?`,
|
|
97
|
+
{
|
|
98
|
+
requestedProvider: config.type,
|
|
99
|
+
availableProviders,
|
|
100
|
+
platform,
|
|
101
|
+
recommendations,
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.config = config;
|
|
108
|
+
this.provider = this.createProvider(config);
|
|
109
|
+
this.initialized = true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get the active crypto provider
|
|
114
|
+
* Automatically initializes with default config if not already initialized
|
|
115
|
+
*
|
|
116
|
+
* @returns The active crypto provider instance
|
|
117
|
+
* @throws Error if called concurrently during initialization
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* This method performs lazy initialization on first call. It is NOT safe to call
|
|
121
|
+
* concurrently from multiple contexts before initialization completes (e.g., from
|
|
122
|
+
* Worker threads or Promise.all). For concurrent access scenarios, explicitly call
|
|
123
|
+
* initialize() first to ensure the provider is ready before concurrent operations begin.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* // Safe: Single-threaded lazy initialization
|
|
128
|
+
* const provider = CryptoContext.getProvider();
|
|
129
|
+
*
|
|
130
|
+
* // Safe: Pre-initialize for concurrent access
|
|
131
|
+
* CryptoContext.initialize({ type: 'noble' });
|
|
132
|
+
* await Promise.all([
|
|
133
|
+
* operation1(CryptoContext.getProvider()),
|
|
134
|
+
* operation2(CryptoContext.getProvider())
|
|
135
|
+
* ]);
|
|
136
|
+
*
|
|
137
|
+
* // Unsafe: Concurrent calls during lazy initialization
|
|
138
|
+
* await Promise.all([
|
|
139
|
+
* operation1(CryptoContext.getProvider()), // May throw if not initialized yet
|
|
140
|
+
* operation2(CryptoContext.getProvider())
|
|
141
|
+
* ]);
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
getProvider(): CryptoProvider {
|
|
145
|
+
// Check if already initialized
|
|
146
|
+
if (this.provider) {
|
|
147
|
+
return this.provider;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Prevent race condition - if already initializing, throw error
|
|
151
|
+
if (this.initializing) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
'CryptoContext initialization in progress. Avoid concurrent calls to getProvider() during initialization.'
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Lazy initialization with defaults
|
|
158
|
+
this.initializing = true;
|
|
159
|
+
try {
|
|
160
|
+
this.initialize();
|
|
161
|
+
// After initialize(), provider is guaranteed to be set
|
|
162
|
+
if (!this.provider) {
|
|
163
|
+
throw new Error('CryptoContext initialization failed: provider is null');
|
|
164
|
+
}
|
|
165
|
+
return this.provider;
|
|
166
|
+
} finally {
|
|
167
|
+
this.initializing = false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Set a custom provider instance
|
|
173
|
+
* Useful for testing or advanced use cases
|
|
174
|
+
*
|
|
175
|
+
* @param provider - Custom provider instance
|
|
176
|
+
*/
|
|
177
|
+
setProvider(provider: CryptoProvider): void {
|
|
178
|
+
this.provider = provider;
|
|
179
|
+
this.initialized = true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Check if context has been explicitly initialized
|
|
184
|
+
*/
|
|
185
|
+
isInitialized(): boolean {
|
|
186
|
+
return this.initialized;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get current configuration
|
|
191
|
+
*/
|
|
192
|
+
getConfig(): CryptoContextConfig | null {
|
|
193
|
+
return this.config;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Reset the context (for testing or reconfiguration)
|
|
198
|
+
*/
|
|
199
|
+
reset(): void {
|
|
200
|
+
this.provider = null;
|
|
201
|
+
this.config = null;
|
|
202
|
+
this.initialized = false;
|
|
203
|
+
this.initializing = false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Create a provider instance from configuration
|
|
208
|
+
*/
|
|
209
|
+
private createProvider(config: CryptoContextConfig): CryptoProvider {
|
|
210
|
+
const baseProvider = createCryptoProvider(config.type, config.logger, config.strict);
|
|
211
|
+
|
|
212
|
+
if (config.compliance?.enabled) {
|
|
213
|
+
return new ComplianceCryptoProvider(baseProvider, config.compliance);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return baseProvider;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Global singleton instance
|
|
223
|
+
*
|
|
224
|
+
* Usage:
|
|
225
|
+
* - Most code should use utility functions (randomBytes, generateNonce)
|
|
226
|
+
* - Advanced use cases can access CryptoContext directly
|
|
227
|
+
*/
|
|
228
|
+
export const CryptoContext = new CryptoContextManager();
|