From 8e2c8467dd80f152cf4a50dfd712f083e8a66507 Mon Sep 17 00:00:00 2001 From: supertramp Date: Fri, 5 Dec 2025 16:26:36 +0000 Subject: [PATCH] Add QUIC transport adapter support for React Native Added FetchAdapter interface to support custom network transports: - ZhtpApiCore accepts optional FetchAdapter in constructor - React Native apps can inject native QUIC fetch implementation - Defaults to standard fetch() for backward compatibility - Exported FetchAdapter type from all entry points This allows React Native/Electron apps to use native QUIC libraries while keeping this TypeScript library transport-agnostic. Added QUIC-TRANSPORT.md with: - Usage examples for HTTP and QUIC transports - Native QUIC implementation guides (Swift/Kotlin) - QUIC connection settings and discovery - Testing and benchmarking examples - Migration guide from HTTP to QUIC Note: JavaScript lacks mature cross-platform QUIC libraries. Mobile apps must implement QUIC in native code (iOS/Android) and bridge to JavaScript. Closes #32 --- QUIC-TRANSPORT.md | 309 +++++++++++++++++++++++++++++++ dist/core/zhtp-api-core.d.ts | 11 ++ dist/core/zhtp-api-core.d.ts.map | 2 +- dist/core/zhtp-api-core.js | 5 +- dist/core/zhtp-api-core.js.map | 2 +- dist/core/zhtp-api.d.ts | 7 +- dist/core/zhtp-api.d.ts.map | 2 +- dist/core/zhtp-api.js | 8 +- dist/core/zhtp-api.js.map | 2 +- dist/react-native/index.d.ts | 1 + dist/react-native/index.d.ts.map | 2 +- dist/vanilla-js/index.d.ts | 1 + dist/vanilla-js/index.d.ts.map | 2 +- src/core/zhtp-api-core.ts | 18 +- src/core/zhtp-api.ts | 9 +- src/react-native/index.ts | 1 + src/vanilla-js/index.ts | 1 + 17 files changed, 369 insertions(+), 14 deletions(-) create mode 100644 QUIC-TRANSPORT.md diff --git a/QUIC-TRANSPORT.md b/QUIC-TRANSPORT.md new file mode 100644 index 0000000..6d445f9 --- /dev/null +++ b/QUIC-TRANSPORT.md @@ -0,0 +1,309 @@ +# QUIC Transport Support + +The Sovereign Network uses QUIC as its primary transport protocol. This library supports custom QUIC implementations through the `FetchAdapter` interface. + +## Overview + +By default, this library uses the standard `fetch()` API which works over HTTP/HTTPS. For React Native apps that need to connect via QUIC, you can provide a custom fetch implementation that uses native QUIC libraries. + +## Architecture + +``` +React Native App + ├── Native QUIC Client (Swift/Kotlin) + │ └── Implements QUIC protocol + ├── JavaScript Bridge + │ └── Exposes fetch-like API + └── This TypeScript Library + └── Uses injected fetch adapter +``` + +## Usage + +### 1. Default HTTP/HTTPS (Browser/Node.js) + +```typescript +import { ZhtpApi, BrowserConfigProvider } from '@sovereign-net/api-client'; + +// Uses standard fetch() - works over HTTP/HTTPS +const config = new BrowserConfigProvider({ + zhtpNodeUrl: 'https://node.sovereignnet.io', + networkType: 'mainnet', + debugMode: false, + enableBiometrics: false, +}); + +const api = new ZhtpApi(config); +``` + +### 2. Custom QUIC Transport (React Native) + +```typescript +import { ZhtpApi, ReactNativeConfigProvider, FetchAdapter } from '@sovereign-net/api-client/react-native'; +import { NativeModules } from 'react-native'; + +// Your native QUIC module (implemented in Swift/Kotlin) +const { QuicClient } = NativeModules; + +// Create fetch adapter using native QUIC +const quicFetchAdapter: FetchAdapter = async (url, options) => { + const response = await QuicClient.request({ + url, + method: options?.method || 'GET', + headers: options?.headers, + body: options?.body, + }); + + // Return Response-like object + return { + ok: response.status >= 200 && response.status < 300, + status: response.status, + statusText: response.statusText, + headers: new Headers(response.headers), + json: async () => JSON.parse(response.body), + text: async () => response.body, + } as Response; +}; + +// Initialize API with QUIC transport +const config = new ReactNativeConfigProvider({ + zhtpNodeUrl: 'quic://node.sovereignnet.io:9333', + networkType: 'mainnet', + debugMode: true, + enableBiometrics: true, +}); + +const api = new ZhtpApi(config, quicFetchAdapter); + +// Use normally - all requests go over QUIC +const identity = await api.signup({ + display_name: 'Alice', + identity_type: 'citizen', + password: 'secure_password', +}); +``` + +## Native QUIC Implementation + +### iOS (Swift) + +Use a Swift QUIC library like: +- **nw_connection** (Apple's Network.framework with QUIC support) +- **swift-quic** community libraries + +```swift +@objc(QuicClient) +class QuicClient: NSObject { + @objc + func request(_ params: NSDictionary, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock) { + + // Establish QUIC connection + let endpoint = NWEndpoint.hostPort( + host: NWEndpoint.Host(params["host"] as! String), + port: NWEndpoint.Port(integerLiteral: 9333) + ) + + let parameters = NWParameters.quic(alpn: ["zhtp/1.0"]) + parameters.allowLocalEndpointReuse = true + + let connection = NWConnection(to: endpoint, using: parameters) + connection.start(queue: .global()) + + // Send HTTP request over QUIC stream + // ... (implement request/response handling) + } +} +``` + +### Android (Kotlin) + +Use a Kotlin QUIC library like: +- **Cronet** (Chromium's network stack with QUIC) +- **kwik** (Pure Kotlin QUIC implementation) + +```kotlin +@ReactModule(name = "QuicClient") +class QuicClientModule(reactContext: ReactApplicationContext) : + ReactContextBaseJavaModule(reactContext) { + + @ReactMethod + fun request(params: ReadableMap, promise: Promise) { + val url = params.getString("url") + val method = params.getString("method") ?: "GET" + + // Use Cronet for QUIC support + val builder = CronetEngine.Builder(reactApplicationContext) + builder.enableQuic(true) + val engine = builder.build() + + val requestBuilder = engine.newUrlRequestBuilder( + url, + object : UrlRequest.Callback() { + override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) { + // Handle response + } + }, + executorService + ) + + requestBuilder.build().start() + } +} +``` + +## QUIC Connection Settings + +### Default Port +- **QUIC**: 9333/UDP +- **HTTP Fallback**: 9333/TCP (if QUIC unavailable) + +### TLS Configuration +- **TLS 1.3 Required** +- **Self-signed certificates accepted** in development/mesh mode +- **Post-Quantum Cryptography**: Kyber512 + Dilithium2 for mesh connections + +### Connection Parameters +```typescript +const quicConfig = { + alpn: ['zhtp/1.0'], // Application protocol + maxIdleTimeout: 30000, // 30 seconds + maxStreamData: 1048576, // 1 MB per stream + initialMaxData: 10485760, // 10 MB total + enableDatagrams: true, // For mesh discovery +}; +``` + +## Protocol Discovery + +The unified server supports multiple discovery methods: + +| Protocol | Port | Purpose | +|----------|------|---------| +| QUIC | 9333/UDP | Primary transport | +| UDP Multicast | 5353/UDP | LAN discovery | +| mDNS | 5353/UDP | Service discovery (_zhtp._udp.local) | +| WiFi Direct | P2P | Direct peer connections | +| Bluetooth LE | N/A | Mobile discovery | +| LoRaWAN | 868MHz | Long-range mesh | + +### Discovery API + +```typescript +// Get list of discovered nodes +const nodes = await api.discoverNodes({ + methods: ['quic', 'mdns', 'bluetooth'], + timeout: 5000, +}); + +// Connect to best available node +await api.connectToBestNode(nodes); +``` + +## Testing + +### Test QUIC Connection + +```typescript +const testQuicConnection = async () => { + try { + // Test protocol info endpoint + const info = await api.getProtocolInfo(); + console.log('✅ QUIC connection successful:', info.protocol); + console.log(' Node:', info.node_id); + console.log(' Uptime:', info.uptime, 'seconds'); + } catch (error) { + console.error('❌ QUIC connection failed:', error); + } +}; +``` + +### Benchmark QUIC vs HTTP + +```typescript +const benchmark = async () => { + const iterations = 100; + + // HTTP timing + const httpStart = Date.now(); + for (let i = 0; i < iterations; i++) { + await api.getProtocolHealth(); + } + const httpTime = Date.now() - httpStart; + + // QUIC timing (with custom adapter) + const quicStart = Date.now(); + for (let i = 0; i < iterations; i++) { + await api.getProtocolHealth(); + } + const quicTime = Date.now() - quicStart; + + console.log(`HTTP: ${httpTime}ms (${httpTime/iterations}ms avg)`); + console.log(`QUIC: ${quicTime}ms (${quicTime/iterations}ms avg)`); + console.log(`Improvement: ${((httpTime - quicTime) / httpTime * 100).toFixed(1)}%`); +}; +``` + +## Troubleshooting + +### Connection Fails +- Check QUIC port 9333/UDP is not blocked +- Verify TLS certificate trust (disable verification in dev) +- Try HTTP fallback to test API methods + +### Performance Issues +- Enable connection pooling in native QUIC client +- Use 0-RTT resumption for faster reconnects +- Check network latency with `getNetworkStats()` + +### Platform-Specific Issues + +**iOS**: +- Ensure `Info.plist` allows UDP connections +- Check App Transport Security settings + +**Android**: +- Add `INTERNET` permission to `AndroidManifest.xml` +- Enable cleartext traffic for development + +## Migration from HTTP + +Existing code requires NO changes when switching to QUIC: + +```typescript +// Before (HTTP) +const api = new ZhtpApi(config); + +// After (QUIC) +const api = new ZhtpApi(config, quicFetchAdapter); + +// All methods work identically +await api.signup({ ... }); +await api.registerWeb4Domain({ ... }); +await api.getWalletList(identityId); +``` + +## Performance Benefits + +QUIC provides: +- **30-50% lower latency** vs TCP (no head-of-line blocking) +- **Faster connection establishment** (0-RTT resumption) +- **Better mobile performance** (connection migration) +- **Improved reliability** (better congestion control) + +## Security + +QUIC connections use: +- **TLS 1.3 mandatory** (no downgrade attacks) +- **Connection ID encryption** (privacy from network observers) +- **Forward secrecy** (ephemeral keys) +- **Post-quantum cryptography** (Kyber512 + Dilithium2 for mesh) + +## References + +- [QUIC RFC 9000](https://www.rfc-editor.org/rfc/rfc9000.html) +- [HTTP/3 RFC 9114](https://www.rfc-editor.org/rfc/rfc9114.html) +- [Sovereign Network Protocol Spec](https://github.com/SOVEREIGN-NET/protocol-spec) +- [React Native Native Modules](https://reactnative.dev/docs/native-modules-intro) +- [Cronet QUIC Documentation](https://chromium.googlesource.com/chromium/src/+/master/components/cronet/) diff --git a/dist/core/zhtp-api-core.d.ts b/dist/core/zhtp-api-core.d.ts index 2616b43..1e28d99 100644 --- a/dist/core/zhtp-api-core.d.ts +++ b/dist/core/zhtp-api-core.d.ts @@ -3,12 +3,23 @@ * Handles request/response, retry logic, and timeouts */ import { ApiConfig } from './types'; +/** + * Transport adapter for custom network implementations (e.g., QUIC) + * React Native apps can provide their own fetch implementation using native QUIC + */ +export type FetchAdapter = (url: string, options?: RequestInit) => Promise; export declare abstract class ZhtpApiCore { protected baseUrl: string; protected config: ApiConfig | null; protected maxRetries: number; protected requestTimeout: number; protected retryDelays: number[]; + /** + * Custom fetch adapter (e.g., QUIC-based fetch for React Native) + * Defaults to global fetch if not provided + */ + protected fetchAdapter: FetchAdapter; + constructor(fetchAdapter?: FetchAdapter); /** * Generic request method with retry logic and timeout */ diff --git a/dist/core/zhtp-api-core.d.ts.map b/dist/core/zhtp-api-core.d.ts.map index 0001631..65f1490 100644 --- a/dist/core/zhtp-api-core.d.ts.map +++ b/dist/core/zhtp-api-core.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"zhtp-api-core.d.ts","sourceRoot":"","sources":["../../src/core/zhtp-api-core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,8BAAsB,WAAW;IAC/B,SAAS,CAAC,OAAO,EAAE,MAAM,CAAM;IAC/B,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAQ;IAC1C,SAAS,CAAC,UAAU,SAAK;IACzB,SAAS,CAAC,cAAc,SAAS;IACjC,SAAS,CAAC,WAAW,WAAsB;IAE3C;;OAEG;cACa,OAAO,CAAC,CAAC,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,EACzB,UAAU,SAAI,GACb,OAAO,CAAC,CAAC,CAAC;IAqCb,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;CAQ3C"} \ No newline at end of file +{"version":3,"file":"zhtp-api-core.d.ts","sourceRoot":"","sources":["../../src/core/zhtp-api-core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErF,8BAAsB,WAAW;IAC/B,SAAS,CAAC,OAAO,EAAE,MAAM,CAAM;IAC/B,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAQ;IAC1C,SAAS,CAAC,UAAU,SAAK;IACzB,SAAS,CAAC,cAAc,SAAS;IACjC,SAAS,CAAC,WAAW,WAAsB;IAE3C;;;OAGG;IACH,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC;gBAEzB,YAAY,CAAC,EAAE,YAAY;IAIvC;;OAEG;cACa,OAAO,CAAC,CAAC,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,EACzB,UAAU,SAAI,GACb,OAAO,CAAC,CAAC,CAAC;IAqCb,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;CAQ3C"} \ No newline at end of file diff --git a/dist/core/zhtp-api-core.js b/dist/core/zhtp-api-core.js index abe29e8..c988f38 100644 --- a/dist/core/zhtp-api-core.js +++ b/dist/core/zhtp-api-core.js @@ -3,12 +3,13 @@ * Handles request/response, retry logic, and timeouts */ export class ZhtpApiCore { - constructor() { + constructor(fetchAdapter) { this.baseUrl = ''; this.config = null; this.maxRetries = 3; this.requestTimeout = 10000; this.retryDelays = [1000, 2000, 4000]; // Exponential backoff + this.fetchAdapter = fetchAdapter || ((url, options) => fetch(url, options)); } /** * Generic request method with retry logic and timeout @@ -18,7 +19,7 @@ export class ZhtpApiCore { const url = `${this.baseUrl}${endpoint}`; const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), this.requestTimeout); - const response = await fetch(url, { + const response = await this.fetchAdapter(url, { ...options, signal: controller.signal, }); diff --git a/dist/core/zhtp-api-core.js.map b/dist/core/zhtp-api-core.js.map index 8f9530b..97b5542 100644 --- a/dist/core/zhtp-api-core.js.map +++ b/dist/core/zhtp-api-core.js.map @@ -1 +1 @@ -{"version":3,"file":"zhtp-api-core.js","sourceRoot":"","sources":["../../src/core/zhtp-api-core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,OAAgB,WAAW;IAAjC;QACY,YAAO,GAAW,EAAE,CAAC;QACrB,WAAM,GAAqB,IAAI,CAAC;QAChC,eAAU,GAAG,CAAC,CAAC;QACf,mBAAc,GAAG,KAAK,CAAC;QACvB,gBAAW,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,sBAAsB;IAsDpE,CAAC;IApDC;;OAEG;IACO,KAAK,CAAC,OAAO,CACrB,QAAgB,EAChB,UAAuB,EAAE,EACzB,UAAU,GAAG,CAAC;QAEd,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,QAAQ,EAAE,CAAC;YAEzC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;YAE1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,GAAG,OAAO;gBACV,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,YAAY,CAAC,OAAO,CAAC,CAAC;YAEtB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YACrE,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,OAAO,IAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,CAAC,CAAC,CAAC;YAEhB,kDAAkD;YAClD,IAAI,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;gBAC3C,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;oBAC3B,OAAO,CAAC,IAAI,CAAC,kCAAkC,KAAK,OAAO,EAAE,KAAK,CAAC,CAAC;gBACtE,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;gBACzD,OAAO,IAAI,CAAC,OAAO,CAAI,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;YAC5D,CAAC;YAED,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAES,WAAW,CAAC,KAAU;QAC9B,iDAAiD;QACjD,IAAI,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,0CAA0C;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"zhtp-api-core.js","sourceRoot":"","sources":["../../src/core/zhtp-api-core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,MAAM,OAAgB,WAAW;IAa/B,YAAY,YAA2B;QAZ7B,YAAO,GAAW,EAAE,CAAC;QACrB,WAAM,GAAqB,IAAI,CAAC;QAChC,eAAU,GAAG,CAAC,CAAC;QACf,mBAAc,GAAG,KAAK,CAAC;QACvB,gBAAW,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,sBAAsB;QAShE,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED;;OAEG;IACO,KAAK,CAAC,OAAO,CACrB,QAAgB,EAChB,UAAuB,EAAE,EACzB,UAAU,GAAG,CAAC;QAEd,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,QAAQ,EAAE,CAAC;YAEzC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;YAE1E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE;gBAC5C,GAAG,OAAO;gBACV,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,YAAY,CAAC,OAAO,CAAC,CAAC;YAEtB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YACrE,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,OAAO,IAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,CAAC,CAAC,CAAC;YAEhB,kDAAkD;YAClD,IAAI,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;gBAC3C,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;oBAC3B,OAAO,CAAC,IAAI,CAAC,kCAAkC,KAAK,OAAO,EAAE,KAAK,CAAC,CAAC;gBACtE,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;gBACzD,OAAO,IAAI,CAAC,OAAO,CAAI,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;YAC5D,CAAC;YAED,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAES,WAAW,CAAC,KAAU;QAC9B,iDAAiD;QACjD,IAAI,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,0CAA0C;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;CACF"} \ No newline at end of file diff --git a/dist/core/zhtp-api.d.ts b/dist/core/zhtp-api.d.ts index d44bd3b..c5e855f 100644 --- a/dist/core/zhtp-api.d.ts +++ b/dist/core/zhtp-api.d.ts @@ -6,10 +6,15 @@ import { ConfigProvider } from './config-provider'; import { ApiConfig } from './types'; import { ZhtpApiMethods } from './zhtp-api-methods'; +import { FetchAdapter } from './zhtp-api-core'; export declare class ZhtpApi extends ZhtpApiMethods { private configProvider; private initPromise; - constructor(configProvider: ConfigProvider); + /** + * @param configProvider - Configuration provider for API settings + * @param fetchAdapter - Optional custom fetch implementation (e.g., QUIC-based for React Native) + */ + constructor(configProvider: ConfigProvider, fetchAdapter?: FetchAdapter); private initialize; /** * Ensure initialization is complete before making requests diff --git a/dist/core/zhtp-api.d.ts.map b/dist/core/zhtp-api.d.ts.map index 48d641b..9931c0f 100644 --- a/dist/core/zhtp-api.d.ts.map +++ b/dist/core/zhtp-api.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"zhtp-api.d.ts","sourceRoot":"","sources":["../../src/core/zhtp-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,qBAAa,OAAQ,SAAQ,cAAc;IACzC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,WAAW,CAAgB;gBAEvB,cAAc,EAAE,cAAc;YAM5B,UAAU;IAaxB;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxC,UAAU,IAAI,MAAM;IAIpB,SAAS,IAAI,SAAS,GAAG,IAAI;IAI7B,WAAW,IAAI,OAAO;IAIhB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;CAe3C"} \ No newline at end of file +{"version":3,"file":"zhtp-api.d.ts","sourceRoot":"","sources":["../../src/core/zhtp-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,qBAAa,OAAQ,SAAQ,cAAc;IACzC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,WAAW,CAAgB;IAEnC;;;OAGG;gBACS,cAAc,EAAE,cAAc,EAAE,YAAY,CAAC,EAAE,YAAY;YAMzD,UAAU;IAaxB;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxC,UAAU,IAAI,MAAM;IAIpB,SAAS,IAAI,SAAS,GAAG,IAAI;IAI7B,WAAW,IAAI,OAAO;IAIhB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;CAe3C"} \ No newline at end of file diff --git a/dist/core/zhtp-api.js b/dist/core/zhtp-api.js index 45c9904..7a2f75a 100644 --- a/dist/core/zhtp-api.js +++ b/dist/core/zhtp-api.js @@ -5,8 +5,12 @@ */ import { ZhtpApiMethods } from './zhtp-api-methods.js'; export class ZhtpApi extends ZhtpApiMethods { - constructor(configProvider) { - super(); + /** + * @param configProvider - Configuration provider for API settings + * @param fetchAdapter - Optional custom fetch implementation (e.g., QUIC-based for React Native) + */ + constructor(configProvider, fetchAdapter) { + super(fetchAdapter); this.configProvider = configProvider; this.initPromise = this.initialize(); } diff --git a/dist/core/zhtp-api.js.map b/dist/core/zhtp-api.js.map index 5855fd4..a504225 100644 --- a/dist/core/zhtp-api.js.map +++ b/dist/core/zhtp-api.js.map @@ -1 +1 @@ -{"version":3,"file":"zhtp-api.js","sourceRoot":"","sources":["../../src/core/zhtp-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,OAAO,OAAQ,SAAQ,cAAc;IAIzC,YAAY,cAA8B;QACxC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IACvC,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;YACpD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;YACvC,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;YACzD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB;QACrB,MAAM,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAED,4DAA4D;IAE5D,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,WAAW;QACT,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,6BAA6B;QAC7B,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;YACpD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;YACvC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;YACvD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"zhtp-api.js","sourceRoot":"","sources":["../../src/core/zhtp-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,OAAO,OAAQ,SAAQ,cAAc;IAIzC;;;OAGG;IACH,YAAY,cAA8B,EAAE,YAA2B;QACrE,KAAK,CAAC,YAAY,CAAC,CAAC;QACpB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IACvC,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;YACpD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;YACvC,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;YACzD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB;QACrB,MAAM,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAED,4DAA4D;IAE5D,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,WAAW;QACT,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,6BAA6B;QAC7B,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;YACpD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;YACvC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;YACvD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"} \ No newline at end of file diff --git a/dist/react-native/index.d.ts b/dist/react-native/index.d.ts index 0c8b5f6..8416496 100644 --- a/dist/react-native/index.d.ts +++ b/dist/react-native/index.d.ts @@ -4,6 +4,7 @@ */ export { ReactNativeConfigProvider } from './config-provider'; export { ZhtpApi } from '../core/zhtp-api'; +export type { FetchAdapter } from '../core/zhtp-api-core'; export type { Identity, Wallet, WalletInfo, NetworkStatus, DaoProposal, DaoStats, Transaction, ApiConfig, ApiResponse, IdentityRecoveryData, Delegate, ProposalDetails, TreasuryRecord, DApp, SmartContract, ContractPermissions, ContractDeploymentResult, ContractExecutionResult, Asset, NodeStatus, GasInfo, Proof, SignupRequest, SignupResponse, LoginRequest, LoginResponse, CitizenshipResult, } from '../core/types'; export type { ConfigProvider } from '../core/config-provider'; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/react-native/index.d.ts.map b/dist/react-native/index.d.ts.map index d9fb55d..401b654 100644 --- a/dist/react-native/index.d.ts.map +++ b/dist/react-native/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-native/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,YAAY,EACV,QAAQ,EACR,MAAM,EACN,UAAU,EACV,aAAa,EACb,WAAW,EACX,QAAQ,EACR,WAAW,EACX,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,IAAI,EACJ,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,KAAK,EACL,UAAU,EACV,OAAO,EACP,KAAK,EACL,aAAa,EACb,cAAc,EACd,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-native/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EACV,QAAQ,EACR,MAAM,EACN,UAAU,EACV,aAAa,EACb,WAAW,EACX,QAAQ,EACR,WAAW,EACX,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,IAAI,EACJ,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,KAAK,EACL,UAAU,EACV,OAAO,EACP,KAAK,EACL,aAAa,EACb,cAAc,EACd,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC"} \ No newline at end of file diff --git a/dist/vanilla-js/index.d.ts b/dist/vanilla-js/index.d.ts index 2085bb8..10053f2 100644 --- a/dist/vanilla-js/index.d.ts +++ b/dist/vanilla-js/index.d.ts @@ -4,6 +4,7 @@ */ export { BrowserConfigProvider } from './config-provider'; export { ZhtpApi } from '../core/zhtp-api'; +export type { FetchAdapter } from '../core/zhtp-api-core'; export type { Identity, Wallet, NetworkStatus, DaoProposal, DaoStats, Transaction, ApiConfig, ApiResponse, IdentityRecoveryData, Delegate, ProposalDetails, TreasuryRecord, DApp, SmartContract, ContractPermissions, ContractDeploymentResult, ContractExecutionResult, Asset, NodeStatus, GasInfo, Proof, } from '../core/types'; export type { ConfigProvider } from '../core/config-provider'; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/vanilla-js/index.d.ts.map b/dist/vanilla-js/index.d.ts.map index ed92733..e5c9f06 100644 --- a/dist/vanilla-js/index.d.ts.map +++ b/dist/vanilla-js/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vanilla-js/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,YAAY,EACV,QAAQ,EACR,MAAM,EACN,aAAa,EACb,WAAW,EACX,QAAQ,EACR,WAAW,EACX,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,IAAI,EACJ,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,KAAK,EACL,UAAU,EACV,OAAO,EACP,KAAK,GACN,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vanilla-js/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EACV,QAAQ,EACR,MAAM,EACN,aAAa,EACb,WAAW,EACX,QAAQ,EACR,WAAW,EACX,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,IAAI,EACJ,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,KAAK,EACL,UAAU,EACV,OAAO,EACP,KAAK,GACN,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC"} \ No newline at end of file diff --git a/src/core/zhtp-api-core.ts b/src/core/zhtp-api-core.ts index 0d32c31..5341521 100644 --- a/src/core/zhtp-api-core.ts +++ b/src/core/zhtp-api-core.ts @@ -5,6 +5,12 @@ import { ApiConfig } from './types'; +/** + * Transport adapter for custom network implementations (e.g., QUIC) + * React Native apps can provide their own fetch implementation using native QUIC + */ +export type FetchAdapter = (url: string, options?: RequestInit) => Promise; + export abstract class ZhtpApiCore { protected baseUrl: string = ''; protected config: ApiConfig | null = null; @@ -12,6 +18,16 @@ export abstract class ZhtpApiCore { protected requestTimeout = 10000; protected retryDelays = [1000, 2000, 4000]; // Exponential backoff + /** + * Custom fetch adapter (e.g., QUIC-based fetch for React Native) + * Defaults to global fetch if not provided + */ + protected fetchAdapter: FetchAdapter; + + constructor(fetchAdapter?: FetchAdapter) { + this.fetchAdapter = fetchAdapter || ((url, options) => fetch(url, options)); + } + /** * Generic request method with retry logic and timeout */ @@ -26,7 +42,7 @@ export abstract class ZhtpApiCore { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), this.requestTimeout); - const response = await fetch(url, { + const response = await this.fetchAdapter(url, { ...options, signal: controller.signal, }); diff --git a/src/core/zhtp-api.ts b/src/core/zhtp-api.ts index c51f9bc..3452f2f 100644 --- a/src/core/zhtp-api.ts +++ b/src/core/zhtp-api.ts @@ -7,13 +7,18 @@ import { ConfigProvider } from './config-provider'; import { ApiConfig } from './types'; import { ZhtpApiMethods } from './zhtp-api-methods'; +import { FetchAdapter } from './zhtp-api-core'; export class ZhtpApi extends ZhtpApiMethods { private configProvider: ConfigProvider; private initPromise: Promise; - constructor(configProvider: ConfigProvider) { - super(); + /** + * @param configProvider - Configuration provider for API settings + * @param fetchAdapter - Optional custom fetch implementation (e.g., QUIC-based for React Native) + */ + constructor(configProvider: ConfigProvider, fetchAdapter?: FetchAdapter) { + super(fetchAdapter); this.configProvider = configProvider; this.initPromise = this.initialize(); } diff --git a/src/react-native/index.ts b/src/react-native/index.ts index 0b28eb6..460f58a 100644 --- a/src/react-native/index.ts +++ b/src/react-native/index.ts @@ -5,6 +5,7 @@ export { ReactNativeConfigProvider } from './config-provider'; export { ZhtpApi } from '../core/zhtp-api'; +export type { FetchAdapter } from '../core/zhtp-api-core'; export type { Identity, Wallet, diff --git a/src/vanilla-js/index.ts b/src/vanilla-js/index.ts index 72814c4..899fce7 100644 --- a/src/vanilla-js/index.ts +++ b/src/vanilla-js/index.ts @@ -5,6 +5,7 @@ export { BrowserConfigProvider } from './config-provider'; export { ZhtpApi } from '../core/zhtp-api'; +export type { FetchAdapter } from '../core/zhtp-api-core'; export type { Identity, Wallet,