feat(sdk): add Database, Hosting, and Bridge SDKs for Flutter

Phase 3 SDK expansion - Flutter/Dart implementations:

- Database SDK: Multi-model database with Key-Value, Document,
  Vector, and Time Series stores
- Hosting SDK: Decentralized web hosting with domain management,
  DNS, deployments, and SSL provisioning
- Bridge SDK: Cross-chain asset transfers with lock-mint and
  burn-unlock patterns

All SDKs follow consistent patterns with:
- Async/await API using Futures
- Proper error handling with typed exceptions
- Configurable retry logic and timeouts
- Full type safety with Dart's type system
This commit is contained in:
Gulshan Yadav 2026-01-27 02:00:41 +05:30
parent 74b82d2bb2
commit dd01a06116
7 changed files with 2109 additions and 0 deletions

View file

@ -0,0 +1,325 @@
/// Synor Bridge SDK Client for Flutter
///
/// Cross-chain asset transfers with lock-mint and burn-unlock patterns.
library synor_bridge;
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'types.dart';
export 'types.dart';
/// Synor Bridge Client
class SynorBridge {
final BridgeConfig config;
final http.Client _client;
bool _closed = false;
static const _finalStatuses = {
TransferStatus.completed,
TransferStatus.failed,
TransferStatus.refunded,
};
SynorBridge(this.config) : _client = http.Client();
// ==================== Chain Operations ====================
Future<List<Chain>> getSupportedChains() async {
final resp = await _request('GET', '/chains');
return (resp['chains'] as List).map((e) => Chain.fromJson(e)).toList();
}
Future<Chain> getChain(ChainId chainId) async {
final resp = await _request('GET', '/chains/${chainId.name}');
return Chain.fromJson(resp);
}
Future<bool> isChainSupported(ChainId chainId) async {
try {
final chain = await getChain(chainId);
return chain.supported;
} catch (_) {
return false;
}
}
// ==================== Asset Operations ====================
Future<List<Asset>> getSupportedAssets(ChainId chainId) async {
final resp = await _request('GET', '/chains/${chainId.name}/assets');
return (resp['assets'] as List).map((e) => Asset.fromJson(e)).toList();
}
Future<Asset> getAsset(String assetId) async {
final resp = await _request('GET', '/assets/${Uri.encodeComponent(assetId)}');
return Asset.fromJson(resp);
}
Future<WrappedAsset> getWrappedAsset(String originalAssetId, ChainId targetChain) async {
final path = '/assets/${Uri.encodeComponent(originalAssetId)}/wrapped/${targetChain.name}';
final resp = await _request('GET', path);
return WrappedAsset.fromJson(resp);
}
// ==================== Fee & Rate Operations ====================
Future<FeeEstimate> estimateFee(String asset, String amount, ChainId sourceChain, ChainId targetChain) async {
final resp = await _request('POST', '/fees/estimate', {
'asset': asset,
'amount': amount,
'sourceChain': sourceChain.name,
'targetChain': targetChain.name,
});
return FeeEstimate.fromJson(resp);
}
Future<ExchangeRate> getExchangeRate(String fromAsset, String toAsset) async {
final path = '/rates/${Uri.encodeComponent(fromAsset)}/${Uri.encodeComponent(toAsset)}';
final resp = await _request('GET', path);
return ExchangeRate.fromJson(resp);
}
// ==================== Lock-Mint Flow ====================
Future<LockReceipt> lock(String asset, String amount, ChainId targetChain, {LockOptions? options}) async {
final body = <String, dynamic>{
'asset': asset,
'amount': amount,
'targetChain': targetChain.name,
};
if (options != null) body.addAll(options.toJson());
final resp = await _request('POST', '/transfers/lock', body);
return LockReceipt.fromJson(resp);
}
Future<LockProof> getLockProof(String lockReceiptId) async {
final resp = await _request('GET', '/transfers/lock/${Uri.encodeComponent(lockReceiptId)}/proof');
return LockProof.fromJson(resp);
}
Future<LockProof> waitForLockProof(
String lockReceiptId, {
Duration pollInterval = const Duration(seconds: 5),
Duration maxWait = const Duration(minutes: 10),
}) async {
final deadline = DateTime.now().add(maxWait);
while (DateTime.now().isBefore(deadline)) {
try {
return await getLockProof(lockReceiptId);
} on BridgeException catch (e) {
if (e.isConfirmationsPending) {
await Future.delayed(pollInterval);
continue;
}
rethrow;
}
}
throw const BridgeException('Timeout waiting for lock proof', code: 'CONFIRMATIONS_PENDING');
}
Future<SignedTransaction> mint(LockProof proof, String targetAddress, {MintOptions? options}) async {
final body = <String, dynamic>{
'proof': proof.toJson(),
'targetAddress': targetAddress,
};
if (options != null) body.addAll(options.toJson());
final resp = await _request('POST', '/transfers/mint', body);
return SignedTransaction.fromJson(resp);
}
// ==================== Burn-Unlock Flow ====================
Future<BurnReceipt> burn(String wrappedAsset, String amount, {BurnOptions? options}) async {
final body = <String, dynamic>{
'wrappedAsset': wrappedAsset,
'amount': amount,
};
if (options != null) body.addAll(options.toJson());
final resp = await _request('POST', '/transfers/burn', body);
return BurnReceipt.fromJson(resp);
}
Future<BurnProof> getBurnProof(String burnReceiptId) async {
final resp = await _request('GET', '/transfers/burn/${Uri.encodeComponent(burnReceiptId)}/proof');
return BurnProof.fromJson(resp);
}
Future<BurnProof> waitForBurnProof(
String burnReceiptId, {
Duration pollInterval = const Duration(seconds: 5),
Duration maxWait = const Duration(minutes: 10),
}) async {
final deadline = DateTime.now().add(maxWait);
while (DateTime.now().isBefore(deadline)) {
try {
return await getBurnProof(burnReceiptId);
} on BridgeException catch (e) {
if (e.isConfirmationsPending) {
await Future.delayed(pollInterval);
continue;
}
rethrow;
}
}
throw const BridgeException('Timeout waiting for burn proof', code: 'CONFIRMATIONS_PENDING');
}
Future<SignedTransaction> unlock(BurnProof proof, {UnlockOptions? options}) async {
final body = <String, dynamic>{'proof': proof.toJson()};
if (options != null) body.addAll(options.toJson());
final resp = await _request('POST', '/transfers/unlock', body);
return SignedTransaction.fromJson(resp);
}
// ==================== Transfer Management ====================
Future<Transfer> getTransfer(String transferId) async {
final resp = await _request('GET', '/transfers/${Uri.encodeComponent(transferId)}');
return Transfer.fromJson(resp);
}
Future<TransferStatus> getTransferStatus(String transferId) async {
final transfer = await getTransfer(transferId);
return transfer.status;
}
Future<List<Transfer>> listTransfers({TransferFilter? filter}) async {
var path = '/transfers';
final params = <String>[];
if (filter?.status != null) params.add('status=${filter!.status!.name}');
if (filter?.sourceChain != null) params.add('sourceChain=${filter!.sourceChain!.name}');
if (filter?.targetChain != null) params.add('targetChain=${filter!.targetChain!.name}');
if (filter?.limit != null) params.add('limit=${filter!.limit}');
if (filter?.offset != null) params.add('offset=${filter!.offset}');
if (params.isNotEmpty) path = '$path?${params.join('&')}';
final resp = await _request('GET', path);
return (resp['transfers'] as List).map((e) => Transfer.fromJson(e)).toList();
}
Future<Transfer> waitForTransfer(
String transferId, {
Duration pollInterval = const Duration(seconds: 10),
Duration maxWait = const Duration(minutes: 30),
}) async {
final deadline = DateTime.now().add(maxWait);
while (DateTime.now().isBefore(deadline)) {
final transfer = await getTransfer(transferId);
if (_finalStatuses.contains(transfer.status)) {
return transfer;
}
await Future.delayed(pollInterval);
}
throw const BridgeException('Timeout waiting for transfer completion');
}
// ==================== Convenience Methods ====================
Future<Transfer> bridgeTo(
String asset,
String amount,
ChainId targetChain,
String targetAddress, {
LockOptions? lockOptions,
MintOptions? mintOptions,
}) async {
final lockReceipt = await lock(asset, amount, targetChain, options: lockOptions);
if (config.debug) print('Locked: ${lockReceipt.id}, waiting for confirmations...');
final proof = await waitForLockProof(lockReceipt.id);
if (config.debug) print('Proof ready, minting on ${targetChain.name}...');
await mint(proof, targetAddress, options: mintOptions);
return waitForTransfer(lockReceipt.id);
}
Future<Transfer> bridgeBack(
String wrappedAsset,
String amount, {
BurnOptions? burnOptions,
UnlockOptions? unlockOptions,
}) async {
final burnReceipt = await burn(wrappedAsset, amount, options: burnOptions);
if (config.debug) print('Burned: ${burnReceipt.id}, waiting for confirmations...');
final proof = await waitForBurnProof(burnReceipt.id);
if (config.debug) print('Proof ready, unlocking on ${burnReceipt.targetChain.name}...');
await unlock(proof, options: unlockOptions);
return waitForTransfer(burnReceipt.id);
}
// ==================== Lifecycle ====================
void close() {
_closed = true;
_client.close();
}
bool get isClosed => _closed;
Future<bool> healthCheck() async {
try {
final resp = await _request('GET', '/health');
return resp['status'] == 'healthy';
} catch (_) {
return false;
}
}
// ==================== Private Methods ====================
Future<Map<String, dynamic>> _request(String method, String path, [Map<String, dynamic>? body]) async {
if (_closed) throw const BridgeException('Client has been closed');
Exception? lastError;
for (var attempt = 0; attempt < config.retries; attempt++) {
try {
return await _doRequest(method, path, body);
} catch (e) {
lastError = e as Exception;
if (attempt < config.retries - 1) {
await Future.delayed(Duration(seconds: 1 << attempt));
}
}
}
throw lastError ?? const BridgeException('Unknown error');
}
Future<Map<String, dynamic>> _doRequest(String method, String path, Map<String, dynamic>? body) async {
final uri = Uri.parse('${config.endpoint}$path');
final headers = {
'Authorization': 'Bearer ${config.apiKey}',
'Content-Type': 'application/json',
'X-SDK-Version': 'flutter/0.1.0',
};
http.Response response;
switch (method) {
case 'GET':
response = await _client.get(uri, headers: headers);
break;
case 'POST':
response = await _client.post(uri, headers: headers, body: body != null ? jsonEncode(body) : null);
break;
case 'DELETE':
response = await _client.delete(uri, headers: headers);
break;
default:
throw BridgeException('Unknown method: $method');
}
if (response.statusCode >= 400) {
final error = jsonDecode(response.body) as Map<String, dynamic>;
throw BridgeException(
error['message'] as String? ?? 'HTTP ${response.statusCode}',
code: error['code'] as String?,
statusCode: response.statusCode,
);
}
if (response.body.isEmpty) return {};
return jsonDecode(response.body) as Map<String, dynamic>;
}
}

