@naculus/connect-appkit-core 0.2.4 → 0.2.5
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/dist/index.cjs +204 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -2
- package/dist/index.d.ts +144 -2
- package/dist/index.js +185 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Namespace, UniversalWalletSession, WalletCapabilities, TokenConfig, WalletError, WalletErrorCode, NameResolverConfig, NameResolver } from '@naculus/connect-core';
|
|
1
|
+
import { Namespace, UniversalWalletSession, WalletCapabilities, TokenConfig, WalletError, WalletErrorCode, NameResolverConfig, NameResolver, NotificationSettings, InAppChannel, NotificationItem } from '@naculus/connect-core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The types the framework-neutral half of appkit is built on.
|
|
@@ -425,6 +425,148 @@ declare function getResolver(config?: NameResolverConfig): NameResolver;
|
|
|
425
425
|
/** Test seam: drop the shared instance. */
|
|
426
426
|
declare function __resetResolverForTests(): void;
|
|
427
427
|
|
|
428
|
+
/** Framework-neutral in-app notification actions and settings persistence. */
|
|
429
|
+
|
|
430
|
+
interface NotificationSettingsStorage {
|
|
431
|
+
getItem<T>(key: string): Promise<T | null>;
|
|
432
|
+
setItem<T>(key: string, value: T): Promise<void>;
|
|
433
|
+
removeItem(key: string): Promise<void>;
|
|
434
|
+
}
|
|
435
|
+
declare const NOTIFICATION_SETTINGS_KEY = "naculus_notif_react_settings";
|
|
436
|
+
declare const DEFAULT_NOTIFICATION_SETTINGS: NotificationSettings;
|
|
437
|
+
/** Preserve the existing localStorage adapter and fail-open UI fallback. */
|
|
438
|
+
declare function createNotificationSettingsStorage(): NotificationSettingsStorage;
|
|
439
|
+
declare function loadNotificationSettings(storage: NotificationSettingsStorage): Promise<NotificationSettings | null>;
|
|
440
|
+
declare function saveNotificationSettings(storage: NotificationSettingsStorage, settings: NotificationSettings): void;
|
|
441
|
+
declare function updateNotificationSettings(current: NotificationSettings, update: Partial<NotificationSettings>): NotificationSettings;
|
|
442
|
+
declare function channelsUpdate(channels: string[]): Partial<NotificationSettings>;
|
|
443
|
+
declare function mutedChainSettings(settings: NotificationSettings, chainId: string, muted: boolean): Partial<NotificationSettings>;
|
|
444
|
+
declare function createNotification(item: Omit<NotificationItem, "id" | "timestamp">): NotificationItem;
|
|
445
|
+
declare function addInAppNotification(channel: InAppChannel, item: Omit<NotificationItem, "id" | "timestamp">): void;
|
|
446
|
+
/** InAppChannel has no remove-one method; preserve its clear/replay behavior. */
|
|
447
|
+
declare function clearOneInAppNotification(channel: InAppChannel, id: string): Promise<NotificationItem[]>;
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Destination-address checks shared by the React hook and the Vue composable.
|
|
451
|
+
*
|
|
452
|
+
* Syntactic only. `"ok"` means none of these checks found anything wrong —
|
|
453
|
+
* not that the recipient is who the user thinks. This cannot see an
|
|
454
|
+
* address-poisoning lookalike, a contract that will not release the funds,
|
|
455
|
+
* or a known-malicious destination. Labelling that "safe" once put a green
|
|
456
|
+
* tick beside a scammer's address; the level is deliberately not "safe".
|
|
457
|
+
*/
|
|
458
|
+
type AddressValidationLevel = "ok" | "warning" | "blocked";
|
|
459
|
+
/** Machine-readable reason; the framework layer maps it to a user string. */
|
|
460
|
+
type DestinationIssue = "empty" | "invalid_format" | "zero_address" | "burn_address";
|
|
461
|
+
interface DestinationValidation {
|
|
462
|
+
isValid: boolean;
|
|
463
|
+
level: AddressValidationLevel;
|
|
464
|
+
issue: DestinationIssue | null;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Burn heuristic kept from the React hook: known sinks plus any well-formed
|
|
468
|
+
* address containing "dead". Stricter than connect-core's prefix-only
|
|
469
|
+
* `isBurnAddress`; unifying the two is a connect-lib change.
|
|
470
|
+
*/
|
|
471
|
+
declare function isBurnDestination(address: string): boolean;
|
|
472
|
+
declare function validateDestination(address: string): DestinationValidation;
|
|
473
|
+
/**
|
|
474
|
+
* The bare `0x…` account from either a CAIP-10 id (`eip155:1:0x…`) or a plain
|
|
475
|
+
* hex address; null when it is neither. Hooks and composables should not each
|
|
476
|
+
* carry their own copy of this split.
|
|
477
|
+
*/
|
|
478
|
+
declare function bareEvmAddress(account: string | null | undefined): `0x${string}` | null;
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Chain-abstraction (routing) domain types and the few decisions the React
|
|
482
|
+
* hooks and Vue composables share. The hooks inject the actual quote /
|
|
483
|
+
* compare / execute functions; nothing here talks to a network.
|
|
484
|
+
*/
|
|
485
|
+
interface RouteQuote {
|
|
486
|
+
routeId: string;
|
|
487
|
+
provider: string;
|
|
488
|
+
netReceiveFormatted: string;
|
|
489
|
+
toTokenSymbol: string;
|
|
490
|
+
}
|
|
491
|
+
interface RouteQuoteOptions {
|
|
492
|
+
sortBy?: "cost" | "time" | "balance";
|
|
493
|
+
maxSlippage?: number;
|
|
494
|
+
}
|
|
495
|
+
interface RouteQuoteInput {
|
|
496
|
+
fromChain: string;
|
|
497
|
+
toChain: string;
|
|
498
|
+
fromToken: string;
|
|
499
|
+
toToken?: string;
|
|
500
|
+
amount: string;
|
|
501
|
+
options?: RouteQuoteOptions;
|
|
502
|
+
}
|
|
503
|
+
type GetRouteQuotes = (from: string, to: string, token: string, amount: string, options?: RouteQuoteOptions, toToken?: string) => Promise<RouteQuote[]>;
|
|
504
|
+
/**
|
|
505
|
+
* `BigInt()` throws on anything that is not a decimal integer — "1.5", "abc",
|
|
506
|
+
* "1e18" — so a user typing into an amount field must not reach it. Only a
|
|
507
|
+
* positive base-unit integer is a quotable amount.
|
|
508
|
+
*/
|
|
509
|
+
declare function isPositiveIntegerAmount(amount: string): boolean;
|
|
510
|
+
/** True when every field a quote needs is present and the amount is quotable. */
|
|
511
|
+
declare function isQuotableInput(input: RouteQuoteInput): boolean;
|
|
512
|
+
interface CostComparison {
|
|
513
|
+
chain: string;
|
|
514
|
+
chainName: string;
|
|
515
|
+
totalCost: string;
|
|
516
|
+
gasCost: string;
|
|
517
|
+
estimatedTimeMs: number;
|
|
518
|
+
}
|
|
519
|
+
type CostComparisonOperation = "send_erc20" | "swap" | "bridge" | (string & {});
|
|
520
|
+
interface CostComparisonOptions {
|
|
521
|
+
amount?: string;
|
|
522
|
+
token?: string;
|
|
523
|
+
[key: string]: unknown;
|
|
524
|
+
}
|
|
525
|
+
interface CompareCostsInput {
|
|
526
|
+
operation: CostComparisonOperation;
|
|
527
|
+
chains: string[];
|
|
528
|
+
options?: CostComparisonOptions;
|
|
529
|
+
}
|
|
530
|
+
type CompareCosts = (operation: string, chains: string[], options?: CostComparisonOptions) => Promise<CostComparison[]>;
|
|
531
|
+
/**
|
|
532
|
+
* Value key for a compare-costs input. `chains` is an array and `options` an
|
|
533
|
+
* object; keying on identity re-fired the fetch on every render/reactive tick
|
|
534
|
+
* for a caller writing the natural inline literal — an unbounded loop against
|
|
535
|
+
* a cost API.
|
|
536
|
+
*/
|
|
537
|
+
declare function compareCostsKey(input: CompareCostsInput): string;
|
|
538
|
+
interface ExecutableQuote {
|
|
539
|
+
routeId: string;
|
|
540
|
+
provider: string;
|
|
541
|
+
totalCost?: bigint;
|
|
542
|
+
estimatedTimeMs?: number;
|
|
543
|
+
toChain?: string;
|
|
544
|
+
}
|
|
545
|
+
interface ExecuteRouteResult {
|
|
546
|
+
fromTxHash: string;
|
|
547
|
+
toTxHash?: string;
|
|
548
|
+
}
|
|
549
|
+
interface ExecuteRouteOptions {
|
|
550
|
+
timeoutMs?: number;
|
|
551
|
+
gasLimit?: bigint;
|
|
552
|
+
}
|
|
553
|
+
interface ExecuteRouteError {
|
|
554
|
+
code: string;
|
|
555
|
+
message: string;
|
|
556
|
+
details?: Record<string, unknown>;
|
|
557
|
+
}
|
|
558
|
+
type ExecuteRoute = (quote: ExecutableQuote, recipient: string, options?: ExecuteRouteOptions) => Promise<ExecuteRouteResult>;
|
|
559
|
+
/**
|
|
560
|
+
* Recipient check before a cross-chain execution. An empty recipient is wrong
|
|
561
|
+
* on every chain. Beyond that the destination namespace decides: when the
|
|
562
|
+
* quote names `toChain`, the address is validated for that namespace; when it
|
|
563
|
+
* does not, this returns null and the executor decides, rather than rejecting
|
|
564
|
+
* a valid non-EVM address on a guess.
|
|
565
|
+
*/
|
|
566
|
+
declare function validateRouteRecipient(quote: ExecutableQuote | null | undefined, recipient: string): ExecuteRouteError | null;
|
|
567
|
+
/** Normalise whatever an executor threw into the hook's error shape. */
|
|
568
|
+
declare function toExecuteRouteError(cause: unknown): ExecuteRouteError;
|
|
569
|
+
|
|
428
570
|
declare function withTimeout<T>(promise: Promise<T>, ms: number, label?: string): Promise<T>;
|
|
429
571
|
interface RetryOptions {
|
|
430
572
|
maxRetries: number;
|
|
@@ -465,4 +607,4 @@ type Web3Action = {
|
|
|
465
607
|
declare const initialWeb3State: Web3State;
|
|
466
608
|
declare function web3Reducer(state: Web3State, action: Web3Action): Web3State;
|
|
467
609
|
|
|
468
|
-
export { type AtomicSupport, type ChainCapabilities, type ChainInfo, type ConnectionStatus, type DecimalsCache, type RetryOptions, type SolanaIdentity, type SolanaPayer, type SolanaRoles, type SolanaRolesAbsence, type SolanaRolesSource, type SolanaRolesState, type SolanaSigner, type SolanaWalletFeatures, type TokenIdentity, type ViemChainShape, type WalletChain, type Web3Action, type Web3State, __resetResolverForTests, atomicSupportFor, chainNamespace, chainNumber, chainsForNamespace, createDecimalsCache, decodeRevertReason, describeChain, eip155ChainIdToNumber, getResolver, initialWeb3State, isEvmChainId, normalizeCapabilities, normalizeEip155ChainId, readDecimals, readSolanaRoles, resolveChain, resolveEvmChainId, resolveRevertReason, selectChainCapabilities, toChainSwitchError, toEip155Accounts, toViemChain, tokenChainMismatch, tokenKey, web3Reducer, withRetry, withTimeout, writeDecimals };
|
|
610
|
+
export { type AddressValidationLevel, type AtomicSupport, type ChainCapabilities, type ChainInfo, type CompareCosts, type CompareCostsInput, type ConnectionStatus, type CostComparison, type CostComparisonOperation, type CostComparisonOptions, DEFAULT_NOTIFICATION_SETTINGS, type DecimalsCache, type DestinationIssue, type DestinationValidation, type ExecutableQuote, type ExecuteRoute, type ExecuteRouteError, type ExecuteRouteOptions, type ExecuteRouteResult, type GetRouteQuotes, NOTIFICATION_SETTINGS_KEY, type NotificationSettingsStorage, type RetryOptions, type RouteQuote, type RouteQuoteInput, type RouteQuoteOptions, type SolanaIdentity, type SolanaPayer, type SolanaRoles, type SolanaRolesAbsence, type SolanaRolesSource, type SolanaRolesState, type SolanaSigner, type SolanaWalletFeatures, type TokenIdentity, type ViemChainShape, type WalletChain, type Web3Action, type Web3State, __resetResolverForTests, addInAppNotification, atomicSupportFor, bareEvmAddress, chainNamespace, chainNumber, chainsForNamespace, channelsUpdate, clearOneInAppNotification, compareCostsKey, createDecimalsCache, createNotification, createNotificationSettingsStorage, decodeRevertReason, describeChain, eip155ChainIdToNumber, getResolver, initialWeb3State, isBurnDestination, isEvmChainId, isPositiveIntegerAmount, isQuotableInput, loadNotificationSettings, mutedChainSettings, normalizeCapabilities, normalizeEip155ChainId, readDecimals, readSolanaRoles, resolveChain, resolveEvmChainId, resolveRevertReason, saveNotificationSettings, selectChainCapabilities, toChainSwitchError, toEip155Accounts, toExecuteRouteError, toViemChain, tokenChainMismatch, tokenKey, updateNotificationSettings, validateDestination, validateRouteRecipient, web3Reducer, withRetry, withTimeout, writeDecimals };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Namespace, UniversalWalletSession, WalletCapabilities, TokenConfig, WalletError, WalletErrorCode, NameResolverConfig, NameResolver } from '@naculus/connect-core';
|
|
1
|
+
import { Namespace, UniversalWalletSession, WalletCapabilities, TokenConfig, WalletError, WalletErrorCode, NameResolverConfig, NameResolver, NotificationSettings, InAppChannel, NotificationItem } from '@naculus/connect-core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The types the framework-neutral half of appkit is built on.
|
|
@@ -425,6 +425,148 @@ declare function getResolver(config?: NameResolverConfig): NameResolver;
|
|
|
425
425
|
/** Test seam: drop the shared instance. */
|
|
426
426
|
declare function __resetResolverForTests(): void;
|
|
427
427
|
|
|
428
|
+
/** Framework-neutral in-app notification actions and settings persistence. */
|
|
429
|
+
|
|
430
|
+
interface NotificationSettingsStorage {
|
|
431
|
+
getItem<T>(key: string): Promise<T | null>;
|
|
432
|
+
setItem<T>(key: string, value: T): Promise<void>;
|
|
433
|
+
removeItem(key: string): Promise<void>;
|
|
434
|
+
}
|
|
435
|
+
declare const NOTIFICATION_SETTINGS_KEY = "naculus_notif_react_settings";
|
|
436
|
+
declare const DEFAULT_NOTIFICATION_SETTINGS: NotificationSettings;
|
|
437
|
+
/** Preserve the existing localStorage adapter and fail-open UI fallback. */
|
|
438
|
+
declare function createNotificationSettingsStorage(): NotificationSettingsStorage;
|
|
439
|
+
declare function loadNotificationSettings(storage: NotificationSettingsStorage): Promise<NotificationSettings | null>;
|
|
440
|
+
declare function saveNotificationSettings(storage: NotificationSettingsStorage, settings: NotificationSettings): void;
|
|
441
|
+
declare function updateNotificationSettings(current: NotificationSettings, update: Partial<NotificationSettings>): NotificationSettings;
|
|
442
|
+
declare function channelsUpdate(channels: string[]): Partial<NotificationSettings>;
|
|
443
|
+
declare function mutedChainSettings(settings: NotificationSettings, chainId: string, muted: boolean): Partial<NotificationSettings>;
|
|
444
|
+
declare function createNotification(item: Omit<NotificationItem, "id" | "timestamp">): NotificationItem;
|
|
445
|
+
declare function addInAppNotification(channel: InAppChannel, item: Omit<NotificationItem, "id" | "timestamp">): void;
|
|
446
|
+
/** InAppChannel has no remove-one method; preserve its clear/replay behavior. */
|
|
447
|
+
declare function clearOneInAppNotification(channel: InAppChannel, id: string): Promise<NotificationItem[]>;
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Destination-address checks shared by the React hook and the Vue composable.
|
|
451
|
+
*
|
|
452
|
+
* Syntactic only. `"ok"` means none of these checks found anything wrong —
|
|
453
|
+
* not that the recipient is who the user thinks. This cannot see an
|
|
454
|
+
* address-poisoning lookalike, a contract that will not release the funds,
|
|
455
|
+
* or a known-malicious destination. Labelling that "safe" once put a green
|
|
456
|
+
* tick beside a scammer's address; the level is deliberately not "safe".
|
|
457
|
+
*/
|
|
458
|
+
type AddressValidationLevel = "ok" | "warning" | "blocked";
|
|
459
|
+
/** Machine-readable reason; the framework layer maps it to a user string. */
|
|
460
|
+
type DestinationIssue = "empty" | "invalid_format" | "zero_address" | "burn_address";
|
|
461
|
+
interface DestinationValidation {
|
|
462
|
+
isValid: boolean;
|
|
463
|
+
level: AddressValidationLevel;
|
|
464
|
+
issue: DestinationIssue | null;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Burn heuristic kept from the React hook: known sinks plus any well-formed
|
|
468
|
+
* address containing "dead". Stricter than connect-core's prefix-only
|
|
469
|
+
* `isBurnAddress`; unifying the two is a connect-lib change.
|
|
470
|
+
*/
|
|
471
|
+
declare function isBurnDestination(address: string): boolean;
|
|
472
|
+
declare function validateDestination(address: string): DestinationValidation;
|
|
473
|
+
/**
|
|
474
|
+
* The bare `0x…` account from either a CAIP-10 id (`eip155:1:0x…`) or a plain
|
|
475
|
+
* hex address; null when it is neither. Hooks and composables should not each
|
|
476
|
+
* carry their own copy of this split.
|
|
477
|
+
*/
|
|
478
|
+
declare function bareEvmAddress(account: string | null | undefined): `0x${string}` | null;
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Chain-abstraction (routing) domain types and the few decisions the React
|
|
482
|
+
* hooks and Vue composables share. The hooks inject the actual quote /
|
|
483
|
+
* compare / execute functions; nothing here talks to a network.
|
|
484
|
+
*/
|
|
485
|
+
interface RouteQuote {
|
|
486
|
+
routeId: string;
|
|
487
|
+
provider: string;
|
|
488
|
+
netReceiveFormatted: string;
|
|
489
|
+
toTokenSymbol: string;
|
|
490
|
+
}
|
|
491
|
+
interface RouteQuoteOptions {
|
|
492
|
+
sortBy?: "cost" | "time" | "balance";
|
|
493
|
+
maxSlippage?: number;
|
|
494
|
+
}
|
|
495
|
+
interface RouteQuoteInput {
|
|
496
|
+
fromChain: string;
|
|
497
|
+
toChain: string;
|
|
498
|
+
fromToken: string;
|
|
499
|
+
toToken?: string;
|
|
500
|
+
amount: string;
|
|
501
|
+
options?: RouteQuoteOptions;
|
|
502
|
+
}
|
|
503
|
+
type GetRouteQuotes = (from: string, to: string, token: string, amount: string, options?: RouteQuoteOptions, toToken?: string) => Promise<RouteQuote[]>;
|
|
504
|
+
/**
|
|
505
|
+
* `BigInt()` throws on anything that is not a decimal integer — "1.5", "abc",
|
|
506
|
+
* "1e18" — so a user typing into an amount field must not reach it. Only a
|
|
507
|
+
* positive base-unit integer is a quotable amount.
|
|
508
|
+
*/
|
|
509
|
+
declare function isPositiveIntegerAmount(amount: string): boolean;
|
|
510
|
+
/** True when every field a quote needs is present and the amount is quotable. */
|
|
511
|
+
declare function isQuotableInput(input: RouteQuoteInput): boolean;
|
|
512
|
+
interface CostComparison {
|
|
513
|
+
chain: string;
|
|
514
|
+
chainName: string;
|
|
515
|
+
totalCost: string;
|
|
516
|
+
gasCost: string;
|
|
517
|
+
estimatedTimeMs: number;
|
|
518
|
+
}
|
|
519
|
+
type CostComparisonOperation = "send_erc20" | "swap" | "bridge" | (string & {});
|
|
520
|
+
interface CostComparisonOptions {
|
|
521
|
+
amount?: string;
|
|
522
|
+
token?: string;
|
|
523
|
+
[key: string]: unknown;
|
|
524
|
+
}
|
|
525
|
+
interface CompareCostsInput {
|
|
526
|
+
operation: CostComparisonOperation;
|
|
527
|
+
chains: string[];
|
|
528
|
+
options?: CostComparisonOptions;
|
|
529
|
+
}
|
|
530
|
+
type CompareCosts = (operation: string, chains: string[], options?: CostComparisonOptions) => Promise<CostComparison[]>;
|
|
531
|
+
/**
|
|
532
|
+
* Value key for a compare-costs input. `chains` is an array and `options` an
|
|
533
|
+
* object; keying on identity re-fired the fetch on every render/reactive tick
|
|
534
|
+
* for a caller writing the natural inline literal — an unbounded loop against
|
|
535
|
+
* a cost API.
|
|
536
|
+
*/
|
|
537
|
+
declare function compareCostsKey(input: CompareCostsInput): string;
|
|
538
|
+
interface ExecutableQuote {
|
|
539
|
+
routeId: string;
|
|
540
|
+
provider: string;
|
|
541
|
+
totalCost?: bigint;
|
|
542
|
+
estimatedTimeMs?: number;
|
|
543
|
+
toChain?: string;
|
|
544
|
+
}
|
|
545
|
+
interface ExecuteRouteResult {
|
|
546
|
+
fromTxHash: string;
|
|
547
|
+
toTxHash?: string;
|
|
548
|
+
}
|
|
549
|
+
interface ExecuteRouteOptions {
|
|
550
|
+
timeoutMs?: number;
|
|
551
|
+
gasLimit?: bigint;
|
|
552
|
+
}
|
|
553
|
+
interface ExecuteRouteError {
|
|
554
|
+
code: string;
|
|
555
|
+
message: string;
|
|
556
|
+
details?: Record<string, unknown>;
|
|
557
|
+
}
|
|
558
|
+
type ExecuteRoute = (quote: ExecutableQuote, recipient: string, options?: ExecuteRouteOptions) => Promise<ExecuteRouteResult>;
|
|
559
|
+
/**
|
|
560
|
+
* Recipient check before a cross-chain execution. An empty recipient is wrong
|
|
561
|
+
* on every chain. Beyond that the destination namespace decides: when the
|
|
562
|
+
* quote names `toChain`, the address is validated for that namespace; when it
|
|
563
|
+
* does not, this returns null and the executor decides, rather than rejecting
|
|
564
|
+
* a valid non-EVM address on a guess.
|
|
565
|
+
*/
|
|
566
|
+
declare function validateRouteRecipient(quote: ExecutableQuote | null | undefined, recipient: string): ExecuteRouteError | null;
|
|
567
|
+
/** Normalise whatever an executor threw into the hook's error shape. */
|
|
568
|
+
declare function toExecuteRouteError(cause: unknown): ExecuteRouteError;
|
|
569
|
+
|
|
428
570
|
declare function withTimeout<T>(promise: Promise<T>, ms: number, label?: string): Promise<T>;
|
|
429
571
|
interface RetryOptions {
|
|
430
572
|
maxRetries: number;
|
|
@@ -465,4 +607,4 @@ type Web3Action = {
|
|
|
465
607
|
declare const initialWeb3State: Web3State;
|
|
466
608
|
declare function web3Reducer(state: Web3State, action: Web3Action): Web3State;
|
|
467
609
|
|
|
468
|
-
export { type AtomicSupport, type ChainCapabilities, type ChainInfo, type ConnectionStatus, type DecimalsCache, type RetryOptions, type SolanaIdentity, type SolanaPayer, type SolanaRoles, type SolanaRolesAbsence, type SolanaRolesSource, type SolanaRolesState, type SolanaSigner, type SolanaWalletFeatures, type TokenIdentity, type ViemChainShape, type WalletChain, type Web3Action, type Web3State, __resetResolverForTests, atomicSupportFor, chainNamespace, chainNumber, chainsForNamespace, createDecimalsCache, decodeRevertReason, describeChain, eip155ChainIdToNumber, getResolver, initialWeb3State, isEvmChainId, normalizeCapabilities, normalizeEip155ChainId, readDecimals, readSolanaRoles, resolveChain, resolveEvmChainId, resolveRevertReason, selectChainCapabilities, toChainSwitchError, toEip155Accounts, toViemChain, tokenChainMismatch, tokenKey, web3Reducer, withRetry, withTimeout, writeDecimals };
|
|
610
|
+
export { type AddressValidationLevel, type AtomicSupport, type ChainCapabilities, type ChainInfo, type CompareCosts, type CompareCostsInput, type ConnectionStatus, type CostComparison, type CostComparisonOperation, type CostComparisonOptions, DEFAULT_NOTIFICATION_SETTINGS, type DecimalsCache, type DestinationIssue, type DestinationValidation, type ExecutableQuote, type ExecuteRoute, type ExecuteRouteError, type ExecuteRouteOptions, type ExecuteRouteResult, type GetRouteQuotes, NOTIFICATION_SETTINGS_KEY, type NotificationSettingsStorage, type RetryOptions, type RouteQuote, type RouteQuoteInput, type RouteQuoteOptions, type SolanaIdentity, type SolanaPayer, type SolanaRoles, type SolanaRolesAbsence, type SolanaRolesSource, type SolanaRolesState, type SolanaSigner, type SolanaWalletFeatures, type TokenIdentity, type ViemChainShape, type WalletChain, type Web3Action, type Web3State, __resetResolverForTests, addInAppNotification, atomicSupportFor, bareEvmAddress, chainNamespace, chainNumber, chainsForNamespace, channelsUpdate, clearOneInAppNotification, compareCostsKey, createDecimalsCache, createNotification, createNotificationSettingsStorage, decodeRevertReason, describeChain, eip155ChainIdToNumber, getResolver, initialWeb3State, isBurnDestination, isEvmChainId, isPositiveIntegerAmount, isQuotableInput, loadNotificationSettings, mutedChainSettings, normalizeCapabilities, normalizeEip155ChainId, readDecimals, readSolanaRoles, resolveChain, resolveEvmChainId, resolveRevertReason, saveNotificationSettings, selectChainCapabilities, toChainSwitchError, toEip155Accounts, toExecuteRouteError, toViemChain, tokenChainMismatch, tokenKey, updateNotificationSettings, validateDestination, validateRouteRecipient, web3Reducer, withRetry, withTimeout, writeDecimals };
|
package/dist/index.js
CHANGED
|
@@ -226,6 +226,172 @@ function __resetResolverForTests() {
|
|
|
226
226
|
sharedResolver = null;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
// src/notification.ts
|
|
230
|
+
import {
|
|
231
|
+
createStorageAdapter
|
|
232
|
+
} from "@naculus/connect-core";
|
|
233
|
+
var NOTIFICATION_SETTINGS_KEY = "naculus_notif_react_settings";
|
|
234
|
+
var DEFAULT_NOTIFICATION_SETTINGS = {
|
|
235
|
+
telegram: false,
|
|
236
|
+
webpush: false,
|
|
237
|
+
inapp: true,
|
|
238
|
+
frequency: "final-only",
|
|
239
|
+
mutedChains: [],
|
|
240
|
+
mutedTypes: []
|
|
241
|
+
};
|
|
242
|
+
function createNotificationSettingsStorage() {
|
|
243
|
+
const storage = createStorageAdapter("local", "naculus_notif_");
|
|
244
|
+
return {
|
|
245
|
+
getItem: async (key) => {
|
|
246
|
+
try {
|
|
247
|
+
return await storage.get(key);
|
|
248
|
+
} catch (cause) {
|
|
249
|
+
console.warn("useNotification: failed to read from storage:", cause);
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
setItem: async (key, value) => {
|
|
254
|
+
try {
|
|
255
|
+
await storage.set(key, value);
|
|
256
|
+
} catch (cause) {
|
|
257
|
+
console.warn("useNotification: failed to write to storage:", cause);
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
removeItem: async (key) => {
|
|
261
|
+
try {
|
|
262
|
+
await storage.remove(key);
|
|
263
|
+
} catch (cause) {
|
|
264
|
+
console.warn("useNotification: failed to remove from storage:", cause);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
async function loadNotificationSettings(storage) {
|
|
270
|
+
return storage.getItem(NOTIFICATION_SETTINGS_KEY);
|
|
271
|
+
}
|
|
272
|
+
function saveNotificationSettings(storage, settings) {
|
|
273
|
+
storage.setItem(NOTIFICATION_SETTINGS_KEY, settings).catch(() => {
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function updateNotificationSettings(current, update) {
|
|
277
|
+
return { ...current, ...update };
|
|
278
|
+
}
|
|
279
|
+
function channelsUpdate(channels) {
|
|
280
|
+
const update = {};
|
|
281
|
+
if (channels.includes("telegram")) update.telegram = true;
|
|
282
|
+
if (channels.includes("webpush")) update.webpush = true;
|
|
283
|
+
if (channels.includes("inapp")) update.inapp = true;
|
|
284
|
+
return update;
|
|
285
|
+
}
|
|
286
|
+
function mutedChainSettings(settings, chainId, muted) {
|
|
287
|
+
return {
|
|
288
|
+
mutedChains: muted ? [.../* @__PURE__ */ new Set([...settings.mutedChains, chainId])] : settings.mutedChains.filter((id) => id !== chainId)
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function createNotification(item) {
|
|
292
|
+
return {
|
|
293
|
+
...item,
|
|
294
|
+
id: `notif_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
295
|
+
timestamp: Date.now()
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function sendItem(channel, item) {
|
|
299
|
+
return channel.send({
|
|
300
|
+
id: item.id,
|
|
301
|
+
userId: "",
|
|
302
|
+
txHash: item.txHash,
|
|
303
|
+
chainId: "",
|
|
304
|
+
chainName: item.chainName,
|
|
305
|
+
status: item.status,
|
|
306
|
+
title: item.title,
|
|
307
|
+
body: item.body,
|
|
308
|
+
valueFormatted: item.valueFormatted,
|
|
309
|
+
explorerUrl: item.explorerUrl,
|
|
310
|
+
timestamp: item.timestamp
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
function addInAppNotification(channel, item) {
|
|
314
|
+
void sendItem(channel, createNotification(item));
|
|
315
|
+
}
|
|
316
|
+
async function clearOneInAppNotification(channel, id) {
|
|
317
|
+
const remaining = channel.getHistory().filter((item) => item.id !== id);
|
|
318
|
+
channel.clear();
|
|
319
|
+
await Promise.all(remaining.map((item) => sendItem(channel, item)));
|
|
320
|
+
return channel.getHistory();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/destination.ts
|
|
324
|
+
import { isEvmAddress, isZeroAddress } from "@naculus/connect-core";
|
|
325
|
+
var DEAD_ADDRESSES = /* @__PURE__ */ new Set([
|
|
326
|
+
"0x0000000000000000000000000000000000000001",
|
|
327
|
+
"0x000000000000000000000000000000000000dead"
|
|
328
|
+
]);
|
|
329
|
+
function isBurnDestination(address) {
|
|
330
|
+
const lower = address.toLowerCase();
|
|
331
|
+
return DEAD_ADDRESSES.has(lower) || lower.includes("dead");
|
|
332
|
+
}
|
|
333
|
+
function validateDestination(address) {
|
|
334
|
+
if (!address) return { isValid: false, level: "blocked", issue: "empty" };
|
|
335
|
+
if (!isEvmAddress(address)) {
|
|
336
|
+
return { isValid: false, level: "blocked", issue: "invalid_format" };
|
|
337
|
+
}
|
|
338
|
+
if (isZeroAddress(address)) {
|
|
339
|
+
return { isValid: false, level: "blocked", issue: "zero_address" };
|
|
340
|
+
}
|
|
341
|
+
if (isBurnDestination(address)) {
|
|
342
|
+
return { isValid: false, level: "blocked", issue: "burn_address" };
|
|
343
|
+
}
|
|
344
|
+
return { isValid: true, level: "ok", issue: null };
|
|
345
|
+
}
|
|
346
|
+
function bareEvmAddress(account) {
|
|
347
|
+
if (!account) return null;
|
|
348
|
+
const value = account.includes(":") ? account.split(":").pop() : account;
|
|
349
|
+
return value && isEvmAddress(value) ? value : null;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/routing.ts
|
|
353
|
+
import { isValidAddress } from "@naculus/connect-core";
|
|
354
|
+
function isPositiveIntegerAmount(amount) {
|
|
355
|
+
return /^(?:0|[1-9][0-9]*)$/.test(amount) && BigInt(amount) > 0n;
|
|
356
|
+
}
|
|
357
|
+
function isQuotableInput(input) {
|
|
358
|
+
return Boolean(
|
|
359
|
+
input.fromChain && input.toChain && input.fromToken && isPositiveIntegerAmount(input.amount)
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
function compareCostsKey(input) {
|
|
363
|
+
const options = input.options;
|
|
364
|
+
const optionsKey = options ? Object.keys(options).sort().map((key) => {
|
|
365
|
+
const value = options[key];
|
|
366
|
+
return `${key}=${typeof value === "object" && value !== null ? "[object]" : String(value)}`;
|
|
367
|
+
}).join("&") : "";
|
|
368
|
+
return `${input.operation}|${(input.chains ?? []).join(",")}|${optionsKey}`;
|
|
369
|
+
}
|
|
370
|
+
function validateRouteRecipient(quote, recipient) {
|
|
371
|
+
if (typeof recipient !== "string" || recipient.trim() === "") {
|
|
372
|
+
return {
|
|
373
|
+
code: "invalid_recipient",
|
|
374
|
+
message: "A recipient address is required"
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
const namespace = quote?.toChain?.split(":")[0];
|
|
378
|
+
if (namespace && !isValidAddress(recipient, namespace)) {
|
|
379
|
+
return {
|
|
380
|
+
code: "invalid_recipient",
|
|
381
|
+
message: `"${recipient}" is not a valid ${namespace} address for the destination chain ${quote?.toChain}`
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
function toExecuteRouteError(cause) {
|
|
387
|
+
const error = cause;
|
|
388
|
+
return {
|
|
389
|
+
code: error?.code ?? "execution_failed",
|
|
390
|
+
message: error?.message ?? String(cause),
|
|
391
|
+
details: error?.details
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
229
395
|
// src/web3-store.ts
|
|
230
396
|
import { logger } from "@naculus/connect-core";
|
|
231
397
|
function withTimeout(promise, ms, label = "Operation") {
|
|
@@ -315,18 +481,32 @@ function web3Reducer(state, action) {
|
|
|
315
481
|
}
|
|
316
482
|
}
|
|
317
483
|
export {
|
|
484
|
+
DEFAULT_NOTIFICATION_SETTINGS,
|
|
485
|
+
NOTIFICATION_SETTINGS_KEY,
|
|
318
486
|
__resetResolverForTests,
|
|
487
|
+
addInAppNotification,
|
|
319
488
|
atomicSupportFor,
|
|
489
|
+
bareEvmAddress,
|
|
320
490
|
chainNamespace,
|
|
321
491
|
chainNumber,
|
|
322
492
|
chainsForNamespace,
|
|
493
|
+
channelsUpdate,
|
|
494
|
+
clearOneInAppNotification,
|
|
495
|
+
compareCostsKey,
|
|
323
496
|
createDecimalsCache,
|
|
497
|
+
createNotification,
|
|
498
|
+
createNotificationSettingsStorage,
|
|
324
499
|
decodeRevertReason,
|
|
325
500
|
describeChain,
|
|
326
501
|
eip155ChainIdToNumber,
|
|
327
502
|
getResolver,
|
|
328
503
|
initialWeb3State,
|
|
504
|
+
isBurnDestination,
|
|
329
505
|
isEvmChainId,
|
|
506
|
+
isPositiveIntegerAmount,
|
|
507
|
+
isQuotableInput,
|
|
508
|
+
loadNotificationSettings,
|
|
509
|
+
mutedChainSettings,
|
|
330
510
|
normalizeCapabilities,
|
|
331
511
|
normalizeEip155ChainId,
|
|
332
512
|
readDecimals,
|
|
@@ -334,12 +514,17 @@ export {
|
|
|
334
514
|
resolveChain,
|
|
335
515
|
resolveEvmChainId,
|
|
336
516
|
resolveRevertReason,
|
|
517
|
+
saveNotificationSettings,
|
|
337
518
|
selectChainCapabilities,
|
|
338
519
|
toChainSwitchError,
|
|
339
520
|
toEip155Accounts,
|
|
521
|
+
toExecuteRouteError,
|
|
340
522
|
toViemChain,
|
|
341
523
|
tokenChainMismatch,
|
|
342
524
|
tokenKey,
|
|
525
|
+
updateNotificationSettings,
|
|
526
|
+
validateDestination,
|
|
527
|
+
validateRouteRecipient,
|
|
343
528
|
web3Reducer,
|
|
344
529
|
withRetry,
|
|
345
530
|
withTimeout,
|