@eos3/connect 0.1.12 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,6 +24,7 @@ It does not bundle Telegram's script into the main SDK bundle; call
24
24
  ```ts
25
25
  import {
26
26
  createEosConnect,
27
+ defineEosConnectElements,
27
28
  isEosConnectError,
28
29
  normalizeEosConnectError
29
30
  } from '@eos3/connect';
@@ -48,6 +49,8 @@ const eosConnect = createEosConnect({
48
49
  }
49
50
  });
50
51
 
52
+ defineEosConnectElements({ client: eosConnect });
53
+
51
54
  eosConnect.subscribe((state) => {
52
55
  console.log('EOS wallet state:', state);
53
56
  });
@@ -56,6 +59,7 @@ await eosConnect.bootstrapTelegram();
56
59
  const quickPay = await eosConnect.checkQuickPay();
57
60
 
58
61
  if (!quickPay.enabled) {
62
+ // Requires <eos-connect-modal hidden></eos-connect-modal>.
59
63
  await eosConnect.enableQuickPay();
60
64
  }
61
65
  ```
@@ -95,10 +99,10 @@ const eosConnect = createEosConnect({
95
99
 
96
100
  ## Quick Payment Flow
97
101
 
98
- For app UIs, prefer `checkQuickPay()` and `enableQuickPay()`. They hide
99
- low-level wallet capability statuses such as `needs_local_key`, open pending
100
- bind URLs, rebind the current device when the local payment key is missing, and
101
- can poll until quick payment is enabled:
102
+ For app UIs, use `checkQuickPay()` for readiness and `enableQuickPay()` for the
103
+ button click. `enableQuickPay()` does not start binding directly; it opens the
104
+ SDK-owned `<eos-connect-modal>` from `@eos3/connect` so users always see the
105
+ quick payment setup sheet first:
102
106
 
103
107
  ```ts
104
108
  const quickPay = await eosConnect.checkQuickPay();
@@ -111,14 +115,12 @@ renderQuickPay({
111
115
  });
112
116
 
113
117
  if (!quickPay.enabled) {
114
- const next = await eosConnect.enableQuickPay({
115
- pollIntervalMs: 1500
116
- });
118
+ const next = await eosConnect.enableQuickPay();
117
119
  renderQuickPay(next);
118
120
  }
119
121
  ```
120
122
 
121
- `enableQuickPay()` performs the common Telegram setup sequence:
123
+ The modal's primary action performs the common Telegram setup sequence:
122
124
 
123
125
  - loads Telegram's WebApp SDK when needed;
124
126
  - initializes `BiometricManager` and checks SecureStorage support;
@@ -131,9 +133,9 @@ if (!quickPay.enabled) {
131
133
  the Telegram Mini App returns to the foreground.
132
134
 
133
135
  Advanced UIs can still call `getWalletView()` or `startTelegramWalletFlow()`
134
- when they need debug-level states and labels. Wallet setup always polls after
135
- opening the binding page and returns when the wallet is ready or reaches another
136
- terminal state.
136
+ inside SDK-owned UI when they need debug-level states and labels. Wallet setup
137
+ always polls after opening the binding page and returns when the wallet is ready
138
+ or reaches another terminal state.
137
139
 
138
140
  ## Connect a Telegram Wallet
139
141
 
@@ -285,11 +287,13 @@ await fetch('https://wallet.example.com/api/market/push', {
285
287
  - `checkEosConnectTelegramPayStorage(app)`: initializes Telegram biometrics and returns secure storage diagnostics.
286
288
  - `client.connectTelegram(options)`: starts or resumes Telegram binding.
287
289
  - `client.connectTokenPocket(options)`: starts TokenPocket binding.
288
- - `client.startTelegramWalletFlow(options)`: runs the high-level Telegram wallet setup flow.
289
- - `client.enableQuickPay(options)`: runs the high-level setup flow and returns quick payment readiness.
290
+ - `client.startTelegramWalletFlow(options)`: runs the high-level Telegram wallet setup flow from SDK-owned UI.
291
+ - `client.enableQuickPay()`: opens the SDK-owned `<eos-connect-modal>` and returns current quick payment readiness.
290
292
  - `client.pay(options)`: builds, signs, confirms, and pushes a paylimit payment.
291
293
  - `client.disconnect()`: removes the local Telegram payment key from
292
294
  SecureStorage, clears the biometric token, and resets the SDK state.
295
+ - `defineEosConnectElements(options)`: registers the built-in quick payment Web Components.
296
+ - `installEosConnectStyles(document)`: injects the built-in quick payment UI stylesheet.
293
297
 
294
298
  ## Network Presets
295
299
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import type { PayLimitAssetConfig, PayLimitPayment, SignedTransferPayload } from '@eos3/shared';
1
+ import type { PayLimitAssetConfig, PayLimitPayment, SignedTransferPayload } from './shared/index.js';
2
2
  import { type EosConnectTelegramWebApp } from './telegram-web-app.js';
3
3
  export { EosConnectError, isEosConnectError, normalizeEosConnectError, type EosConnectErrorCode } from './errors.js';
4
4
  export { EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL, getEosConnectTelegramWebApp, loadEosConnectTelegramWebAppSdk, type EosConnectTelegramWebApp } from './telegram-web-app.js';
5
+ export * from './shared/index.js';
6
+ export * from './ui.js';
5
7
  export type EosConnectProviderId = 'telegram' | 'tokenpocket' | 'anchor';
6
8
  export type EosConnectProviderState = 'available' | 'coming_soon' | 'disabled';
7
9
  export type EosConnectStatus = 'idle' | 'not_connected' | 'pending' | 'connected' | 'unsupported' | 'error';
@@ -139,7 +141,7 @@ export interface EosConnectClient {
139
141
  connectTelegram(options?: EosConnectTelegramOptions): Promise<EosConnectState>;
140
142
  connectTokenPocket(options?: EosConnectTelegramOptions): Promise<EosConnectState>;
141
143
  startTelegramWalletFlow(options?: EosConnectWalletFlowOptions): Promise<EosConnectWalletView>;
142
- enableQuickPay(options?: EosConnectWalletFlowOptions): Promise<EosConnectQuickPayStatus>;
144
+ enableQuickPay(): Promise<EosConnectQuickPayStatus>;
143
145
  pay(options: EosConnectPayOptions): Promise<EosConnectPayResult>;
144
146
  disconnect(): Promise<EosConnectState>;
145
147
  }
package/dist/index.js CHANGED
@@ -4,6 +4,8 @@ import { getEosConnectTelegramWebApp, loadEosConnectTelegramWebAppSdk } from './
4
4
  export { EosConnectError, isEosConnectError, normalizeEosConnectError } from './errors.js';
5
5
  import { normalizeEosConnectError } from './errors.js';
6
6
  export { EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL, getEosConnectTelegramWebApp, loadEosConnectTelegramWebAppSdk } from './telegram-web-app.js';
7
+ export * from './shared/index.js';
8
+ export * from './ui.js';
7
9
  const defaultWalletSetupEnv = {
8
10
  hasTelegramSession: true,
9
11
  canStorePayKey: true
@@ -1320,6 +1322,14 @@ function waitForNextWalletPoll(ms) {
1320
1322
  documentRef.addEventListener('visibilitychange', onVisibilityChange);
1321
1323
  });
1322
1324
  }
1325
+ function openEosConnectUiModal() {
1326
+ const modal = globalThis.document?.querySelector?.('eos-connect-modal,eos-connect');
1327
+ if (!modal) {
1328
+ return false;
1329
+ }
1330
+ modal.removeAttribute('hidden');
1331
+ return true;
1332
+ }
1323
1333
  function openFlowUrl(url, clientOptions, flowOptions, telegramWebApp) {
1324
1334
  if (flowOptions.openExternal) {
1325
1335
  flowOptions.openExternal(url);
@@ -1634,8 +1644,11 @@ export function createEosConnect(options) {
1634
1644
  return walletViewFromError(normalized, message);
1635
1645
  }
1636
1646
  },
1637
- async enableQuickPay(flowOptions = {}) {
1638
- return quickPayFromView(await this.startTelegramWalletFlow(flowOptions));
1647
+ async enableQuickPay() {
1648
+ if (!openEosConnectUiModal()) {
1649
+ throw new Error('EOS Connect UI modal is required to enable quick payment');
1650
+ }
1651
+ return this.checkQuickPay();
1639
1652
  },
1640
1653
  async connectTokenPocket(tokenPocketOptions = {}) {
1641
1654
  const paymentKey = await generateEosConnectPaymentKey();
@@ -0,0 +1,2 @@
1
+ export declare function generateEosAccountName(): string;
2
+ export declare function assertEosAccountName(accountName: string): void;
@@ -0,0 +1,18 @@
1
+ const EOS_ACCOUNT_CHARS = 'abcdefghijklmnopqrstuvwxyz12345';
2
+ export function generateEosAccountName() {
3
+ const bytes = new Uint8Array(11);
4
+ globalThis.crypto.getRandomValues(bytes);
5
+ let suffix = '';
6
+ for (const byte of bytes) {
7
+ suffix += EOS_ACCOUNT_CHARS[byte % EOS_ACCOUNT_CHARS.length];
8
+ }
9
+ return `u${suffix}`;
10
+ }
11
+ export function assertEosAccountName(accountName) {
12
+ if (!/^[a-z][a-z1-5.]{0,11}$/.test(accountName)) {
13
+ throw new Error('Invalid EOS account name');
14
+ }
15
+ if (accountName.startsWith('.') || /^[1-5]/.test(accountName)) {
16
+ throw new Error('EOS account name cannot start with a dot or number');
17
+ }
18
+ }
@@ -0,0 +1,3 @@
1
+ export * from './account.js';
2
+ export * from './transfer.js';
3
+ export * from './types.js';
@@ -0,0 +1,3 @@
1
+ export * from './account.js';
2
+ export * from './transfer.js';
3
+ export * from './types.js';
@@ -0,0 +1,54 @@
1
+ import type { OptionalAssetLimit, PayLimitPayment, TransferSummary } from './types.js';
2
+ export declare function normalizeEosQuantity(amount: string, symbol?: string, precision?: number): string;
3
+ export declare function normalizeOptionalAssetLimit(amount: string | null | undefined, symbol?: string, precision?: number): OptionalAssetLimit;
4
+ export declare function hashTelegramBotId(botId: string): string;
5
+ export declare function deriveBotPermissionName(botId: string, collisionNonce?: number): string;
6
+ export declare function assertTransferSummaryBelongsToUser(summary: TransferSummary, eosAccount: string): void;
7
+ export declare function assertTransferActionBelongsToUser(signedTransaction: {
8
+ transaction?: {
9
+ actions?: Array<{
10
+ account?: string;
11
+ name?: string;
12
+ authorization?: Array<{
13
+ actor?: string;
14
+ permission?: string;
15
+ }>;
16
+ data?: Record<string, unknown> & {
17
+ from?: string;
18
+ };
19
+ }>;
20
+ };
21
+ }, eosAccount: string, options?: {
22
+ tokenContract?: string;
23
+ permission?: 'active' | 'tgpay';
24
+ }): void;
25
+ export declare function assertPayLimitActionBelongsToUser(signedTransaction: {
26
+ transaction?: {
27
+ actions?: Array<{
28
+ account?: string;
29
+ name?: string;
30
+ authorization?: Array<{
31
+ actor?: string;
32
+ permission?: string;
33
+ }>;
34
+ data?: Record<string, unknown> & {
35
+ from?: string;
36
+ to?: string;
37
+ token_contract?: string;
38
+ quantity?: string;
39
+ memo?: string;
40
+ bot_id_hash?: string;
41
+ permission?: string;
42
+ payments?: unknown;
43
+ };
44
+ }>;
45
+ };
46
+ }, expected: {
47
+ payLimitContract: string;
48
+ eosAccount: string;
49
+ permission: string;
50
+ botIdHash: string;
51
+ payments: PayLimitPayment[];
52
+ sponsorAccount?: string;
53
+ sponsorPermission?: string;
54
+ }): void;
@@ -0,0 +1,122 @@
1
+ import { sha256 } from '@noble/hashes/sha2.js';
2
+ import { bytesToHex } from '@noble/hashes/utils.js';
3
+ const EOS_NAME_CHARS = 'abcdefghijklmnopqrstuvwxyz12345';
4
+ function normalizeQuantity(amount, symbol = 'EOS', precision = 4, options = {}) {
5
+ const trimmed = amount.trim();
6
+ if (!/^\d+(\.\d+)?$/.test(trimmed)) {
7
+ throw new Error('Invalid transfer amount');
8
+ }
9
+ const [wholePart, decimalPart = ''] = trimmed.split('.');
10
+ if (decimalPart.length > precision) {
11
+ throw new Error(`Amount exceeds ${precision} decimal precision`);
12
+ }
13
+ const whole = Number(wholePart);
14
+ const decimal = Number(decimalPart.padEnd(precision, '0') || '0');
15
+ if (!options.allowZero && whole === 0 && decimal === 0) {
16
+ throw new Error('Transfer amount must be positive');
17
+ }
18
+ return `${wholePart}.${decimalPart.padEnd(precision, '0')} ${symbol}`;
19
+ }
20
+ export function normalizeEosQuantity(amount, symbol = 'EOS', precision = 4) {
21
+ return normalizeQuantity(amount, symbol, precision);
22
+ }
23
+ export function normalizeOptionalAssetLimit(amount, symbol = 'EOS', precision = 4) {
24
+ if (amount === null || amount === undefined || amount.trim() === '') {
25
+ return {
26
+ hasLimit: false,
27
+ quantity: normalizeQuantity('0', symbol, precision, { allowZero: true })
28
+ };
29
+ }
30
+ return {
31
+ hasLimit: true,
32
+ quantity: normalizeQuantity(amount, symbol, precision, { allowZero: true })
33
+ };
34
+ }
35
+ export function hashTelegramBotId(botId) {
36
+ return bytesToHex(sha256(new TextEncoder().encode(botId)));
37
+ }
38
+ export function deriveBotPermissionName(botId, collisionNonce = 0) {
39
+ const seed = collisionNonce === 0 ? botId : `${botId}:${collisionNonce}`;
40
+ const hash = sha256(new TextEncoder().encode(seed));
41
+ let suffix = '';
42
+ for (let index = 0; suffix.length < 10; index += 1) {
43
+ suffix += EOS_NAME_CHARS[hash[index % hash.length] % EOS_NAME_CHARS.length];
44
+ }
45
+ return `tg${suffix}`;
46
+ }
47
+ export function assertTransferSummaryBelongsToUser(summary, eosAccount) {
48
+ if (summary.from !== eosAccount) {
49
+ throw new Error('Signed transaction does not belong to the current wallet');
50
+ }
51
+ }
52
+ export function assertTransferActionBelongsToUser(signedTransaction, eosAccount, options = {}) {
53
+ const actions = signedTransaction.transaction?.actions;
54
+ if (!Array.isArray(actions) || actions.length !== 1) {
55
+ throw new Error('Signed transaction must contain exactly one action');
56
+ }
57
+ const transferAction = actions[0];
58
+ const tokenContract = options.tokenContract ?? 'eosio.token';
59
+ const permission = options.permission ?? 'tgpay';
60
+ if (transferAction.account !== tokenContract || transferAction.name !== 'transfer') {
61
+ throw new Error('Signed transaction action must be an EOS token transfer');
62
+ }
63
+ if (transferAction?.data?.from !== eosAccount) {
64
+ throw new Error('Signed transaction action does not belong to the current wallet');
65
+ }
66
+ const hasWalletActor = transferAction.authorization?.some((auth) => auth.actor === eosAccount);
67
+ if (!hasWalletActor) {
68
+ throw new Error('Signed transaction authorization does not belong to the current wallet');
69
+ }
70
+ const hasWalletAuthorization = transferAction.authorization?.some((auth) => auth.actor === eosAccount && auth.permission === permission);
71
+ if (!hasWalletAuthorization) {
72
+ throw new Error(`Signed transaction authorization must use ${eosAccount}@${permission}`);
73
+ }
74
+ }
75
+ export function assertPayLimitActionBelongsToUser(signedTransaction, expected) {
76
+ const actions = signedTransaction.transaction?.actions;
77
+ if (!Array.isArray(actions) || actions.length !== 2) {
78
+ throw new Error('Signed transaction must contain exactly sponsor noop and paylimit actions');
79
+ }
80
+ const sponsorAction = actions[0];
81
+ const expectedSponsorAccount = expected.sponsorAccount ?? expected.payLimitContract;
82
+ const expectedSponsorPermission = expected.sponsorPermission ?? 'paycpu';
83
+ if (sponsorAction.account !== expected.payLimitContract || sponsorAction.name !== 'noop') {
84
+ throw new Error('Signed transaction first action must be the paylimit sponsor noop');
85
+ }
86
+ const hasSponsorAuthorization = sponsorAction.authorization?.some((auth) => auth.actor === expectedSponsorAccount &&
87
+ auth.permission === expectedSponsorPermission);
88
+ if (!hasSponsorAuthorization) {
89
+ throw new Error(`Signed transaction sponsor action must use ${expectedSponsorAccount}@${expectedSponsorPermission}`);
90
+ }
91
+ const action = actions[1];
92
+ if (action.account !== expected.payLimitContract || action.name !== 'pay') {
93
+ throw new Error('Signed transaction second action must be a paylimit payment');
94
+ }
95
+ const data = action.data;
96
+ if (!data || data.from !== expected.eosAccount) {
97
+ throw new Error('Signed paylimit action does not belong to the current wallet');
98
+ }
99
+ if (data.bot_id_hash !== expected.botIdHash ||
100
+ data.permission !== expected.permission) {
101
+ throw new Error('Signed paylimit action does not match the current Telegram bot permission');
102
+ }
103
+ if (!Array.isArray(data.payments) || data.payments.length !== expected.payments.length) {
104
+ throw new Error('Signed paylimit action payments do not match the requested payment count');
105
+ }
106
+ const actualPayments = data.payments;
107
+ expected.payments.forEach((payment, index) => {
108
+ const actual = actualPayments[index];
109
+ if (!actual ||
110
+ actual.to !== payment.to ||
111
+ actual.token_contract !== payment.tokenContract ||
112
+ actual.quantity !== payment.quantity ||
113
+ actual.memo !== payment.memo) {
114
+ throw new Error(`Signed paylimit action payment ${index + 1} does not match the request`);
115
+ }
116
+ });
117
+ const hasWalletAuthorization = action.authorization?.some((auth) => auth.actor === expected.eosAccount &&
118
+ auth.permission === expected.permission);
119
+ if (!hasWalletAuthorization) {
120
+ throw new Error(`Signed transaction authorization must use ${expected.eosAccount}@${expected.permission}`);
121
+ }
122
+ }
@@ -0,0 +1,76 @@
1
+ export type WalletDeviceStatus = 'pending' | 'active' | 'failed' | 'expired' | 'superseded';
2
+ export type BindIntentStatus = 'pending' | 'passkey_created' | 'account_created_waiting_tgpay' | 'account_created' | 'expired' | 'superseded' | 'failed';
3
+ export type TransferStatus = 'pending' | 'pushed' | 'failed';
4
+ export interface PublicUser {
5
+ id: string;
6
+ telegramUserId: string | null;
7
+ telegramUsername: string | null;
8
+ googleSub?: string | null;
9
+ email?: string | null;
10
+ displayName?: string | null;
11
+ avatarUrl?: string | null;
12
+ eosAccount: string | null;
13
+ }
14
+ export interface TransferSummary {
15
+ from: string;
16
+ to: string;
17
+ quantity: string;
18
+ memo: string;
19
+ permission?: string;
20
+ }
21
+ export interface PayLimitAssetConfig {
22
+ tokenContract: string;
23
+ symbol: string;
24
+ precision: number;
25
+ perTxLimit?: string | null;
26
+ dailyLimit?: string | null;
27
+ totalBudget?: string | null;
28
+ }
29
+ export interface OptionalAssetLimit {
30
+ hasLimit: boolean;
31
+ quantity: string;
32
+ }
33
+ export interface PayLimitSummary {
34
+ from: string;
35
+ to: string;
36
+ tokenContract: string;
37
+ quantity: string;
38
+ memo: string;
39
+ botIdHash: string;
40
+ permission: string;
41
+ }
42
+ export interface PayLimitPayment {
43
+ to: string;
44
+ tokenContract: string;
45
+ quantity: string;
46
+ memo: string;
47
+ }
48
+ export interface PayLimitBatchSummary {
49
+ from: string;
50
+ payments: PayLimitPayment[];
51
+ botIdHash: string;
52
+ permission: string;
53
+ }
54
+ export interface BuiltTransfer {
55
+ transaction: Record<string, unknown>;
56
+ chainId: string;
57
+ summary: TransferSummary;
58
+ }
59
+ export interface BuiltPayLimitTransfer {
60
+ intentId: string;
61
+ transaction: Record<string, unknown>;
62
+ chainId: string;
63
+ summary: PayLimitSummary;
64
+ payments?: PayLimitPayment[];
65
+ }
66
+ export interface BuiltPayLimitBatchTransfer {
67
+ intentId: string;
68
+ transaction: Record<string, unknown>;
69
+ chainId: string;
70
+ summary: PayLimitBatchSummary;
71
+ }
72
+ export interface SignedTransferPayload {
73
+ signatures: string[];
74
+ serializedTransaction: number[] | string;
75
+ transaction: Record<string, unknown>;
76
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/ui.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ import type { EosConnectClient, EosConnectNetwork, EosConnectProviderId, EosConnectTelegramOptions, EosConnectTelegramWebApp, EosConnectWalletView } from './index.js';
2
+ export type EosConnectUiTelegramOptions = EosConnectTelegramOptions & {
3
+ botUsername?: string;
4
+ openExternal?: (url: string) => void;
5
+ };
6
+ export interface EosConnectUiMessages {
7
+ enableQuickPayment?: string;
8
+ quickPaymentEnabled?: string;
9
+ quickPaymentChecking?: string;
10
+ quickPaymentCheckingDescription?: string;
11
+ quickPaymentSuccess?: string;
12
+ quickPaymentSuccessDescription?: string;
13
+ quickPaymentSetupDescription?: string;
14
+ /** @deprecated Use quickPaymentSetupDescription instead. */
15
+ localKeyMissingDescription?: string;
16
+ closeEosConnect?: string;
17
+ }
18
+ export interface EosConnectElementsOptions {
19
+ client?: EosConnectClient;
20
+ network?: EosConnectNetwork;
21
+ apiBaseUrl?: string;
22
+ botUsername?: string;
23
+ locale?: string;
24
+ messages?: EosConnectUiMessages;
25
+ assetLimits?: EosConnectTelegramOptions['assetLimits'];
26
+ replaceWallet?: boolean;
27
+ telegramOptions?: EosConnectUiTelegramOptions;
28
+ openExternal?: (url: string) => void;
29
+ telegramWebApp?: EosConnectTelegramWebApp | null;
30
+ injectStyles?: boolean;
31
+ customElements?: CustomElementRegistry;
32
+ }
33
+ export interface EosConnectUiErrorDetail {
34
+ error: unknown;
35
+ provider?: EosConnectProviderId;
36
+ }
37
+ type DocumentLike = Pick<Document, 'createElement' | 'head' | 'querySelector'>;
38
+ export declare function installEosConnectStyles(documentRef?: DocumentLike | undefined): void;
39
+ export type EosConnectUiFlowState = 'idle' | 'checking' | 'success';
40
+ export type EosConnectUiRenderOptions = {
41
+ locale?: string;
42
+ messages?: EosConnectUiMessages;
43
+ telegramWebApp?: EosConnectTelegramWebApp | null;
44
+ flowState?: EosConnectUiFlowState;
45
+ };
46
+ export declare function renderEosConnectButton(client: EosConnectClient, options?: EosConnectUiRenderOptions): string;
47
+ export declare function renderEosConnectSheet(client: EosConnectClient, options?: EosConnectUiRenderOptions): string;
48
+ export declare function connectEosProvider(client: EosConnectClient, _provider?: EosConnectProviderId, options?: EosConnectUiTelegramOptions): Promise<EosConnectWalletView | void>;
49
+ export declare function defineEosConnectElements({ client, network, apiBaseUrl, botUsername, locale, messages, assetLimits, replaceWallet, telegramOptions, openExternal, telegramWebApp, injectStyles, customElements: registry }: EosConnectElementsOptions): void;
50
+ export {};