View file

@ -0,0 +1,636 @@
/// Synor Bridge SDK Types for Flutter
///
/// Cross-chain asset transfers with lock-mint and burn-unlock patterns.
library synor_bridge_types;
// ==================== Chain Types ====================
/// Supported blockchain networks
enum ChainId { synor, ethereum, polygon, arbitrum, optimism, bsc, avalanche, solana, cosmos }
/// Native currency info
class NativeCurrency {
final String name;
final String symbol;
final int decimals;
const NativeCurrency({required this.name, required this.symbol, required this.decimals});
factory NativeCurrency.fromJson(Map<String, dynamic> json) => NativeCurrency(
name: json['name'] as String,
symbol: json['symbol'] as String,
decimals: json['decimals'] as int,
);
}
/// Chain information
class Chain {
final ChainId id;
final String name;
final int chainId;
final String rpcUrl;
final String explorerUrl;
final NativeCurrency nativeCurrency;
final int confirmations;
final int estimatedBlockTime;
final bool supported;
const Chain({
required this.id,
required this.name,
required this.chainId,
required this.rpcUrl,
required this.explorerUrl,
required this.nativeCurrency,
required this.confirmations,
required this.estimatedBlockTime,
required this.supported,
});
factory Chain.fromJson(Map<String, dynamic> json) => Chain(
id: ChainId.values.firstWhere((e) => e.name == json['id']),
name: json['name'] as String,
chainId: json['chainId'] as int,
rpcUrl: json['rpcUrl'] as String,
explorerUrl: json['explorerUrl'] as String,
nativeCurrency: NativeCurrency.fromJson(json['nativeCurrency']),
confirmations: json['confirmations'] as int,
estimatedBlockTime: json['estimatedBlockTime'] as int,
supported: json['supported'] as bool,
);
}
// ==================== Asset Types ====================
/// Asset type
enum AssetType { native, erc20, erc721, erc1155 }
/// Asset information
class Asset {
final String id;
final String symbol;
final String name;
final AssetType type;
final ChainId chain;
final String? contractAddress;
final int decimals;
final String? logoUrl;
final bool verified;
const Asset({
required this.id,
required this.symbol,
required this.name,
required this.type,
required this.chain,
this.contractAddress,
required this.decimals,
this.logoUrl,
this.verified = false,
});
factory Asset.fromJson(Map<String, dynamic> json) => Asset(
id: json['id'] as String,
symbol: json['symbol'] as String,
name: json['name'] as String,
type: AssetType.values.firstWhere((e) => e.name == json['type']),
chain: ChainId.values.firstWhere((e) => e.name == json['chain']),
contractAddress: json['contractAddress'] as String?,
decimals: json['decimals'] as int,
logoUrl: json['logoUrl'] as String?,
verified: json['verified'] as bool? ?? false,
);
Map<String, dynamic> toJson() => {
'id': id,
'symbol': symbol,
'name': name,
'type': type.name,
'chain': chain.name,
if (contractAddress != null) 'contractAddress': contractAddress,
'decimals': decimals,
if (logoUrl != null) 'logoUrl': logoUrl,
'verified': verified,
};
}
/// Wrapped asset mapping
class WrappedAsset {
final Asset originalAsset;
final Asset wrappedAsset;
final ChainId chain;
final String bridgeContract;
const WrappedAsset({
required this.originalAsset,
required this.wrappedAsset,
required this.chain,
required this.bridgeContract,
});
factory WrappedAsset.fromJson(Map<String, dynamic> json) => WrappedAsset(
originalAsset: Asset.fromJson(json['originalAsset']),
wrappedAsset: Asset.fromJson(json['wrappedAsset']),
chain: ChainId.values.firstWhere((e) => e.name == json['chain']),
bridgeContract: json['bridgeContract'] as String,
);
}
// ==================== Transfer Types ====================
/// Transfer status
enum TransferStatus { pending, locked, confirming, minting, completed, failed, refunded }
/// Transfer direction
enum TransferDirection { lockMint, burnUnlock }
/// Validator signature
class ValidatorSignature {
final String validator;
final String signature;
final int timestamp;
const ValidatorSignature({
required this.validator,
required this.signature,
required this.timestamp,
});
factory ValidatorSignature.fromJson(Map<String, dynamic> json) => ValidatorSignature(
validator: json['validator'] as String,
signature: json['signature'] as String,
timestamp: json['timestamp'] as int,
);
Map<String, dynamic> toJson() => {
'validator': validator,
'signature': signature,
'timestamp': timestamp,
};
}
/// Lock receipt
class LockReceipt {
final String id;
final String txHash;
final ChainId sourceChain;
final ChainId targetChain;
final Asset asset;
final String amount;
final String sender;
final String recipient;
final int lockTimestamp;
final int confirmations;
final int requiredConfirmations;
const LockReceipt({
required this.id,
required this.txHash,
required this.sourceChain,
required this.targetChain,
required this.asset,
required this.amount,
required this.sender,
required this.recipient,
required this.lockTimestamp,
required this.confirmations,
required this.requiredConfirmations,
});
factory LockReceipt.fromJson(Map<String, dynamic> json) => LockReceipt(
id: json['id'] as String,
txHash: json['txHash'] as String,
sourceChain: ChainId.values.firstWhere((e) => e.name == json['sourceChain']),
targetChain: ChainId.values.firstWhere((e) => e.name == json['targetChain']),
asset: Asset.fromJson(json['asset']),
amount: json['amount'] as String,
sender: json['sender'] as String,
recipient: json['recipient'] as String,
lockTimestamp: json['lockTimestamp'] as int,
confirmations: json['confirmations'] as int,
requiredConfirmations: json['requiredConfirmations'] as int,
);
Map<String, dynamic> toJson() => {
'id': id,
'txHash': txHash,
'sourceChain': sourceChain.name,
'targetChain': targetChain.name,
'asset': asset.toJson(),
'amount': amount,
'sender': sender,
'recipient': recipient,
'lockTimestamp': lockTimestamp,
'confirmations': confirmations,
'requiredConfirmations': requiredConfirmations,
};
}
/// Lock proof
class LockProof {
final LockReceipt lockReceipt;
final List<String> merkleProof;
final String blockHeader;
final List<ValidatorSignature> signatures;
const LockProof({
required this.lockReceipt,
required this.merkleProof,
required this.blockHeader,
required this.signatures,
});
factory LockProof.fromJson(Map<String, dynamic> json) => LockProof(
lockReceipt: LockReceipt.fromJson(json['lockReceipt']),
merkleProof: List<String>.from(json['merkleProof']),
blockHeader: json['blockHeader'] as String,
signatures: (json['signatures'] as List)
.map((e) => ValidatorSignature.fromJson(e))
.toList(),
);
Map<String, dynamic> toJson() => {
'lockReceipt': lockReceipt.toJson(),
'merkleProof': merkleProof,
'blockHeader': blockHeader,
'signatures': signatures.map((s) => s.toJson()).toList(),
};
}
/// Burn receipt
class BurnReceipt {
final String id;
final String txHash;
final ChainId sourceChain;
final ChainId targetChain;
final Asset wrappedAsset;
final Asset originalAsset;
final String amount;
final String sender;
final String recipient;
final int burnTimestamp;
final int confirmations;
final int requiredConfirmations;
const BurnReceipt({
required this.id,
required this.txHash,
required this.sourceChain,
required this.targetChain,
required this.wrappedAsset,
required this.originalAsset,
required this.amount,
required this.sender,
required this.recipient,
required this.burnTimestamp,
required this.confirmations,
required this.requiredConfirmations,
});
factory BurnReceipt.fromJson(Map<String, dynamic> json) => BurnReceipt(
id: json['id'] as String,
txHash: json['txHash'] as String,
sourceChain: ChainId.values.firstWhere((e) => e.name == json['sourceChain']),
targetChain: ChainId.values.firstWhere((e) => e.name == json['targetChain']),
wrappedAsset: Asset.fromJson(json['wrappedAsset']),
originalAsset: Asset.fromJson(json['originalAsset']),
amount: json['amount'] as String,
sender: json['sender'] as String,
recipient: json['recipient'] as String,
burnTimestamp: json['burnTimestamp'] as int,
confirmations: json['confirmations'] as int,
requiredConfirmations: json['requiredConfirmations'] as int,
);
Map<String, dynamic> toJson() => {
'id': id,
'txHash': txHash,
'sourceChain': sourceChain.name,
'targetChain': targetChain.name,
'wrappedAsset': wrappedAsset.toJson(),
'originalAsset': originalAsset.toJson(),
'amount': amount,
'sender': sender,
'recipient': recipient,
'burnTimestamp': burnTimestamp,
'confirmations': confirmations,
'requiredConfirmations': requiredConfirmations,
};
}
/// Burn proof
class BurnProof {
final BurnReceipt burnReceipt;
final List<String> merkleProof;
final String blockHeader;
final List<ValidatorSignature> signatures;
const BurnProof({
required this.burnReceipt,
required this.merkleProof,
required this.blockHeader,
required this.signatures,
});
factory BurnProof.fromJson(Map<String, dynamic> json) => BurnProof(
burnReceipt: BurnReceipt.fromJson(json['burnReceipt']),
merkleProof: List<String>.from(json['merkleProof']),
blockHeader: json['blockHeader'] as String,
signatures: (json['signatures'] as List)
.map((e) => ValidatorSignature.fromJson(e))
.toList(),
);
Map<String, dynamic> toJson() => {
'burnReceipt': burnReceipt.toJson(),
'merkleProof': merkleProof,
'blockHeader': blockHeader,
'signatures': signatures.map((s) => s.toJson()).toList(),
};
}
/// Transfer record
class Transfer {
final String id;
final TransferDirection direction;
final TransferStatus status;
final ChainId sourceChain;
final ChainId targetChain;
final Asset asset;
final String amount;
final String sender;
final String recipient;
final String? sourceTxHash;
final String? targetTxHash;
final String fee;
final Asset feeAsset;
final int createdAt;
final int updatedAt;
final int? completedAt;
final String? errorMessage;
const Transfer({
required this.id,
required this.direction,
required this.status,
required this.sourceChain,
required this.targetChain,
required this.asset,
required this.amount,
required this.sender,
required this.recipient,
this.sourceTxHash,
this.targetTxHash,
required this.fee,
required this.feeAsset,
required this.createdAt,
required this.updatedAt,
this.completedAt,
this.errorMessage,
});
factory Transfer.fromJson(Map<String, dynamic> json) => Transfer(
id: json['id'] as String,
direction: json['direction'] == 'lock_mint'
? TransferDirection.lockMint
: TransferDirection.burnUnlock,
status: TransferStatus.values.firstWhere((e) => e.name == json['status']),
sourceChain: ChainId.values.firstWhere((e) => e.name == json['sourceChain']),
targetChain: ChainId.values.firstWhere((e) => e.name == json['targetChain']),
asset: Asset.fromJson(json['asset']),
amount: json['amount'] as String,
sender: json['sender'] as String,
recipient: json['recipient'] as String,
sourceTxHash: json['sourceTxHash'] as String?,
targetTxHash: json['targetTxHash'] as String?,
fee: json['fee'] as String,
feeAsset: Asset.fromJson(json['feeAsset']),
createdAt: json['createdAt'] as int,
updatedAt: json['updatedAt'] as int,
completedAt: json['completedAt'] as int?,
errorMessage: json['errorMessage'] as String?,
);
}
// ==================== Fee Types ====================
/// Fee estimate
class FeeEstimate {
final String bridgeFee;
final String gasFeeSource;
final String gasFeeTarget;
final String totalFee;
final Asset feeAsset;
final int estimatedTime;
final String? exchangeRate;
const FeeEstimate({
required this.bridgeFee,
required this.gasFeeSource,
required this.gasFeeTarget,
required this.totalFee,
required this.feeAsset,
required this.estimatedTime,
this.exchangeRate,
});
factory FeeEstimate.fromJson(Map<String, dynamic> json) => FeeEstimate(
bridgeFee: json['bridgeFee'] as String,
gasFeeSource: json['gasFeeSource'] as String,
gasFeeTarget: json['gasFeeTarget'] as String,
totalFee: json['totalFee'] as String,
feeAsset: Asset.fromJson(json['feeAsset']),
estimatedTime: json['estimatedTime'] as int,
exchangeRate: json['exchangeRate'] as String?,
);
}
/// Exchange rate
class ExchangeRate {
final Asset fromAsset;
final Asset toAsset;
final String rate;
final String inverseRate;
final int lastUpdated;
final String source;
const ExchangeRate({
required this.fromAsset,
required this.toAsset,
required this.rate,
required this.inverseRate,
required this.lastUpdated,
required this.source,
});
factory ExchangeRate.fromJson(Map<String, dynamic> json) => ExchangeRate(
fromAsset: Asset.fromJson(json['fromAsset']),
toAsset: Asset.fromJson(json['toAsset']),
rate: json['rate'] as String,
inverseRate: json['inverseRate'] as String,
lastUpdated: json['lastUpdated'] as int,
source: json['source'] as String,
);
}
/// Signed transaction
class SignedTransaction {
final String txHash;
final ChainId chain;
final String from;
final String to;
final String value;
final String data;
final String gasLimit;
final String? gasPrice;
final String? maxFeePerGas;
final String? maxPriorityFeePerGas;
final int nonce;
final String signature;
const SignedTransaction({
required this.txHash,
required this.chain,
required this.from,
required this.to,
required this.value,
required this.data,
required this.gasLimit,
this.gasPrice,
this.maxFeePerGas,
this.maxPriorityFeePerGas,
required this.nonce,
required this.signature,
});
factory SignedTransaction.fromJson(Map<String, dynamic> json) => SignedTransaction(
txHash: json['txHash'] as String,
chain: ChainId.values.firstWhere((e) => e.name == json['chain']),
from: json['from'] as String,
to: json['to'] as String,
value: json['value'] as String,
data: json['data'] as String,
gasLimit: json['gasLimit'] as String,
gasPrice: json['gasPrice'] as String?,
maxFeePerGas: json['maxFeePerGas'] as String?,
maxPriorityFeePerGas: json['maxPriorityFeePerGas'] as String?,
nonce: json['nonce'] as int,
signature: json['signature'] as String,
);
}
// ==================== Options & Filter ====================
/// Lock options
class LockOptions {
final String? recipient;
final int? deadline;
final double? slippage;
const LockOptions({this.recipient, this.deadline, this.slippage});
Map<String, dynamic> toJson() => {
if (recipient != null) 'recipient': recipient,
if (deadline != null) 'deadline': deadline,
if (slippage != null) 'slippage': slippage,
};
}
/// Mint options
class MintOptions {
final String? gasLimit;
final String? maxFeePerGas;
final String? maxPriorityFeePerGas;
const MintOptions({this.gasLimit, this.maxFeePerGas, this.maxPriorityFeePerGas});
Map<String, dynamic> toJson() => {
if (gasLimit != null) 'gasLimit': gasLimit,
if (maxFeePerGas != null) 'maxFeePerGas': maxFeePerGas,
if (maxPriorityFeePerGas != null) 'maxPriorityFeePerGas': maxPriorityFeePerGas,
};
}
/// Burn options
class BurnOptions {
final String? recipient;
final int? deadline;
const BurnOptions({this.recipient, this.deadline});
Map<String, dynamic> toJson() => {
if (recipient != null) 'recipient': recipient,
if (deadline != null) 'deadline': deadline,
};
}
/// Unlock options
class UnlockOptions {
final String? gasLimit;
final String? gasPrice;
const UnlockOptions({this.gasLimit, this.gasPrice});
Map<String, dynamic> toJson() => {
if (gasLimit != null) 'gasLimit': gasLimit,
if (gasPrice != null) 'gasPrice': gasPrice,
};
}
/// Transfer filter
class TransferFilter {
final TransferStatus? status;
final ChainId? sourceChain;
final ChainId? targetChain;
final String? asset;
final String? sender;
final String? recipient;
final int? limit;
final int? offset;
const TransferFilter({
this.status,
this.sourceChain,
this.targetChain,
this.asset,
this.sender,
this.recipient,
this.limit,
this.offset,
});
}
// ==================== Config ====================
/// Bridge configuration
class BridgeConfig {
final String apiKey;
final String endpoint;
final Duration timeout;
final int retries;
final bool debug;
const BridgeConfig({
required this.apiKey,
this.endpoint = 'https://bridge.synor.io/v1',
this.timeout = const Duration(seconds: 60),
this.retries = 3,
this.debug = false,
});
}
// ==================== Error ====================
/// Bridge error
class BridgeException implements Exception {
final String message;
final String? code;
final int? statusCode;
const BridgeException(this.message, {this.code, this.statusCode});
bool get isConfirmationsPending => code == 'CONFIRMATIONS_PENDING';
@override
String toString() => 'BridgeException: $message';
}

View file

@ -0,0 +1,246 @@
/// Synor Database SDK Client for Flutter
///
/// Multi-model database with Key-Value, Document, Vector, and Time Series stores.
library synor_database;
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'types.dart';
export 'types.dart';
/// Synor Database Client
class SynorDatabase {
final DatabaseConfig config;
final http.Client _client;
bool _closed = false;
late final KeyValueStore kv;
late final DocumentStore documents;
late final VectorStore vectors;
late final TimeSeriesStore timeseries;
SynorDatabase(this.config) : _client = http.Client() {
kv = KeyValueStore(this);
documents = DocumentStore(this);
vectors = VectorStore(this);
timeseries = TimeSeriesStore(this);
}
/// Close the client
void close() {
_closed = true;
_client.close();
}
/// Check if closed
bool get isClosed => _closed;
/// Health check
Future<bool> healthCheck() async {
try {
final resp = await _request('GET', '/health');
return resp['status'] == 'healthy';
} catch (_) {
return false;
}
}
Future<Map<String, dynamic>> _request(
String method,
String path, [
Map<String, dynamic>? body,
]) async {
if (_closed) throw DatabaseException('Client has been closed');
Exception? lastError;
for (var attempt = 0; attempt < config.retries; attempt++) {
try {
return await _doRequest(method, path, body);
} catch (e) {
lastError = e as Exception;
if (attempt < config.retries - 1) {
await Future.delayed(Duration(seconds: 1 << attempt));
}
}
}
throw lastError ?? DatabaseException('Unknown error');
}
Future<Map<String, dynamic>> _doRequest(
String method,
String path,
Map<String, dynamic>? body,
) async {
final uri = Uri.parse('${config.endpoint}$path');
final headers = {
'Authorization': 'Bearer ${config.apiKey}',
'Content-Type': 'application/json',
'X-SDK-Version': 'flutter/0.1.0',
};
http.Response response;
switch (method) {
case 'GET':
response = await _client.get(uri, headers: headers);
break;
case 'POST':
response = await _client.post(uri, headers: headers, body: jsonEncode(body));
break;
case 'PUT':
response = await _client.put(uri, headers: headers, body: jsonEncode(body));
break;
case 'PATCH':
response = await _client.patch(uri, headers: headers, body: jsonEncode(body));
break;
case 'DELETE':
response = await _client.delete(uri, headers: headers, body: body != null ? jsonEncode(body) : null);
break;
default:
throw DatabaseException('Unknown method: $method');
}
if (response.statusCode >= 400) {
final error = jsonDecode(response.body) as Map<String, dynamic>;
throw DatabaseException(
error['message'] as String? ?? 'HTTP ${response.statusCode}',
code: error['code'] as String?,
statusCode: response.statusCode,
);
}
return jsonDecode(response.body) as Map<String, dynamic>;
}
}
/// Key-Value Store
class KeyValueStore {
final SynorDatabase _db;
KeyValueStore(this._db);
Future<dynamic> get(String key) async {
final resp = await _db._request('GET', '/kv/${Uri.encodeComponent(key)}');
return resp['value'];
}
Future<void> set(String key, dynamic value, {int? ttl}) async {
await _db._request('PUT', '/kv/${Uri.encodeComponent(key)}', {
'key': key,
'value': value,
if (ttl != null) 'ttl': ttl,
});
}
Future<void> delete(String key) async {
await _db._request('DELETE', '/kv/${Uri.encodeComponent(key)}');
}
Future<List<KeyValue>> list(String prefix) async {
final resp = await _db._request('GET', '/kv?prefix=${Uri.encodeComponent(prefix)}');
return (resp['items'] as List).map((e) => KeyValue.fromJson(e)).toList();
}
}
/// Document Store
class DocumentStore {
final SynorDatabase _db;
DocumentStore(this._db);
Future<String> create(String collection, Map<String, dynamic> document) async {
final resp = await _db._request(
'POST',
'/collections/${Uri.encodeComponent(collection)}/documents',
document,
);
return resp['id'] as String;
}
Future<Document> get(String collection, String id) async {
final resp = await _db._request(
'GET',
'/collections/${Uri.encodeComponent(collection)}/documents/${Uri.encodeComponent(id)}',
);
return Document.fromJson(resp);
}
Future<void> update(String collection, String id, Map<String, dynamic> update) async {
await _db._request(
'PATCH',
'/collections/${Uri.encodeComponent(collection)}/documents/${Uri.encodeComponent(id)}',
update,
);
}
Future<void> delete(String collection, String id) async {
await _db._request(
'DELETE',
'/collections/${Uri.encodeComponent(collection)}/documents/${Uri.encodeComponent(id)}',
);
}
Future<List<Document>> query(String collection, Query query) async {
final resp = await _db._request(
'POST',
'/collections/${Uri.encodeComponent(collection)}/query',
query.toJson(),
);
return (resp['documents'] as List).map((e) => Document.fromJson(e)).toList();
}
}
/// Vector Store
class VectorStore {
final SynorDatabase _db;
VectorStore(this._db);
Future<void> upsert(String collection, List<VectorEntry> vectors) async {
await _db._request(
'POST',
'/vectors/${Uri.encodeComponent(collection)}/upsert',
{'vectors': vectors.map((v) => v.toJson()).toList()},
);
}
Future<List<SearchResult>> search(String collection, List<double> vector, int k) async {
final resp = await _db._request(
'POST',
'/vectors/${Uri.encodeComponent(collection)}/search',
{'vector': vector, 'k': k},
);
return (resp['results'] as List).map((e) => SearchResult.fromJson(e)).toList();
}
Future<void> delete(String collection, List<String> ids) async {
await _db._request(
'DELETE',
'/vectors/${Uri.encodeComponent(collection)}',
{'ids': ids},
);
}
}
/// Time Series Store
class TimeSeriesStore {
final SynorDatabase _db;
TimeSeriesStore(this._db);
Future<void> write(String series, List<DataPoint> points) async {
await _db._request(
'POST',
'/timeseries/${Uri.encodeComponent(series)}/write',
{'points': points.map((p) => p.toJson()).toList()},
);
}
Future<List<DataPoint>> query(String series, TimeRange range, {Aggregation? aggregation}) async {
final body = <String, dynamic>{'range': range.toJson()};
if (aggregation != null) body['aggregation'] = aggregation.toJson();
final resp = await _db._request(
'POST',
'/timeseries/${Uri.encodeComponent(series)}/query',
body,
);
return (resp['points'] as List).map((e) => DataPoint.fromJson(e)).toList();
}
}

View file

@ -0,0 +1,224 @@
/// Synor Database SDK Types for Flutter
///
/// Multi-model database with Key-Value, Document, Vector, and Time Series stores.
library synor_database_types;
// ==================== Config ====================
/// Database configuration
class DatabaseConfig {
final String apiKey;
final String endpoint;
final Duration timeout;
final int retries;
final bool debug;
const DatabaseConfig({
required this.apiKey,
this.endpoint = 'https://db.synor.io/v1',
this.timeout = const Duration(seconds: 60),
this.retries = 3,
this.debug = false,
});
}
// ==================== Key-Value Types ====================
/// Key-Value entry
class KeyValue {
final String key;
final dynamic value;
final int? ttl;
final DateTime? createdAt;
final DateTime? updatedAt;
const KeyValue({
required this.key,
required this.value,
this.ttl,
this.createdAt,
this.updatedAt,
});
factory KeyValue.fromJson(Map<String, dynamic> json) => KeyValue(
key: json['key'] as String,
value: json['value'],
ttl: json['ttl'] as int?,
createdAt: json['createdAt'] != null
? DateTime.fromMillisecondsSinceEpoch(json['createdAt'] as int)
: null,
updatedAt: json['updatedAt'] != null
? DateTime.fromMillisecondsSinceEpoch(json['updatedAt'] as int)
: null,
);
}
// ==================== Document Types ====================
/// Document record
class Document {
final String id;
final String collection;
final Map<String, dynamic> data;
final DateTime createdAt;
final DateTime updatedAt;
const Document({
required this.id,
required this.collection,
required this.data,
required this.createdAt,
required this.updatedAt,
});
factory Document.fromJson(Map<String, dynamic> json) => Document(
id: json['id'] as String,
collection: json['collection'] as String,
data: Map<String, dynamic>.from(json['data'] as Map),
createdAt: DateTime.fromMillisecondsSinceEpoch(json['createdAt'] as int),
updatedAt: DateTime.fromMillisecondsSinceEpoch(json['updatedAt'] as int),
);
}
/// Query builder
class Query {
final Map<String, dynamic>? filter;
final Map<String, int>? sort;
final int? limit;
final int? offset;
final List<String>? projection;
const Query({
this.filter,
this.sort,
this.limit,
this.offset,
this.projection,
});
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (filter != null) json['filter'] = filter;
if (sort != null) json['sort'] = sort;
if (limit != null) json['limit'] = limit;
if (offset != null) json['offset'] = offset;
if (projection != null) json['projection'] = projection;
return json;
}
}
// ==================== Vector Types ====================
/// Vector entry for upsert
class VectorEntry {
final String id;
final List<double> vector;
final Map<String, dynamic>? metadata;
const VectorEntry({
required this.id,
required this.vector,
this.metadata,
});
Map<String, dynamic> toJson() => {
'id': id,
'vector': vector,
if (metadata != null) 'metadata': metadata,
};
}
/// Vector search result
class SearchResult {
final String id;
final double score;
final List<double>? vector;
final Map<String, dynamic>? metadata;
const SearchResult({
required this.id,
required this.score,
this.vector,
this.metadata,
});
factory SearchResult.fromJson(Map<String, dynamic> json) => SearchResult(
id: json['id'] as String,
score: (json['score'] as num).toDouble(),
vector: json['vector'] != null
? List<double>.from((json['vector'] as List).map((e) => (e as num).toDouble()))
: null,
metadata: json['metadata'] != null
? Map<String, dynamic>.from(json['metadata'] as Map)
: null,
);
}
// ==================== Time Series Types ====================
/// Data point
class DataPoint {
final DateTime timestamp;
final double value;
final Map<String, String>? tags;
const DataPoint({
required this.timestamp,
required this.value,
this.tags,
});
factory DataPoint.fromJson(Map<String, dynamic> json) => DataPoint(
timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int),
value: (json['value'] as num).toDouble(),
tags: json['tags'] != null
? Map<String, String>.from(json['tags'] as Map)
: null,
);
Map<String, dynamic> toJson() => {
'timestamp': timestamp.millisecondsSinceEpoch,
'value': value,
if (tags != null) 'tags': tags,
};
}
/// Time range
class TimeRange {
final DateTime start;
final DateTime end;
const TimeRange({required this.start, required this.end});
Map<String, dynamic> toJson() => {
'start': start.millisecondsSinceEpoch,
'end': end.millisecondsSinceEpoch,
};
}
/// Aggregation options
class Aggregation {
final String function; // sum, avg, min, max, count
final String interval; // 1m, 5m, 1h, 1d
const Aggregation({required this.function, required this.interval});
Map<String, dynamic> toJson() => {
'function': function,
'interval': interval,
};
}
// ==================== Error Types ====================
/// Database error
class DatabaseException implements Exception {
final String message;
final String? code;
final int? statusCode;
const DatabaseException(this.message, {this.code, this.statusCode});
@override
String toString() => 'DatabaseException: $message';
}

View file

@ -0,0 +1,253 @@
/// Synor Hosting SDK Client for Flutter
///
/// Decentralized web hosting with domain management, DNS, and deployments.
library synor_hosting;
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'types.dart';
export 'types.dart';
/// Synor Hosting Client
class SynorHosting {
final HostingConfig config;
final http.Client _client;
bool _closed = false;
SynorHosting(this.config) : _client = http.Client();
// ==================== Domain Operations ====================
Future<DomainAvailability> checkAvailability(String name) async {
final resp = await _request('GET', '/domains/check/${Uri.encodeComponent(name)}');
return DomainAvailability.fromJson(resp);
}
Future<Domain> registerDomain(String name, {RegisterDomainOptions? options}) async {
final body = <String, dynamic>{'name': name};
if (options != null) body.addAll(options.toJson());
final resp = await _request('POST', '/domains', body);
return Domain.fromJson(resp);
}
Future<Domain> getDomain(String name) async {
final resp = await _request('GET', '/domains/${Uri.encodeComponent(name)}');
return Domain.fromJson(resp);
}
Future<List<Domain>> listDomains() async {
final resp = await _request('GET', '/domains');
return (resp['domains'] as List).map((e) => Domain.fromJson(e)).toList();
}
Future<Domain> updateDomainRecord(String name, DomainRecord record) async {
final resp = await _request('PUT', '/domains/${Uri.encodeComponent(name)}/record', record.toJson());
return Domain.fromJson(resp);
}
Future<DomainRecord> resolveDomain(String name) async {
final resp = await _request('GET', '/domains/${Uri.encodeComponent(name)}/resolve');
return DomainRecord.fromJson(resp);
}
Future<Domain> renewDomain(String name, int years) async {
final resp = await _request('POST', '/domains/${Uri.encodeComponent(name)}/renew', {'years': years});
return Domain.fromJson(resp);
}
// ==================== DNS Operations ====================
Future<DnsZone> getDnsZone(String domain) async {
final resp = await _request('GET', '/dns/${Uri.encodeComponent(domain)}');
return DnsZone.fromJson(resp);
}
Future<DnsZone> setDnsRecords(String domain, List<DnsRecord> records) async {
final resp = await _request('PUT', '/dns/${Uri.encodeComponent(domain)}', {
'records': records.map((r) => r.toJson()).toList(),
});
return DnsZone.fromJson(resp);
}
Future<DnsZone> addDnsRecord(String domain, DnsRecord record) async {
final resp = await _request('POST', '/dns/${Uri.encodeComponent(domain)}/records', record.toJson());
return DnsZone.fromJson(resp);
}
Future<DnsZone> deleteDnsRecord(String domain, String recordType, String name) async {
final path = '/dns/${Uri.encodeComponent(domain)}/records/$recordType/${Uri.encodeComponent(name)}';
final resp = await _request('DELETE', path);
return DnsZone.fromJson(resp);
}
// ==================== Deployment Operations ====================
Future<Deployment> deploy(String cid, {DeployOptions? options}) async {
final body = <String, dynamic>{'cid': cid};
if (options != null) body.addAll(options.toJson());
final resp = await _request('POST', '/deployments', body);
return Deployment.fromJson(resp);
}
Future<Deployment> getDeployment(String id) async {
final resp = await _request('GET', '/deployments/${Uri.encodeComponent(id)}');
return Deployment.fromJson(resp);
}
Future<List<Deployment>> listDeployments({String? domain}) async {
final path = domain != null ? '/deployments?domain=${Uri.encodeComponent(domain)}' : '/deployments';
final resp = await _request('GET', path);
return (resp['deployments'] as List).map((e) => Deployment.fromJson(e)).toList();
}
Future<Deployment> rollback(String domain, String deploymentId) async {
final resp = await _request('POST', '/deployments/${Uri.encodeComponent(deploymentId)}/rollback', {
'domain': domain,
});
return Deployment.fromJson(resp);
}
Future<void> deleteDeployment(String id) async {
await _request('DELETE', '/deployments/${Uri.encodeComponent(id)}');
}
// ==================== SSL Operations ====================
Future<Certificate> provisionSsl(String domain, {ProvisionSslOptions? options}) async {
final resp = await _request('POST', '/ssl/${Uri.encodeComponent(domain)}', options?.toJson());
return Certificate.fromJson(resp);
}
Future<Certificate> getCertificate(String domain) async {
final resp = await _request('GET', '/ssl/${Uri.encodeComponent(domain)}');
return Certificate.fromJson(resp);
}
Future<Certificate> renewCertificate(String domain) async {
final resp = await _request('POST', '/ssl/${Uri.encodeComponent(domain)}/renew');
return Certificate.fromJson(resp);
}
Future<void> deleteCertificate(String domain) async {
await _request('DELETE', '/ssl/${Uri.encodeComponent(domain)}');
}
// ==================== Site Configuration ====================
Future<Map<String, dynamic>> getSiteConfig(String domain) async {
return await _request('GET', '/sites/${Uri.encodeComponent(domain)}/config');
}
Future<Map<String, dynamic>> updateSiteConfig(String domain, Map<String, dynamic> siteConfig) async {
return await _request('PATCH', '/sites/${Uri.encodeComponent(domain)}/config', siteConfig);
}
Future<int> purgeCache(String domain, {List<String>? paths}) async {
final resp = await _request('DELETE', '/sites/${Uri.encodeComponent(domain)}/cache', {
if (paths != null) 'paths': paths,
});
return resp['purged'] as int;
}
// ==================== Analytics ====================
Future<AnalyticsData> getAnalytics(String domain, {AnalyticsOptions? options}) async {
var path = '/sites/${Uri.encodeComponent(domain)}/analytics';
final params = <String>[];
if (options?.period != null) params.add('period=${Uri.encodeComponent(options!.period!)}');
if (options?.start != null) params.add('start=${Uri.encodeComponent(options!.start!)}');
if (options?.end != null) params.add('end=${Uri.encodeComponent(options!.end!)}');
if (params.isNotEmpty) path = '$path?${params.join('&')}';
final resp = await _request('GET', path);
return AnalyticsData.fromJson(resp);
}
// ==================== Lifecycle ====================
void close() {
_closed = true;
_client.close();
}
bool get isClosed => _closed;
Future<bool> healthCheck() async {
try {
final resp = await _request('GET', '/health');
return resp['status'] == 'healthy';
} catch (_) {
return false;
}
}
// ==================== Private Methods ====================
Future<Map<String, dynamic>> _request(
String method,
String path, [
Map<String, dynamic>? body,
]) async {
if (_closed) throw HostingException('Client has been closed');
Exception? lastError;
for (var attempt = 0; attempt < config.retries; attempt++) {
try {
return await _doRequest(method, path, body);
} catch (e) {
lastError = e as Exception;
if (attempt < config.retries - 1) {
await Future.delayed(Duration(seconds: 1 << attempt));
}
}
}
throw lastError ?? HostingException('Unknown error');
}
Future<Map<String, dynamic>> _doRequest(
String method,
String path,
Map<String, dynamic>? body,
) async {
final uri = Uri.parse('${config.endpoint}$path');
final headers = {
'Authorization': 'Bearer ${config.apiKey}',
'Content-Type': 'application/json',
'X-SDK-Version': 'flutter/0.1.0',
};
http.Response response;
switch (method) {
case 'GET':
response = await _client.get(uri, headers: headers);
break;
case 'POST':
response = await _client.post(uri, headers: headers, body: body != null ? jsonEncode(body) : null);
break;
case 'PUT':
response = await _client.put(uri, headers: headers, body: jsonEncode(body));
break;
case 'PATCH':
response = await _client.patch(uri, headers: headers, body: jsonEncode(body));
break;
case 'DELETE':
response = await _client.delete(uri, headers: headers, body: body != null ? jsonEncode(body) : null);
break;
default:
throw HostingException('Unknown method: $method');
}
if (response.statusCode >= 400) {
final error = jsonDecode(response.body) as Map<String, dynamic>;
throw HostingException(
error['message'] as String? ?? 'HTTP ${response.statusCode}',
code: error['code'] as String?,
statusCode: response.statusCode,
);
}
if (response.body.isEmpty) return {};
return jsonDecode(response.body) as Map<String, dynamic>;
}
}

View file

@ -0,0 +1,397 @@
/// Synor Hosting SDK Types for Flutter
///
/// Decentralized web hosting with domain management, DNS, and deployments.
library synor_hosting_types;
// ==================== Config ====================
/// Hosting configuration
class HostingConfig {
final String apiKey;
final String endpoint;
final Duration timeout;
final int retries;
final bool debug;
const HostingConfig({
required this.apiKey,
this.endpoint = 'https://hosting.synor.io/v1',
this.timeout = const Duration(seconds: 60),
this.retries = 3,
this.debug = false,
});
}
// ==================== Domain Types ====================
/// Domain status
enum DomainStatus { pending, active, expired, suspended }
/// Domain information
class Domain {
final String name;
final DomainStatus status;
final String owner;
final DateTime registeredAt;
final DateTime expiresAt;
final bool autoRenew;
final DomainRecord? records;
const Domain({
required this.name,
required this.status,
required this.owner,
required this.registeredAt,
required this.expiresAt,
required this.autoRenew,
this.records,
});
factory Domain.fromJson(Map<String, dynamic> json) => Domain(
name: json['name'] as String,
status: DomainStatus.values.firstWhere(
(e) => e.name == json['status'],
orElse: () => DomainStatus.pending),
owner: json['owner'] as String,
registeredAt: DateTime.fromMillisecondsSinceEpoch(json['registeredAt'] as int),
expiresAt: DateTime.fromMillisecondsSinceEpoch(json['expiresAt'] as int),
autoRenew: json['autoRenew'] as bool? ?? false,
records: json['records'] != null ? DomainRecord.fromJson(json['records']) : null,
);
}
/// Domain record
class DomainRecord {
final String? cid;
final List<String>? ipv4;
final List<String>? ipv6;
final String? cname;
final List<String>? txt;
final Map<String, String>? metadata;
const DomainRecord({
this.cid,
this.ipv4,
this.ipv6,
this.cname,
this.txt,
this.metadata,
});
factory DomainRecord.fromJson(Map<String, dynamic> json) => DomainRecord(
cid: json['cid'] as String?,
ipv4: (json['ipv4'] as List?)?.cast<String>(),
ipv6: (json['ipv6'] as List?)?.cast<String>(),
cname: json['cname'] as String?,
txt: (json['txt'] as List?)?.cast<String>(),
metadata: (json['metadata'] as Map?)?.cast<String, String>(),
);
Map<String, dynamic> toJson() => {
if (cid != null) 'cid': cid,
if (ipv4 != null) 'ipv4': ipv4,
if (ipv6 != null) 'ipv6': ipv6,
if (cname != null) 'cname': cname,
if (txt != null) 'txt': txt,
if (metadata != null) 'metadata': metadata,
};
}
/// Domain availability
class DomainAvailability {
final String name;
final bool available;
final double? price;
final bool premium;
const DomainAvailability({
required this.name,
required this.available,
this.price,
this.premium = false,
});
factory DomainAvailability.fromJson(Map<String, dynamic> json) => DomainAvailability(
name: json['name'] as String,
available: json['available'] as bool,
price: (json['price'] as num?)?.toDouble(),
premium: json['premium'] as bool? ?? false,
);
}
/// Options for registering a domain
class RegisterDomainOptions {
final int? years;
final bool? autoRenew;
const RegisterDomainOptions({this.years, this.autoRenew});
Map<String, dynamic> toJson() => {
if (years != null) 'years': years,
if (autoRenew != null) 'autoRenew': autoRenew,
};
}
// ==================== DNS Types ====================
/// DNS record type
enum DnsRecordType { A, AAAA, CNAME, TXT, MX, NS, SRV, CAA }
/// DNS record
class DnsRecord {
final DnsRecordType type;
final String name;
final String value;
final int ttl;
final int? priority;
const DnsRecord({
required this.type,
required this.name,
required this.value,
this.ttl = 3600,
this.priority,
});
factory DnsRecord.fromJson(Map<String, dynamic> json) => DnsRecord(
type: DnsRecordType.values.firstWhere((e) => e.name == json['type']),
name: json['name'] as String,
value: json['value'] as String,
ttl: json['ttl'] as int? ?? 3600,
priority: json['priority'] as int?,
);
Map<String, dynamic> toJson() => {
'type': type.name,
'name': name,
'value': value,
'ttl': ttl,
if (priority != null) 'priority': priority,
};
}
/// DNS zone
class DnsZone {
final String domain;
final List<DnsRecord> records;
final DateTime updatedAt;
const DnsZone({
required this.domain,
required this.records,
required this.updatedAt,
});
factory DnsZone.fromJson(Map<String, dynamic> json) => DnsZone(
domain: json['domain'] as String,
records: (json['records'] as List).map((e) => DnsRecord.fromJson(e)).toList(),
updatedAt: DateTime.fromMillisecondsSinceEpoch(json['updatedAt'] as int),
);
}
// ==================== Deployment Types ====================
/// Deployment status
enum DeploymentStatus { pending, building, deploying, active, failed, inactive }
/// Deployment information
class Deployment {
final String id;
final String domain;
final String cid;
final DeploymentStatus status;
final String url;
final DateTime createdAt;
final DateTime updatedAt;
final String? buildLogs;
final String? errorMessage;
const Deployment({
required this.id,
required this.domain,
required this.cid,
required this.status,
required this.url,
required this.createdAt,
required this.updatedAt,
this.buildLogs,
this.errorMessage,
});
factory Deployment.fromJson(Map<String, dynamic> json) => Deployment(
id: json['id'] as String,
domain: json['domain'] as String,
cid: json['cid'] as String,
status: DeploymentStatus.values.firstWhere(
(e) => e.name == json['status'],
orElse: () => DeploymentStatus.pending),
url: json['url'] as String,
createdAt: DateTime.fromMillisecondsSinceEpoch(json['createdAt'] as int),
updatedAt: DateTime.fromMillisecondsSinceEpoch(json['updatedAt'] as int),
buildLogs: json['buildLogs'] as String?,
errorMessage: json['errorMessage'] as String?,
);
}
/// Deploy options
class DeployOptions {
final String? domain;
final String? subdomain;
final bool? spa;
final bool? cleanUrls;
final bool? trailingSlash;
const DeployOptions({
this.domain,
this.subdomain,
this.spa,
this.cleanUrls,
this.trailingSlash,
});
Map<String, dynamic> toJson() => {
if (domain != null) 'domain': domain,
if (subdomain != null) 'subdomain': subdomain,
if (spa != null) 'spa': spa,
if (cleanUrls != null) 'cleanUrls': cleanUrls,
if (trailingSlash != null) 'trailingSlash': trailingSlash,
};
}
// ==================== SSL Types ====================
/// Certificate status
enum CertificateStatus { pending, issued, expired, revoked }
/// SSL certificate
class Certificate {
final String domain;
final CertificateStatus status;
final bool autoRenew;
final String issuer;
final DateTime? issuedAt;
final DateTime? expiresAt;
final String? fingerprint;
const Certificate({
required this.domain,
required this.status,
required this.autoRenew,
required this.issuer,
this.issuedAt,
this.expiresAt,
this.fingerprint,
});
factory Certificate.fromJson(Map<String, dynamic> json) => Certificate(
domain: json['domain'] as String,
status: CertificateStatus.values.firstWhere(
(e) => e.name == json['status'],
orElse: () => CertificateStatus.pending),
autoRenew: json['autoRenew'] as bool? ?? false,
issuer: json['issuer'] as String,
issuedAt: json['issuedAt'] != null
? DateTime.fromMillisecondsSinceEpoch(json['issuedAt'] as int)
: null,
expiresAt: json['expiresAt'] != null
? DateTime.fromMillisecondsSinceEpoch(json['expiresAt'] as int)
: null,
fingerprint: json['fingerprint'] as String?,
);
}
/// Provision SSL options
class ProvisionSslOptions {
final bool? includeWww;
final bool? autoRenew;
const ProvisionSslOptions({this.includeWww, this.autoRenew});
Map<String, dynamic> toJson() => {
if (includeWww != null) 'includeWww': includeWww,
if (autoRenew != null) 'autoRenew': autoRenew,
};
}
// ==================== Analytics Types ====================
/// Analytics data
class AnalyticsData {
final String domain;
final String period;
final int pageViews;
final int uniqueVisitors;
final int bandwidth;
final List<PageView> topPages;
final List<Referrer> topReferrers;
final List<Country> topCountries;
const AnalyticsData({
required this.domain,
required this.period,
required this.pageViews,
required this.uniqueVisitors,
required this.bandwidth,
required this.topPages,
required this.topReferrers,
required this.topCountries,
});
factory AnalyticsData.fromJson(Map<String, dynamic> json) => AnalyticsData(
domain: json['domain'] as String,
period: json['period'] as String,
pageViews: json['pageViews'] as int,
uniqueVisitors: json['uniqueVisitors'] as int,
bandwidth: json['bandwidth'] as int,
topPages: (json['topPages'] as List).map((e) => PageView.fromJson(e)).toList(),
topReferrers: (json['topReferrers'] as List).map((e) => Referrer.fromJson(e)).toList(),
topCountries: (json['topCountries'] as List).map((e) => Country.fromJson(e)).toList(),
);
}
class PageView {
final String path;
final int views;
const PageView({required this.path, required this.views});
factory PageView.fromJson(Map<String, dynamic> json) =>
PageView(path: json['path'] as String, views: json['views'] as int);
}
class Referrer {
final String referrer;
final int count;
const Referrer({required this.referrer, required this.count});
factory Referrer.fromJson(Map<String, dynamic> json) =>
Referrer(referrer: json['referrer'] as String, count: json['count'] as int);
}
class Country {
final String country;
final int count;
const Country({required this.country, required this.count});
factory Country.fromJson(Map<String, dynamic> json) =>
Country(country: json['country'] as String, count: json['count'] as int);
}
/// Analytics options
class AnalyticsOptions {
final String? period;
final String? start;
final String? end;
const AnalyticsOptions({this.period, this.start, this.end});
}
// ==================== Error Types ====================
/// Hosting error
class HostingException implements Exception {
final String message;
final String? code;
final int? statusCode;
const HostingException(this.message, {this.code, this.statusCode});
@override
String toString() => 'HostingException: $message';
}

View file

@ -5,6 +5,9 @@
/// - **Wallet**: Key management and transaction signing
/// - **RPC**: Blockchain queries and subscriptions
/// - **Storage**: IPFS-compatible decentralized storage
/// - **Database**: Multi-model database (KV, Document, Vector, TimeSeries)
/// - **Hosting**: Decentralized web hosting
/// - **Bridge**: Cross-chain asset transfers
///
/// ## Quick Start
///
@ -28,10 +31,25 @@
/// final upload = await storage.upload(Uint8List.fromList(data));
/// print('CID: ${upload.cid}');
///
/// // Database operations
/// final db = SynorDatabase(DatabaseConfig(apiKey: 'your-api-key'));
/// await db.kv.set('key', 'value');
///
/// // Hosting operations
/// final hosting = SynorHosting(HostingConfig(apiKey: 'your-api-key'));
/// final deployment = await hosting.deploy('Qm...');
///
/// // Bridge operations
/// final bridge = SynorBridge(BridgeConfig(apiKey: 'your-api-key'));
/// final transfer = await bridge.bridgeTo('SYNR', '1000', ChainId.ethereum, '0x...');
///
/// // Clean up
/// wallet.close();
/// rpc.close();
/// storage.close();
/// db.close();
/// hosting.close();
/// bridge.close();
/// }
/// ```
///
@ -42,6 +60,7 @@
/// - RPC: `RpcNetwork`, `RpcPriority`, `RpcTransaction`
/// - Storage: `PinStatus`, `HashAlgorithm`, `EntryType`
/// - Compute: `Precision`, `ProcessorType`, `Priority` (as `ComputePriority`)
/// - Bridge: `ChainId`, `TransferStatus`, `TransferDirection`
library synor_sdk;
// Compute SDK - hide Priority to avoid conflict with Wallet
@ -56,5 +75,14 @@ export 'src/rpc/synor_rpc.dart';
// Storage SDK
export 'src/storage/synor_storage.dart';
// Database SDK
export 'src/database/client.dart';
// Hosting SDK
export 'src/hosting/client.dart';
// Bridge SDK - hide types that conflict with other SDKs
export 'src/bridge/client.dart' hide FeeEstimate, SignedTransaction;
// Re-export Compute Priority with alias-friendly access
// Users can import compute directly for Priority: import 'package:synor_sdk/synor_compute.dart';