@eos3/connect 0.1.4 → 0.1.10
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 +69 -9
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +143 -0
- package/dist/http.d.ts +3 -0
- package/dist/http.js +40 -0
- package/dist/index.d.ts +54 -49
- package/dist/index.js +342 -184
- package/dist/telegram-web-app.d.ts +35 -0
- package/dist/telegram-web-app.js +37 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,28 +24,40 @@ It does not bundle Telegram's script into the main SDK bundle; call
|
|
|
24
24
|
```ts
|
|
25
25
|
import {
|
|
26
26
|
createEosConnect,
|
|
27
|
-
getEosConnectTelegramWebApp,
|
|
28
27
|
isEosConnectError,
|
|
29
|
-
loadEosConnectTelegramWebAppSdk,
|
|
30
28
|
normalizeEosConnectError
|
|
31
29
|
} from '@eos3/connect';
|
|
32
30
|
|
|
33
|
-
await loadEosConnectTelegramWebAppSdk().catch(() => undefined);
|
|
34
|
-
const telegramWebApp = getEosConnectTelegramWebApp();
|
|
35
|
-
|
|
36
31
|
const eosConnect = createEosConnect({
|
|
37
32
|
network: 'testnet',
|
|
38
33
|
apiBaseUrl: 'https://your-wallet-api.example.com',
|
|
39
34
|
botUsername: 'your_bot',
|
|
40
35
|
locale: 'zh-CN',
|
|
41
|
-
|
|
36
|
+
defaultConnectOptions: {
|
|
37
|
+
replaceWallet: true,
|
|
38
|
+
assetLimits: [
|
|
39
|
+
{
|
|
40
|
+
tokenContract: 'core.vaulta',
|
|
41
|
+
symbol: 'A',
|
|
42
|
+
precision: 4,
|
|
43
|
+
perTxLimit: '1',
|
|
44
|
+
dailyLimit: '10',
|
|
45
|
+
totalBudget: '100'
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
42
49
|
});
|
|
43
50
|
|
|
44
51
|
eosConnect.subscribe((state) => {
|
|
45
52
|
console.log('EOS wallet state:', state);
|
|
46
53
|
});
|
|
47
54
|
|
|
48
|
-
await eosConnect.
|
|
55
|
+
await eosConnect.bootstrapTelegram();
|
|
56
|
+
const quickPay = await eosConnect.checkQuickPay();
|
|
57
|
+
|
|
58
|
+
if (!quickPay.enabled) {
|
|
59
|
+
await eosConnect.enableQuickPay();
|
|
60
|
+
}
|
|
49
61
|
```
|
|
50
62
|
|
|
51
63
|
`network` can be `testnet` or `mainnet`. It selects browser signing RPC
|
|
@@ -58,13 +70,14 @@ When `botUsername` is set, the SDK sends it as `x-telegram-bot-username` so a
|
|
|
58
70
|
shared backend can choose the correct Telegram bot token for `initData`
|
|
59
71
|
verification.
|
|
60
72
|
|
|
61
|
-
`connectTelegram()`
|
|
73
|
+
`enableQuickPay()`, `startTelegramWalletFlow()`, and `connectTelegram()` open the `bindUrl` returned by the API. The API should
|
|
62
74
|
generate that URL from its `WEB_BASE_URL`, so users leave the Mini App and finish
|
|
63
75
|
passkey authentication on the hosted passkey binding page.
|
|
64
76
|
|
|
65
77
|
## Internationalization
|
|
66
78
|
|
|
67
|
-
|
|
79
|
+
Quick payment labels, Wallet ViewModel text, and the built-in payment confirmation sheet support
|
|
80
|
+
English and Simplified Chinese.
|
|
68
81
|
The SDK uses explicit `locale`, then Telegram `language_code`, then
|
|
69
82
|
`navigator.language`, and falls back to English:
|
|
70
83
|
|
|
@@ -73,12 +86,53 @@ const eosConnect = createEosConnect({
|
|
|
73
86
|
telegramWebApp,
|
|
74
87
|
locale: 'zh-CN',
|
|
75
88
|
messages: {
|
|
89
|
+
walletSetupTitle: '开启钱包',
|
|
76
90
|
paymentConfirmTitle: '确认付款',
|
|
77
91
|
paymentConfirmAction: '支付'
|
|
78
92
|
}
|
|
79
93
|
});
|
|
80
94
|
```
|
|
81
95
|
|
|
96
|
+
## Quick Payment Flow
|
|
97
|
+
|
|
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
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const quickPay = await eosConnect.checkQuickPay();
|
|
105
|
+
|
|
106
|
+
renderQuickPay({
|
|
107
|
+
enabled: quickPay.enabled,
|
|
108
|
+
account: quickPay.account,
|
|
109
|
+
balance: quickPay.balance,
|
|
110
|
+
buttonLabel: quickPay.enabled ? '快捷支付已开启' : '开启快捷支付'
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (!quickPay.enabled) {
|
|
114
|
+
const next = await eosConnect.enableQuickPay({
|
|
115
|
+
pollIntervalMs: 1500,
|
|
116
|
+
timeoutMs: 120_000
|
|
117
|
+
});
|
|
118
|
+
renderQuickPay(next);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`enableQuickPay()` performs the common Telegram setup sequence:
|
|
123
|
+
|
|
124
|
+
- loads Telegram's WebApp SDK when needed;
|
|
125
|
+
- initializes `BiometricManager` and checks SecureStorage support;
|
|
126
|
+
- calls `checkWallet()`;
|
|
127
|
+
- opens an existing `pending` `bindUrl`;
|
|
128
|
+
- calls `connectTelegram({ replaceWallet: true })` when the current device is
|
|
129
|
+
missing the local payment key;
|
|
130
|
+
- polls wallet readiness until `ready`, another terminal state, or timeout.
|
|
131
|
+
|
|
132
|
+
Advanced UIs can still call `getWalletView()` or `startTelegramWalletFlow()`
|
|
133
|
+
when they need debug-level states and labels. Pass `waitForReady: false` if
|
|
134
|
+
your UI should return immediately after opening the binding page.
|
|
135
|
+
|
|
82
136
|
## Connect a Telegram Wallet
|
|
83
137
|
|
|
84
138
|
```ts
|
|
@@ -220,11 +274,17 @@ await fetch('https://wallet.example.com/api/market/push', {
|
|
|
220
274
|
- `client.getProviders()`: returns wallet provider metadata.
|
|
221
275
|
- `client.getSnapshot()`: returns the current state.
|
|
222
276
|
- `client.subscribe(listener)`: subscribes to state changes.
|
|
277
|
+
- `client.bootstrapTelegram()`: loads Telegram WebApp SDK, initializes biometrics, and checks secure storage support.
|
|
223
278
|
- `client.restore()`: loads wallet state from the API.
|
|
279
|
+
- `client.refreshWallet()`: refreshes wallet readiness and returns a UI-ready ViewModel.
|
|
224
280
|
- `client.checkWallet()`: checks server wallet plus local key readiness.
|
|
281
|
+
- `client.checkQuickPay()`: returns `{ enabled, account, balance, reason }` for business UI.
|
|
282
|
+
- `client.getWalletView()`: returns the current wallet ViewModel for app UIs.
|
|
225
283
|
- `checkEosConnectTelegramPayStorage(app)`: initializes Telegram biometrics and returns secure storage diagnostics.
|
|
226
284
|
- `client.connectTelegram(options)`: starts or resumes Telegram binding.
|
|
227
285
|
- `client.connectTokenPocket(options)`: starts TokenPocket binding.
|
|
286
|
+
- `client.startTelegramWalletFlow(options)`: runs the high-level Telegram wallet setup flow.
|
|
287
|
+
- `client.enableQuickPay(options)`: runs the high-level setup flow and returns quick payment readiness.
|
|
228
288
|
- `client.pay(options)`: builds, signs, confirms, and pushes a paylimit payment.
|
|
229
289
|
- `client.disconnect()`: removes the local Telegram payment key from
|
|
230
290
|
SecureStorage, clears the biometric token, and resets the SDK state.
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type EosConnectErrorCode = 'DAILY_LIMIT_EXCEEDED' | 'PER_TX_LIMIT_EXCEEDED' | 'TOTAL_BUDGET_EXCEEDED' | 'INSUFFICIENT_BALANCE' | 'RAM_INSUFFICIENT' | 'PAYMENT_PERMISSION_MISSING' | 'SIGNATURE_REJECTED' | 'SESSION_EXPIRED' | 'NETWORK_ERROR' | 'UNKNOWN_CHAIN_ERROR';
|
|
2
|
+
export declare class EosConnectError extends Error {
|
|
3
|
+
readonly code: EosConnectErrorCode;
|
|
4
|
+
readonly rawMessage: string;
|
|
5
|
+
readonly retryable: boolean;
|
|
6
|
+
constructor(code: EosConnectErrorCode, message: string, options?: {
|
|
7
|
+
rawMessage?: string;
|
|
8
|
+
retryable?: boolean;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export declare function isEosConnectError(error: unknown): error is EosConnectError;
|
|
13
|
+
export declare function normalizeEosConnectError(error: unknown): EosConnectError;
|
|
14
|
+
export declare function rawErrorMessage(error: unknown): string;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export class EosConnectError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
rawMessage;
|
|
4
|
+
retryable;
|
|
5
|
+
constructor(code, message, options = {}) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'EosConnectError';
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.rawMessage = options.rawMessage ?? message;
|
|
10
|
+
this.retryable = options.retryable ?? false;
|
|
11
|
+
if (options.cause !== undefined) {
|
|
12
|
+
this.cause = options.cause;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function isEosConnectError(error) {
|
|
17
|
+
return error instanceof EosConnectError;
|
|
18
|
+
}
|
|
19
|
+
export function normalizeEosConnectError(error) {
|
|
20
|
+
if (isEosConnectError(error)) {
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
const rawMessage = rawErrorMessage(error);
|
|
24
|
+
const normalized = rawMessage.toLowerCase();
|
|
25
|
+
if (normalized.includes('daily limit exceeded')) {
|
|
26
|
+
return new EosConnectError('DAILY_LIMIT_EXCEEDED', '今日支付额度已用完,请明天再试或提高每日额度。', {
|
|
27
|
+
rawMessage,
|
|
28
|
+
cause: error
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (normalized.includes('per-transfer limit exceeded') ||
|
|
32
|
+
normalized.includes('per transfer limit exceeded') ||
|
|
33
|
+
normalized.includes('per_tx_limit') ||
|
|
34
|
+
normalized.includes('single transfer limit')) {
|
|
35
|
+
return new EosConnectError('PER_TX_LIMIT_EXCEEDED', '本次支付超过单笔额度,请降低金额或提高单笔额度。', {
|
|
36
|
+
rawMessage,
|
|
37
|
+
cause: error
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (normalized.includes('total budget exceeded')) {
|
|
41
|
+
return new EosConnectError('TOTAL_BUDGET_EXCEEDED', '该权限的总预算已用完,请调整总预算后再试。', {
|
|
42
|
+
rawMessage,
|
|
43
|
+
cause: error
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (normalized.includes('overdrawn balance') ||
|
|
47
|
+
normalized.includes('insufficient balance') ||
|
|
48
|
+
normalized.includes('balance is insufficient')) {
|
|
49
|
+
return new EosConnectError('INSUFFICIENT_BALANCE', '余额不足,请充值后再试。', {
|
|
50
|
+
rawMessage,
|
|
51
|
+
cause: error
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (normalized.includes('ram usage') ||
|
|
55
|
+
normalized.includes('billed ram') ||
|
|
56
|
+
normalized.includes('insufficient ram') ||
|
|
57
|
+
normalized.includes('current ram usage limit')) {
|
|
58
|
+
return new EosConnectError('RAM_INSUFFICIENT', '账号 RAM 不足,请补充 RAM 后再试。', {
|
|
59
|
+
rawMessage,
|
|
60
|
+
cause: error
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (normalized.includes('bot permission is inactive') ||
|
|
64
|
+
normalized.includes('permission does not match bot authorization') ||
|
|
65
|
+
normalized.includes('paylimit code authority is missing') ||
|
|
66
|
+
normalized.includes('missing from transfer permission') ||
|
|
67
|
+
normalized.includes('transaction declares authority') ||
|
|
68
|
+
normalized.includes('missing authority')) {
|
|
69
|
+
return new EosConnectError('PAYMENT_PERMISSION_MISSING', '快捷支付权限未绑定或已失效,请重新绑定后再试。', {
|
|
70
|
+
rawMessage,
|
|
71
|
+
cause: error
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (normalized.includes('not signed in') ||
|
|
75
|
+
normalized.includes('invalid session') ||
|
|
76
|
+
normalized.includes('session user not found') ||
|
|
77
|
+
normalized.includes('telegram initdata is missing') ||
|
|
78
|
+
normalized.includes('telegram session not found')) {
|
|
79
|
+
return new EosConnectError('SESSION_EXPIRED', '登录状态已失效,请重新打开小程序或重新登录。', {
|
|
80
|
+
rawMessage,
|
|
81
|
+
cause: error
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (normalized.includes('notallowederror') ||
|
|
85
|
+
normalized.includes('aborterror') ||
|
|
86
|
+
normalized.includes('payment confirmation was cancelled') ||
|
|
87
|
+
normalized.includes('biometric authentication failed') ||
|
|
88
|
+
normalized.includes('user cancelled')) {
|
|
89
|
+
return new EosConnectError('SIGNATURE_REJECTED', '已取消签名确认,支付未提交。', {
|
|
90
|
+
rawMessage,
|
|
91
|
+
cause: error
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (normalized.includes('open this wallet in the telegram mobile app') ||
|
|
95
|
+
normalized.includes('secure biometric key storage') ||
|
|
96
|
+
normalized.includes('securestorage is not available') ||
|
|
97
|
+
normalized.includes('secure storage is not available')) {
|
|
98
|
+
return new EosConnectError('SIGNATURE_REJECTED', '请在 Telegram 手机客户端打开,当前设备不支持安全存储。', {
|
|
99
|
+
rawMessage,
|
|
100
|
+
cause: error
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (normalized.includes('biometric unlock key is missing') ||
|
|
104
|
+
normalized.includes('quick key is missing')) {
|
|
105
|
+
return new EosConnectError('PAYMENT_PERMISSION_MISSING', '当前设备缺少本地支付密钥,请重新绑定。', {
|
|
106
|
+
rawMessage,
|
|
107
|
+
cause: error
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (normalized.includes('failed to fetch') ||
|
|
111
|
+
normalized.includes('network') ||
|
|
112
|
+
normalized.includes('all eos rpc nodes failed') ||
|
|
113
|
+
normalized.includes('eos rpc') ||
|
|
114
|
+
normalized.includes('timeout')) {
|
|
115
|
+
return new EosConnectError('NETWORK_ERROR', '网络连接失败,请稍后重试。', {
|
|
116
|
+
rawMessage,
|
|
117
|
+
retryable: true,
|
|
118
|
+
cause: error
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return new EosConnectError('UNKNOWN_CHAIN_ERROR', '支付失败,请稍后重试或联系服务方。', {
|
|
122
|
+
rawMessage,
|
|
123
|
+
cause: error
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
export function rawErrorMessage(error) {
|
|
127
|
+
if (error instanceof Error) {
|
|
128
|
+
return error.message;
|
|
129
|
+
}
|
|
130
|
+
if (typeof error === 'string') {
|
|
131
|
+
return error;
|
|
132
|
+
}
|
|
133
|
+
if (error && typeof error === 'object') {
|
|
134
|
+
const maybeError = error;
|
|
135
|
+
if (typeof maybeError.error === 'string') {
|
|
136
|
+
return maybeError.error;
|
|
137
|
+
}
|
|
138
|
+
if (typeof maybeError.message === 'string') {
|
|
139
|
+
return maybeError.message;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return 'EOS Connect request failed';
|
|
143
|
+
}
|
package/dist/http.d.ts
ADDED
package/dist/http.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { EosConnectError, normalizeEosConnectError, rawErrorMessage } from './errors.js';
|
|
2
|
+
export async function parseResponseBody(response) {
|
|
3
|
+
try {
|
|
4
|
+
return await response.json();
|
|
5
|
+
}
|
|
6
|
+
catch (jsonError) {
|
|
7
|
+
if (typeof response.text === 'function') {
|
|
8
|
+
const text = await response.text().catch(() => '');
|
|
9
|
+
if (text) {
|
|
10
|
+
return text;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
throw jsonError;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function httpStatusMessage(response) {
|
|
17
|
+
const status = typeof response.status === 'number' ? response.status : 0;
|
|
18
|
+
const statusText = response.statusText ? ` ${response.statusText}` : '';
|
|
19
|
+
return status ? `HTTP ${status}${statusText}` : 'HTTP request failed';
|
|
20
|
+
}
|
|
21
|
+
function bodyMessage(body) {
|
|
22
|
+
if (typeof body === 'string') {
|
|
23
|
+
return body.replace(/\s+/g, ' ').trim();
|
|
24
|
+
}
|
|
25
|
+
return rawErrorMessage(body);
|
|
26
|
+
}
|
|
27
|
+
export function normalizeHttpResponseError(response, body) {
|
|
28
|
+
if (body && typeof body === 'object') {
|
|
29
|
+
return normalizeEosConnectError(body);
|
|
30
|
+
}
|
|
31
|
+
const rawMessage = `${httpStatusMessage(response)}: ${bodyMessage(body)}`.trim();
|
|
32
|
+
const status = typeof response.status === 'number' ? response.status : 0;
|
|
33
|
+
if (status >= 500) {
|
|
34
|
+
return new EosConnectError('NETWORK_ERROR', '网络连接失败,请稍后重试。', {
|
|
35
|
+
rawMessage,
|
|
36
|
+
retryable: true
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return normalizeEosConnectError(rawMessage);
|
|
40
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { PayLimitAssetConfig, PayLimitPayment, SignedTransferPayload } from '@eos3/shared';
|
|
2
|
+
import { type EosConnectTelegramWebApp } from './telegram-web-app.js';
|
|
3
|
+
export { EosConnectError, isEosConnectError, normalizeEosConnectError, type EosConnectErrorCode } from './errors.js';
|
|
4
|
+
export { EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL, getEosConnectTelegramWebApp, loadEosConnectTelegramWebAppSdk, type EosConnectTelegramWebApp } from './telegram-web-app.js';
|
|
2
5
|
export type EosConnectProviderId = 'telegram' | 'tokenpocket' | 'anchor';
|
|
3
6
|
export type EosConnectProviderState = 'available' | 'coming_soon' | 'disabled';
|
|
4
7
|
export type EosConnectStatus = 'idle' | 'not_connected' | 'pending' | 'connected' | 'unsupported' | 'error';
|
|
@@ -12,41 +15,6 @@ export interface EosConnectProvider {
|
|
|
12
15
|
state: EosConnectProviderState;
|
|
13
16
|
description: string;
|
|
14
17
|
}
|
|
15
|
-
export interface EosConnectTelegramWebApp {
|
|
16
|
-
initData?: string;
|
|
17
|
-
initDataUnsafe?: {
|
|
18
|
-
user?: {
|
|
19
|
-
language_code?: string;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
platform?: string;
|
|
23
|
-
version?: string;
|
|
24
|
-
openLink?(url: string): void;
|
|
25
|
-
SecureStorage?: {
|
|
26
|
-
setItem(key: string, value: string, callback?: (error: string | null, isStored?: boolean) => void): void;
|
|
27
|
-
getItem(key: string, callback: (error: string | null, value?: string | null) => void): void;
|
|
28
|
-
removeItem?(key: string, callback?: (error: string | null, isRemoved?: boolean) => void): void;
|
|
29
|
-
};
|
|
30
|
-
BiometricManager?: {
|
|
31
|
-
isInited?: boolean;
|
|
32
|
-
isBiometricAvailable?: boolean;
|
|
33
|
-
isAccessRequested?: boolean;
|
|
34
|
-
isAccessGranted?: boolean;
|
|
35
|
-
isBiometricTokenSaved?: boolean;
|
|
36
|
-
init(callback?: () => void): void;
|
|
37
|
-
requestAccess?(params: {
|
|
38
|
-
reason?: string;
|
|
39
|
-
}, callback?: (isGranted: boolean) => void): void;
|
|
40
|
-
authenticate(params: {
|
|
41
|
-
reason?: string;
|
|
42
|
-
}, callback: (isAuthenticated: boolean, biometricToken?: string) => void): void;
|
|
43
|
-
updateBiometricToken(token: string, callback?: (isUpdated: boolean) => void): void;
|
|
44
|
-
openSettings?(): void;
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
export declare const EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL = "https://telegram.org/js/telegram-web-app.js";
|
|
48
|
-
export declare function getEosConnectTelegramWebApp(): EosConnectTelegramWebApp | null;
|
|
49
|
-
export declare function loadEosConnectTelegramWebAppSdk(doc?: Document | null | undefined): Promise<void>;
|
|
50
18
|
export interface EosConnectState {
|
|
51
19
|
status: EosConnectStatus;
|
|
52
20
|
provider: EosConnectProviderId | null;
|
|
@@ -102,9 +70,11 @@ export interface EosConnectOptions {
|
|
|
102
70
|
network?: EosConnectNetwork;
|
|
103
71
|
apiBaseUrl?: string;
|
|
104
72
|
botUsername?: string;
|
|
73
|
+
tokenPocketSource?: string;
|
|
105
74
|
deviceLabel?: string;
|
|
106
75
|
locale?: string;
|
|
107
76
|
messages?: EosConnectMessages;
|
|
77
|
+
defaultConnectOptions?: EosConnectTelegramOptions;
|
|
108
78
|
balanceAsset?: EosConnectBalanceAsset;
|
|
109
79
|
rpcUrls?: string | string[];
|
|
110
80
|
signTransaction?: EosConnectTransactionSigner;
|
|
@@ -127,15 +97,51 @@ export interface EosConnectTelegramOptions {
|
|
|
127
97
|
replaceWallet?: boolean;
|
|
128
98
|
openLink?: boolean;
|
|
129
99
|
}
|
|
100
|
+
export interface EosConnectWalletFlowOptions extends EosConnectTelegramOptions {
|
|
101
|
+
waitForReady?: boolean;
|
|
102
|
+
pollIntervalMs?: number;
|
|
103
|
+
timeoutMs?: number;
|
|
104
|
+
openExternal?: (url: string) => void;
|
|
105
|
+
}
|
|
106
|
+
export type EosConnectWalletViewStatus = 'setup' | 'pending' | 'ready' | 'unsupported' | 'error';
|
|
107
|
+
export type EosConnectWalletViewAction = 'start_wallet_flow' | 'open_bind_url' | 'pay' | 'none';
|
|
108
|
+
export interface EosConnectWalletViewPrimaryAction {
|
|
109
|
+
label: string;
|
|
110
|
+
action: EosConnectWalletViewAction;
|
|
111
|
+
disabled?: boolean;
|
|
112
|
+
}
|
|
113
|
+
export interface EosConnectWalletView {
|
|
114
|
+
status: EosConnectWalletViewStatus;
|
|
115
|
+
account: string | null;
|
|
116
|
+
balance: string | null;
|
|
117
|
+
canPay: boolean;
|
|
118
|
+
title: string;
|
|
119
|
+
description: string;
|
|
120
|
+
primaryAction: EosConnectWalletViewPrimaryAction;
|
|
121
|
+
bindUrl: string | null;
|
|
122
|
+
reason: string | null;
|
|
123
|
+
}
|
|
124
|
+
export interface EosConnectQuickPayStatus {
|
|
125
|
+
enabled: boolean;
|
|
126
|
+
account: string | null;
|
|
127
|
+
balance: string | null;
|
|
128
|
+
reason: string | null;
|
|
129
|
+
}
|
|
130
130
|
export interface EosConnectClient {
|
|
131
131
|
getProviders(): EosConnectProvider[];
|
|
132
132
|
getSnapshot(): EosConnectState;
|
|
133
133
|
subscribe(listener: (state: EosConnectState) => void): () => void;
|
|
134
|
+
bootstrapTelegram(): Promise<EosConnectTelegramPayStorageCheck>;
|
|
134
135
|
restore(): Promise<EosConnectState>;
|
|
136
|
+
refreshWallet(): Promise<EosConnectWalletView>;
|
|
135
137
|
checkWallet(): Promise<EosConnectWalletCapability>;
|
|
138
|
+
checkQuickPay(): Promise<EosConnectQuickPayStatus>;
|
|
139
|
+
getWalletView(): Promise<EosConnectWalletView>;
|
|
136
140
|
connect(options: EosConnectConnectOptions): Promise<EosConnectState>;
|
|
137
141
|
connectTelegram(options?: EosConnectTelegramOptions): Promise<EosConnectState>;
|
|
138
142
|
connectTokenPocket(options?: EosConnectTelegramOptions): Promise<EosConnectState>;
|
|
143
|
+
startTelegramWalletFlow(options?: EosConnectWalletFlowOptions): Promise<EosConnectWalletView>;
|
|
144
|
+
enableQuickPay(options?: EosConnectWalletFlowOptions): Promise<EosConnectQuickPayStatus>;
|
|
139
145
|
pay(options: EosConnectPayOptions): Promise<EosConnectPayResult>;
|
|
140
146
|
disconnect(): Promise<EosConnectState>;
|
|
141
147
|
}
|
|
@@ -169,18 +175,6 @@ export interface EosConnectPayResult {
|
|
|
169
175
|
ok: true;
|
|
170
176
|
txid: string;
|
|
171
177
|
}
|
|
172
|
-
export type EosConnectErrorCode = 'DAILY_LIMIT_EXCEEDED' | 'PER_TX_LIMIT_EXCEEDED' | 'TOTAL_BUDGET_EXCEEDED' | 'INSUFFICIENT_BALANCE' | 'RAM_INSUFFICIENT' | 'PAYMENT_PERMISSION_MISSING' | 'SIGNATURE_REJECTED' | 'SESSION_EXPIRED' | 'NETWORK_ERROR' | 'UNKNOWN_CHAIN_ERROR';
|
|
173
|
-
export declare class EosConnectError extends Error {
|
|
174
|
-
readonly code: EosConnectErrorCode;
|
|
175
|
-
readonly rawMessage: string;
|
|
176
|
-
readonly retryable: boolean;
|
|
177
|
-
constructor(code: EosConnectErrorCode, message: string, options?: {
|
|
178
|
-
rawMessage?: string;
|
|
179
|
-
retryable?: boolean;
|
|
180
|
-
cause?: unknown;
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
export declare function isEosConnectError(error: unknown): error is EosConnectError;
|
|
184
178
|
export interface EosConnectPaymentDetails {
|
|
185
179
|
intentId: string;
|
|
186
180
|
chainId: string;
|
|
@@ -194,6 +188,18 @@ export interface EosConnectPaymentDetails {
|
|
|
194
188
|
export type EosConnectSignedTransaction = SignedTransferPayload;
|
|
195
189
|
export type EosConnectPaymentConfirmer = (details: EosConnectPaymentDetails) => boolean | Promise<boolean>;
|
|
196
190
|
export interface EosConnectMessages {
|
|
191
|
+
walletSetupTitle?: string;
|
|
192
|
+
walletSetupDescription?: string;
|
|
193
|
+
walletReadyTitle?: string;
|
|
194
|
+
walletReadyDescription?: string;
|
|
195
|
+
walletPendingTitle?: string;
|
|
196
|
+
walletPendingDescription?: string;
|
|
197
|
+
walletUnsupportedTitle?: string;
|
|
198
|
+
walletUnsupportedDescription?: string;
|
|
199
|
+
walletErrorTitle?: string;
|
|
200
|
+
walletActionStart?: string;
|
|
201
|
+
walletActionContinue?: string;
|
|
202
|
+
walletActionPay?: string;
|
|
197
203
|
paymentConfirmTitle?: string;
|
|
198
204
|
paymentConfirmClose?: string;
|
|
199
205
|
paymentConfirmRecipient?: string;
|
|
@@ -227,8 +233,7 @@ export declare function checkEosConnectTelegramPayStorage(app: EosConnectTelegra
|
|
|
227
233
|
export declare function initEosConnectTelegramBiometricManager(app: EosConnectTelegramWebApp, timeoutMs?: number): Promise<boolean>;
|
|
228
234
|
export declare function openEosConnectTelegramBiometricSettings(app: EosConnectTelegramWebApp): Promise<EosConnectTelegramBiometricSettingsResult>;
|
|
229
235
|
export declare function eosConnectWalletSetupState(wallet: EosConnectWalletInfo, env?: EosConnectWalletSetupEnv): EosConnectWalletSetupState;
|
|
230
|
-
export declare function
|
|
231
|
-
export declare function tokenPocketDappUrl(url: string): string;
|
|
236
|
+
export declare function tokenPocketDappUrl(url: string, source?: string): string;
|
|
232
237
|
export declare function generateEosConnectPaymentKey(): Promise<{
|
|
233
238
|
privateKey: string;
|
|
234
239
|
publicKey: string;
|
package/dist/index.js
CHANGED
|
@@ -1,59 +1,9 @@
|
|
|
1
1
|
import { ABI, PrivateKey, Serializer, Transaction } from '@wharfkit/antelope';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
export function loadEosConnectTelegramWebAppSdk(doc = globalThis.document) {
|
|
9
|
-
if (getEosConnectTelegramWebApp()) {
|
|
10
|
-
return Promise.resolve();
|
|
11
|
-
}
|
|
12
|
-
if (telegramWebAppSdkLoadPromise) {
|
|
13
|
-
return telegramWebAppSdkLoadPromise;
|
|
14
|
-
}
|
|
15
|
-
if (!doc?.head) {
|
|
16
|
-
return Promise.reject(new Error('Document is not available to load Telegram WebApp SDK'));
|
|
17
|
-
}
|
|
18
|
-
telegramWebAppSdkLoadPromise = new Promise((resolve, reject) => {
|
|
19
|
-
const finish = () => resolve();
|
|
20
|
-
const fail = () => {
|
|
21
|
-
telegramWebAppSdkLoadPromise = null;
|
|
22
|
-
reject(new Error('Failed to load Telegram WebApp SDK'));
|
|
23
|
-
};
|
|
24
|
-
const existing = doc.querySelector(`script[src="${EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL}"]`);
|
|
25
|
-
if (existing) {
|
|
26
|
-
existing.addEventListener('load', finish, { once: true });
|
|
27
|
-
existing.addEventListener('error', fail, { once: true });
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const script = doc.createElement('script');
|
|
31
|
-
script.src = EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL;
|
|
32
|
-
script.async = true;
|
|
33
|
-
script.onload = finish;
|
|
34
|
-
script.onerror = fail;
|
|
35
|
-
doc.head.appendChild(script);
|
|
36
|
-
});
|
|
37
|
-
return telegramWebAppSdkLoadPromise;
|
|
38
|
-
}
|
|
39
|
-
export class EosConnectError extends Error {
|
|
40
|
-
code;
|
|
41
|
-
rawMessage;
|
|
42
|
-
retryable;
|
|
43
|
-
constructor(code, message, options = {}) {
|
|
44
|
-
super(message);
|
|
45
|
-
this.name = 'EosConnectError';
|
|
46
|
-
this.code = code;
|
|
47
|
-
this.rawMessage = options.rawMessage ?? message;
|
|
48
|
-
this.retryable = options.retryable ?? false;
|
|
49
|
-
if (options.cause !== undefined) {
|
|
50
|
-
this.cause = options.cause;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
export function isEosConnectError(error) {
|
|
55
|
-
return error instanceof EosConnectError;
|
|
56
|
-
}
|
|
2
|
+
import { normalizeHttpResponseError, parseResponseBody } from './http.js';
|
|
3
|
+
import { getEosConnectTelegramWebApp, loadEosConnectTelegramWebAppSdk } from './telegram-web-app.js';
|
|
4
|
+
export { EosConnectError, isEosConnectError, normalizeEosConnectError } from './errors.js';
|
|
5
|
+
import { normalizeEosConnectError } from './errors.js';
|
|
6
|
+
export { EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL, getEosConnectTelegramWebApp, loadEosConnectTelegramWebAppSdk } from './telegram-web-app.js';
|
|
57
7
|
const defaultWalletSetupEnv = {
|
|
58
8
|
hasTelegramSession: true,
|
|
59
9
|
canStorePayKey: true
|
|
@@ -437,117 +387,20 @@ function paymentDetailsFromBuiltTransfer(built) {
|
|
|
437
387
|
payments
|
|
438
388
|
};
|
|
439
389
|
}
|
|
440
|
-
export function normalizeEosConnectError(error) {
|
|
441
|
-
if (isEosConnectError(error)) {
|
|
442
|
-
return error;
|
|
443
|
-
}
|
|
444
|
-
const rawMessage = rawErrorMessage(error);
|
|
445
|
-
const normalized = rawMessage.toLowerCase();
|
|
446
|
-
if (normalized.includes('daily limit exceeded')) {
|
|
447
|
-
return new EosConnectError('DAILY_LIMIT_EXCEEDED', '今日支付额度已用完,请明天再试或提高每日额度。', {
|
|
448
|
-
rawMessage,
|
|
449
|
-
cause: error
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
if (normalized.includes('per-transfer limit exceeded') ||
|
|
453
|
-
normalized.includes('per transfer limit exceeded') ||
|
|
454
|
-
normalized.includes('per_tx_limit') ||
|
|
455
|
-
normalized.includes('single transfer limit')) {
|
|
456
|
-
return new EosConnectError('PER_TX_LIMIT_EXCEEDED', '本次支付超过单笔额度,请降低金额或提高单笔额度。', {
|
|
457
|
-
rawMessage,
|
|
458
|
-
cause: error
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
if (normalized.includes('total budget exceeded')) {
|
|
462
|
-
return new EosConnectError('TOTAL_BUDGET_EXCEEDED', '该权限的总预算已用完,请调整总预算后再试。', {
|
|
463
|
-
rawMessage,
|
|
464
|
-
cause: error
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
if (normalized.includes('overdrawn balance') ||
|
|
468
|
-
normalized.includes('insufficient balance') ||
|
|
469
|
-
normalized.includes('balance is insufficient')) {
|
|
470
|
-
return new EosConnectError('INSUFFICIENT_BALANCE', '余额不足,请充值后再试。', {
|
|
471
|
-
rawMessage,
|
|
472
|
-
cause: error
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
if (normalized.includes('ram usage') ||
|
|
476
|
-
normalized.includes('billed ram') ||
|
|
477
|
-
normalized.includes('insufficient ram') ||
|
|
478
|
-
normalized.includes('current ram usage limit')) {
|
|
479
|
-
return new EosConnectError('RAM_INSUFFICIENT', '账号 RAM 不足,请补充 RAM 后再试。', {
|
|
480
|
-
rawMessage,
|
|
481
|
-
cause: error
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
if (normalized.includes('bot permission is inactive') ||
|
|
485
|
-
normalized.includes('permission does not match bot authorization') ||
|
|
486
|
-
normalized.includes('paylimit code authority is missing') ||
|
|
487
|
-
normalized.includes('missing from transfer permission') ||
|
|
488
|
-
normalized.includes('transaction declares authority') ||
|
|
489
|
-
normalized.includes('missing authority')) {
|
|
490
|
-
return new EosConnectError('PAYMENT_PERMISSION_MISSING', '快捷支付权限未绑定或已失效,请重新绑定后再试。', {
|
|
491
|
-
rawMessage,
|
|
492
|
-
cause: error
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
if (normalized.includes('not signed in') ||
|
|
496
|
-
normalized.includes('invalid session') ||
|
|
497
|
-
normalized.includes('session user not found') ||
|
|
498
|
-
normalized.includes('telegram initdata is missing') ||
|
|
499
|
-
normalized.includes('telegram session not found')) {
|
|
500
|
-
return new EosConnectError('SESSION_EXPIRED', '登录状态已失效,请重新打开小程序或重新登录。', {
|
|
501
|
-
rawMessage,
|
|
502
|
-
cause: error
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
if (normalized.includes('notallowederror') ||
|
|
506
|
-
normalized.includes('aborterror') ||
|
|
507
|
-
normalized.includes('payment confirmation was cancelled') ||
|
|
508
|
-
normalized.includes('biometric authentication failed') ||
|
|
509
|
-
normalized.includes('user cancelled')) {
|
|
510
|
-
return new EosConnectError('SIGNATURE_REJECTED', '已取消签名确认,支付未提交。', {
|
|
511
|
-
rawMessage,
|
|
512
|
-
cause: error
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
if (normalized.includes('failed to fetch') ||
|
|
516
|
-
normalized.includes('network') ||
|
|
517
|
-
normalized.includes('all eos rpc nodes failed') ||
|
|
518
|
-
normalized.includes('eos rpc') ||
|
|
519
|
-
normalized.includes('timeout')) {
|
|
520
|
-
return new EosConnectError('NETWORK_ERROR', '网络连接失败,请稍后重试。', {
|
|
521
|
-
rawMessage,
|
|
522
|
-
retryable: true,
|
|
523
|
-
cause: error
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
return new EosConnectError('UNKNOWN_CHAIN_ERROR', '支付失败,请稍后重试或联系服务方。', {
|
|
527
|
-
rawMessage,
|
|
528
|
-
cause: error
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
function rawErrorMessage(error) {
|
|
532
|
-
if (error instanceof Error) {
|
|
533
|
-
return error.message;
|
|
534
|
-
}
|
|
535
|
-
if (typeof error === 'string') {
|
|
536
|
-
return error;
|
|
537
|
-
}
|
|
538
|
-
if (error && typeof error === 'object') {
|
|
539
|
-
const maybeError = error;
|
|
540
|
-
if (typeof maybeError.error === 'string') {
|
|
541
|
-
return maybeError.error;
|
|
542
|
-
}
|
|
543
|
-
if (typeof maybeError.message === 'string') {
|
|
544
|
-
return maybeError.message;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
return 'EOS Connect request failed';
|
|
548
|
-
}
|
|
549
390
|
const EOS_CONNECT_MESSAGES = {
|
|
550
391
|
en: {
|
|
392
|
+
walletSetupTitle: 'Enable quick payment',
|
|
393
|
+
walletSetupDescription: 'Complete one binding, then eligible payments can be confirmed quickly.',
|
|
394
|
+
walletReadyTitle: 'Wallet connected',
|
|
395
|
+
walletReadyDescription: 'Quick payment is enabled.',
|
|
396
|
+
walletPendingTitle: 'Continue wallet binding',
|
|
397
|
+
walletPendingDescription: 'Finish the security confirmation in the opened binding page.',
|
|
398
|
+
walletUnsupportedTitle: 'Open in Telegram mobile',
|
|
399
|
+
walletUnsupportedDescription: 'Telegram initData and secure storage are required.',
|
|
400
|
+
walletErrorTitle: 'Wallet unavailable',
|
|
401
|
+
walletActionStart: 'Enable quick payment',
|
|
402
|
+
walletActionContinue: 'Continue binding',
|
|
403
|
+
walletActionPay: 'Pay',
|
|
551
404
|
paymentConfirmTitle: 'Payment details',
|
|
552
405
|
paymentConfirmClose: 'Close',
|
|
553
406
|
paymentConfirmRecipient: 'Recipient',
|
|
@@ -557,6 +410,18 @@ const EOS_CONNECT_MESSAGES = {
|
|
|
557
410
|
emptyMemo: '-'
|
|
558
411
|
},
|
|
559
412
|
'zh-CN': {
|
|
413
|
+
walletSetupTitle: '开启快捷支付',
|
|
414
|
+
walletSetupDescription: '完成一次绑定,符合额度的支付可快速确认',
|
|
415
|
+
walletReadyTitle: '钱包已连接',
|
|
416
|
+
walletReadyDescription: '快捷支付已开启',
|
|
417
|
+
walletPendingTitle: '继续完成绑定',
|
|
418
|
+
walletPendingDescription: '请在打开的页面完成安全绑定。',
|
|
419
|
+
walletUnsupportedTitle: '请在 Telegram 手机端打开',
|
|
420
|
+
walletUnsupportedDescription: '需要 Telegram initData 和安全存储能力。',
|
|
421
|
+
walletErrorTitle: '钱包暂不可用',
|
|
422
|
+
walletActionStart: '开启快捷支付',
|
|
423
|
+
walletActionContinue: '继续绑定',
|
|
424
|
+
walletActionPay: '去支付',
|
|
560
425
|
paymentConfirmTitle: '交易详情',
|
|
561
426
|
paymentConfirmClose: '关闭',
|
|
562
427
|
paymentConfirmRecipient: '收款地址',
|
|
@@ -696,8 +561,9 @@ function ensurePaymentConfirmStyle(documentRef) {
|
|
|
696
561
|
}
|
|
697
562
|
function defaultConfirmPayment(details, options) {
|
|
698
563
|
const documentRef = globalThis.document;
|
|
699
|
-
if (!documentRef?.body)
|
|
700
|
-
return Promise.
|
|
564
|
+
if (!documentRef?.body) {
|
|
565
|
+
return Promise.reject(new Error('Payment confirmation UI is not available. Pass confirmPayment: false to skip it explicitly.'));
|
|
566
|
+
}
|
|
701
567
|
ensurePaymentConfirmStyle(documentRef);
|
|
702
568
|
const message = (key) => eosConnectMessage(key, options.locale, options.messages);
|
|
703
569
|
const backdrop = documentRef.createElement('div');
|
|
@@ -775,11 +641,11 @@ function parseRpcUrls(raw) {
|
|
|
775
641
|
}
|
|
776
642
|
return urls;
|
|
777
643
|
}
|
|
778
|
-
export function tokenPocketDappUrl(url) {
|
|
644
|
+
export function tokenPocketDappUrl(url, source = 'eosconnect') {
|
|
779
645
|
return `tpdapp://open?params=${encodeURIComponent(JSON.stringify({
|
|
780
646
|
url,
|
|
781
647
|
chain: 'EOS',
|
|
782
|
-
source
|
|
648
|
+
source
|
|
783
649
|
}))}`;
|
|
784
650
|
}
|
|
785
651
|
export async function generateEosConnectPaymentKey() {
|
|
@@ -812,11 +678,17 @@ function randomBase64Url(byteLength) {
|
|
|
812
678
|
return base64UrlEncode(bytes);
|
|
813
679
|
}
|
|
814
680
|
function requireSecureTelegramStorage(app) {
|
|
815
|
-
if (!app?.SecureStorage || !app.BiometricManager
|
|
681
|
+
if (!app?.SecureStorage || !app.BiometricManager) {
|
|
816
682
|
throw new Error(TELEGRAM_MOBILE_REQUIRED);
|
|
817
683
|
}
|
|
818
684
|
return app;
|
|
819
685
|
}
|
|
686
|
+
function requireTelegramMethod(method, name) {
|
|
687
|
+
if (typeof method !== 'function') {
|
|
688
|
+
throw new Error(`Telegram ${name} is not available`);
|
|
689
|
+
}
|
|
690
|
+
return method;
|
|
691
|
+
}
|
|
820
692
|
async function importUnlockKey(unlockKey) {
|
|
821
693
|
return crypto.subtle.importKey('raw', arrayBuffer(base64UrlDecode(unlockKey)), { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);
|
|
822
694
|
}
|
|
@@ -842,9 +714,12 @@ async function decryptPrivateKey(envelope, unlockKey) {
|
|
|
842
714
|
}
|
|
843
715
|
async function ensureBiometricAccess(app) {
|
|
844
716
|
const biometric = app.BiometricManager;
|
|
845
|
-
if (!biometric
|
|
717
|
+
if (!biometric) {
|
|
846
718
|
throw new Error(TELEGRAM_MOBILE_REQUIRED);
|
|
847
719
|
}
|
|
720
|
+
requireTelegramMethod(biometric?.init, 'BiometricManager.init');
|
|
721
|
+
requireTelegramMethod(biometric?.authenticate, 'BiometricManager.authenticate');
|
|
722
|
+
requireTelegramMethod(biometric?.updateBiometricToken, 'BiometricManager.updateBiometricToken');
|
|
848
723
|
if (!biometric.isInited) {
|
|
849
724
|
await new Promise((resolve) => biometric.init(resolve));
|
|
850
725
|
}
|
|
@@ -864,8 +739,9 @@ async function ensureBiometricAccess(app) {
|
|
|
864
739
|
}
|
|
865
740
|
}
|
|
866
741
|
function secureStorageSet(app, key, value) {
|
|
742
|
+
const setItem = requireTelegramMethod(app.SecureStorage?.setItem, 'SecureStorage.setItem');
|
|
867
743
|
return new Promise((resolve, reject) => {
|
|
868
|
-
app.SecureStorage
|
|
744
|
+
setItem.call(app.SecureStorage, key, value, (error, isStored) => {
|
|
869
745
|
if (error) {
|
|
870
746
|
reject(new Error(error));
|
|
871
747
|
return;
|
|
@@ -879,8 +755,9 @@ function secureStorageSet(app, key, value) {
|
|
|
879
755
|
});
|
|
880
756
|
}
|
|
881
757
|
function secureStorageGet(app, key) {
|
|
758
|
+
const getItem = requireTelegramMethod(app.SecureStorage?.getItem, 'SecureStorage.getItem');
|
|
882
759
|
return new Promise((resolve, reject) => {
|
|
883
|
-
app.SecureStorage
|
|
760
|
+
getItem.call(app.SecureStorage, key, (error, value) => {
|
|
884
761
|
if (error) {
|
|
885
762
|
reject(new Error(error));
|
|
886
763
|
return;
|
|
@@ -890,8 +767,9 @@ function secureStorageGet(app, key) {
|
|
|
890
767
|
});
|
|
891
768
|
}
|
|
892
769
|
function updateBiometricToken(app, token) {
|
|
770
|
+
const update = requireTelegramMethod(app.BiometricManager?.updateBiometricToken, 'BiometricManager.updateBiometricToken');
|
|
893
771
|
return new Promise((resolve, reject) => {
|
|
894
|
-
app.BiometricManager
|
|
772
|
+
update.call(app.BiometricManager, token, (isUpdated) => {
|
|
895
773
|
if (isUpdated) {
|
|
896
774
|
resolve();
|
|
897
775
|
}
|
|
@@ -902,8 +780,9 @@ function updateBiometricToken(app, token) {
|
|
|
902
780
|
});
|
|
903
781
|
}
|
|
904
782
|
function authenticateForUnlock(app) {
|
|
783
|
+
const authenticate = requireTelegramMethod(app.BiometricManager?.authenticate, 'BiometricManager.authenticate');
|
|
905
784
|
return new Promise((resolve, reject) => {
|
|
906
|
-
app.BiometricManager
|
|
785
|
+
authenticate.call(app.BiometricManager, { reason: 'Unlock EOS signing key' }, (isAuthenticated, biometricToken) => {
|
|
907
786
|
if (!isAuthenticated) {
|
|
908
787
|
reject(new Error('Biometric authentication failed'));
|
|
909
788
|
return;
|
|
@@ -932,7 +811,8 @@ function secureStorageRemove(app, key) {
|
|
|
932
811
|
});
|
|
933
812
|
return;
|
|
934
813
|
}
|
|
935
|
-
app.SecureStorage?.setItem
|
|
814
|
+
const setItem = requireTelegramMethod(app.SecureStorage?.setItem, 'SecureStorage.setItem');
|
|
815
|
+
setItem.call(app.SecureStorage, key, '', (error, isStored) => {
|
|
936
816
|
if (error) {
|
|
937
817
|
reject(new Error(error));
|
|
938
818
|
return;
|
|
@@ -953,7 +833,13 @@ export async function saveEosConnectPaymentKey(privateKey, app) {
|
|
|
953
833
|
envelope.publicKey = await publicKeyFromEosPrivateKey(privateKey);
|
|
954
834
|
envelope.createdAt = new Date().toISOString();
|
|
955
835
|
await secureStorageSet(telegram, EOS_CONNECT_PRIVATE_KEY_STORAGE, JSON.stringify(envelope));
|
|
956
|
-
|
|
836
|
+
try {
|
|
837
|
+
await updateBiometricToken(telegram, unlockKey);
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
await secureStorageRemove(telegram, EOS_CONNECT_PRIVATE_KEY_STORAGE).catch(() => undefined);
|
|
841
|
+
throw error;
|
|
842
|
+
}
|
|
957
843
|
}
|
|
958
844
|
export async function loadEosConnectStoredPublicKey(app) {
|
|
959
845
|
if (!app?.SecureStorage) {
|
|
@@ -1251,6 +1137,146 @@ function notConnectedWalletCapability(reason = null) {
|
|
|
1251
1137
|
wallet: null
|
|
1252
1138
|
};
|
|
1253
1139
|
}
|
|
1140
|
+
function pendingWalletCapabilityFromState(state) {
|
|
1141
|
+
return {
|
|
1142
|
+
status: 'pending',
|
|
1143
|
+
hasWallet: Boolean(state.hasWallet),
|
|
1144
|
+
canUse: false,
|
|
1145
|
+
needsLocalKey: false,
|
|
1146
|
+
account: state.account,
|
|
1147
|
+
balance: state.balance,
|
|
1148
|
+
bindId: state.bindId,
|
|
1149
|
+
bindUrl: state.bindUrl,
|
|
1150
|
+
expectedPublicKey: null,
|
|
1151
|
+
localPublicKey: null,
|
|
1152
|
+
reason: state.error,
|
|
1153
|
+
wallet: null
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
function walletViewFromCapability(capability, message) {
|
|
1157
|
+
if (capability.status === 'ready') {
|
|
1158
|
+
return {
|
|
1159
|
+
status: 'ready',
|
|
1160
|
+
account: capability.account,
|
|
1161
|
+
balance: capability.balance,
|
|
1162
|
+
canPay: true,
|
|
1163
|
+
title: message('walletReadyTitle'),
|
|
1164
|
+
description: message('walletReadyDescription'),
|
|
1165
|
+
primaryAction: {
|
|
1166
|
+
label: message('walletActionPay'),
|
|
1167
|
+
action: 'pay'
|
|
1168
|
+
},
|
|
1169
|
+
bindUrl: null,
|
|
1170
|
+
reason: null
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
if (capability.status === 'pending') {
|
|
1174
|
+
return {
|
|
1175
|
+
status: 'pending',
|
|
1176
|
+
account: capability.account,
|
|
1177
|
+
balance: capability.balance,
|
|
1178
|
+
canPay: false,
|
|
1179
|
+
title: message('walletPendingTitle'),
|
|
1180
|
+
description: capability.reason ?? message('walletPendingDescription'),
|
|
1181
|
+
primaryAction: {
|
|
1182
|
+
label: message('walletActionContinue'),
|
|
1183
|
+
action: capability.bindUrl ? 'open_bind_url' : 'none',
|
|
1184
|
+
disabled: !capability.bindUrl
|
|
1185
|
+
},
|
|
1186
|
+
bindUrl: capability.bindUrl,
|
|
1187
|
+
reason: capability.reason
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
if (capability.status === 'unsupported') {
|
|
1191
|
+
return {
|
|
1192
|
+
status: 'unsupported',
|
|
1193
|
+
account: null,
|
|
1194
|
+
balance: capability.balance,
|
|
1195
|
+
canPay: false,
|
|
1196
|
+
title: message('walletUnsupportedTitle'),
|
|
1197
|
+
description: capability.reason ?? message('walletUnsupportedDescription'),
|
|
1198
|
+
primaryAction: {
|
|
1199
|
+
label: message('walletActionStart'),
|
|
1200
|
+
action: 'none',
|
|
1201
|
+
disabled: true
|
|
1202
|
+
},
|
|
1203
|
+
bindUrl: null,
|
|
1204
|
+
reason: capability.reason
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
return {
|
|
1208
|
+
status: 'setup',
|
|
1209
|
+
account: capability.account,
|
|
1210
|
+
balance: capability.balance,
|
|
1211
|
+
canPay: false,
|
|
1212
|
+
title: message('walletSetupTitle'),
|
|
1213
|
+
description: message('walletSetupDescription'),
|
|
1214
|
+
primaryAction: {
|
|
1215
|
+
label: message('walletActionStart'),
|
|
1216
|
+
action: 'start_wallet_flow'
|
|
1217
|
+
},
|
|
1218
|
+
bindUrl: capability.bindUrl,
|
|
1219
|
+
reason: capability.reason
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
function walletViewFromError(error, message) {
|
|
1223
|
+
return {
|
|
1224
|
+
status: 'error',
|
|
1225
|
+
account: null,
|
|
1226
|
+
balance: null,
|
|
1227
|
+
canPay: false,
|
|
1228
|
+
title: message('walletErrorTitle'),
|
|
1229
|
+
description: error.message,
|
|
1230
|
+
primaryAction: {
|
|
1231
|
+
label: message('walletActionStart'),
|
|
1232
|
+
action: 'start_wallet_flow'
|
|
1233
|
+
},
|
|
1234
|
+
bindUrl: null,
|
|
1235
|
+
reason: error.rawMessage
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
function quickPayFromCapability(capability) {
|
|
1239
|
+
return {
|
|
1240
|
+
enabled: capability.status === 'ready' && capability.canUse,
|
|
1241
|
+
account: capability.account,
|
|
1242
|
+
balance: capability.balance,
|
|
1243
|
+
reason: capability.status === 'ready' && capability.canUse ? null : capability.reason
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
function quickPayFromView(view) {
|
|
1247
|
+
return {
|
|
1248
|
+
enabled: view.canPay,
|
|
1249
|
+
account: view.account,
|
|
1250
|
+
balance: view.balance,
|
|
1251
|
+
reason: view.canPay ? null : view.reason ?? view.description
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
function quickPayFromError(error) {
|
|
1255
|
+
return {
|
|
1256
|
+
enabled: false,
|
|
1257
|
+
account: null,
|
|
1258
|
+
balance: null,
|
|
1259
|
+
reason: error.message
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
function mergeTelegramConnectOptions(defaults, overrides) {
|
|
1263
|
+
return {
|
|
1264
|
+
botUsername: overrides?.botUsername ?? defaults?.botUsername,
|
|
1265
|
+
assetLimits: overrides?.assetLimits ?? defaults?.assetLimits,
|
|
1266
|
+
replaceWallet: overrides?.replaceWallet ?? defaults?.replaceWallet,
|
|
1267
|
+
openLink: overrides?.openLink ?? defaults?.openLink
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
function delay(ms) {
|
|
1271
|
+
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
1272
|
+
}
|
|
1273
|
+
function openFlowUrl(url, clientOptions, flowOptions, telegramWebApp) {
|
|
1274
|
+
if (flowOptions.openExternal) {
|
|
1275
|
+
flowOptions.openExternal(url);
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
openExternalUrl(url, clientOptions, telegramWebApp);
|
|
1279
|
+
}
|
|
1254
1280
|
export function createEosConnect(options) {
|
|
1255
1281
|
const fetchImpl = options.fetch ?? fetch;
|
|
1256
1282
|
const networkConfig = options.network ? EOS_CONNECT_NETWORKS[options.network] : null;
|
|
@@ -1270,6 +1296,9 @@ export function createEosConnect(options) {
|
|
|
1270
1296
|
function initData() {
|
|
1271
1297
|
return telegramWebApp()?.initData ?? '';
|
|
1272
1298
|
}
|
|
1299
|
+
function message(key) {
|
|
1300
|
+
return eosConnectMessage(key, resolveEosConnectLocale(options.locale, telegramWebApp()), options.messages);
|
|
1301
|
+
}
|
|
1273
1302
|
function botUsernameHeader() {
|
|
1274
1303
|
return options.botUsername ? { 'x-telegram-bot-username': options.botUsername } : {};
|
|
1275
1304
|
}
|
|
@@ -1288,9 +1317,15 @@ export function createEosConnect(options) {
|
|
|
1288
1317
|
catch (error) {
|
|
1289
1318
|
throw normalizeEosConnectError(error);
|
|
1290
1319
|
}
|
|
1291
|
-
|
|
1320
|
+
let body;
|
|
1321
|
+
try {
|
|
1322
|
+
body = await parseResponseBody(response);
|
|
1323
|
+
}
|
|
1324
|
+
catch (error) {
|
|
1325
|
+
throw normalizeEosConnectError(error);
|
|
1326
|
+
}
|
|
1292
1327
|
if (!response.ok) {
|
|
1293
|
-
throw
|
|
1328
|
+
throw normalizeHttpResponseError(response, body);
|
|
1294
1329
|
}
|
|
1295
1330
|
return body;
|
|
1296
1331
|
}
|
|
@@ -1305,6 +1340,31 @@ export function createEosConnect(options) {
|
|
|
1305
1340
|
listeners.add(listener);
|
|
1306
1341
|
return () => listeners.delete(listener);
|
|
1307
1342
|
},
|
|
1343
|
+
async bootstrapTelegram() {
|
|
1344
|
+
await loadEosConnectTelegramWebAppSdk().catch(() => undefined);
|
|
1345
|
+
const app = telegramWebApp();
|
|
1346
|
+
if (!app) {
|
|
1347
|
+
publish({
|
|
1348
|
+
...idleState,
|
|
1349
|
+
status: 'unsupported',
|
|
1350
|
+
error: 'Telegram WebApp is missing'
|
|
1351
|
+
});
|
|
1352
|
+
return {
|
|
1353
|
+
supported: false,
|
|
1354
|
+
biometricInitialized: false,
|
|
1355
|
+
diagnostics: eosConnectTelegramPayStorageDiagnostics({})
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
const check = await checkEosConnectTelegramPayStorage(app);
|
|
1359
|
+
if (!check.supported) {
|
|
1360
|
+
publish({
|
|
1361
|
+
...idleState,
|
|
1362
|
+
status: 'unsupported',
|
|
1363
|
+
error: TELEGRAM_MOBILE_REQUIRED
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
return check;
|
|
1367
|
+
},
|
|
1308
1368
|
async restore() {
|
|
1309
1369
|
if (!initData()) {
|
|
1310
1370
|
return publish({
|
|
@@ -1320,6 +1380,20 @@ export function createEosConnect(options) {
|
|
|
1320
1380
|
});
|
|
1321
1381
|
return publish(walletToState(wallet));
|
|
1322
1382
|
},
|
|
1383
|
+
async refreshWallet() {
|
|
1384
|
+
try {
|
|
1385
|
+
return walletViewFromCapability(await this.checkWallet(), message);
|
|
1386
|
+
}
|
|
1387
|
+
catch (error) {
|
|
1388
|
+
const normalized = normalizeEosConnectError(error);
|
|
1389
|
+
publish({
|
|
1390
|
+
...state,
|
|
1391
|
+
status: 'error',
|
|
1392
|
+
error: normalized.message
|
|
1393
|
+
});
|
|
1394
|
+
return walletViewFromError(normalized, message);
|
|
1395
|
+
}
|
|
1396
|
+
},
|
|
1323
1397
|
async checkWallet() {
|
|
1324
1398
|
if (!initData()) {
|
|
1325
1399
|
const capability = {
|
|
@@ -1354,6 +1428,23 @@ export function createEosConnect(options) {
|
|
|
1354
1428
|
publish(walletCapabilityToState(capability));
|
|
1355
1429
|
return capability;
|
|
1356
1430
|
},
|
|
1431
|
+
async checkQuickPay() {
|
|
1432
|
+
try {
|
|
1433
|
+
return quickPayFromCapability(await this.checkWallet());
|
|
1434
|
+
}
|
|
1435
|
+
catch (error) {
|
|
1436
|
+
const normalized = normalizeEosConnectError(error);
|
|
1437
|
+
publish({
|
|
1438
|
+
...state,
|
|
1439
|
+
status: 'error',
|
|
1440
|
+
error: normalized.message
|
|
1441
|
+
});
|
|
1442
|
+
return quickPayFromError(normalized);
|
|
1443
|
+
}
|
|
1444
|
+
},
|
|
1445
|
+
async getWalletView() {
|
|
1446
|
+
return this.refreshWallet();
|
|
1447
|
+
},
|
|
1357
1448
|
async connect(connectOptions) {
|
|
1358
1449
|
if (connectOptions.provider !== 'telegram' && connectOptions.provider !== 'tokenpocket') {
|
|
1359
1450
|
throw new Error(`${providerDisplayName(connectOptions.provider)} is not supported yet`);
|
|
@@ -1409,18 +1500,21 @@ export function createEosConnect(options) {
|
|
|
1409
1500
|
error: null
|
|
1410
1501
|
});
|
|
1411
1502
|
if (connectOptions.openLink !== false) {
|
|
1412
|
-
openExternalUrl(connectOptions.provider === 'tokenpocket'
|
|
1503
|
+
openExternalUrl(connectOptions.provider === 'tokenpocket'
|
|
1504
|
+
? tokenPocketDappUrl(bind.bindUrl, options.tokenPocketSource)
|
|
1505
|
+
: bind.bindUrl, options, telegramWebApp());
|
|
1413
1506
|
}
|
|
1414
1507
|
return next;
|
|
1415
1508
|
},
|
|
1416
1509
|
async connectTelegram(telegramOptions = {}) {
|
|
1510
|
+
const resolvedTelegramOptions = mergeTelegramConnectOptions(options.defaultConnectOptions, telegramOptions);
|
|
1417
1511
|
const paymentKey = await generateEosConnectPaymentKey();
|
|
1418
1512
|
const next = await this.connect({
|
|
1419
1513
|
provider: 'telegram',
|
|
1420
1514
|
publicKey: paymentKey.publicKey,
|
|
1421
|
-
botUsername:
|
|
1422
|
-
assetLimits:
|
|
1423
|
-
replaceWallet:
|
|
1515
|
+
botUsername: resolvedTelegramOptions.botUsername,
|
|
1516
|
+
assetLimits: resolvedTelegramOptions.assetLimits,
|
|
1517
|
+
replaceWallet: resolvedTelegramOptions.replaceWallet,
|
|
1424
1518
|
openLink: false
|
|
1425
1519
|
});
|
|
1426
1520
|
if (next.hasWallet) {
|
|
@@ -1432,11 +1526,75 @@ export function createEosConnect(options) {
|
|
|
1432
1526
|
if (!next.reused) {
|
|
1433
1527
|
await saveEosConnectPaymentKey(paymentKey.privateKey, telegramWebApp());
|
|
1434
1528
|
}
|
|
1435
|
-
if (
|
|
1529
|
+
if (resolvedTelegramOptions.openLink !== false) {
|
|
1436
1530
|
openExternalUrl(next.bindUrl, options, telegramWebApp());
|
|
1437
1531
|
}
|
|
1438
1532
|
return next;
|
|
1439
1533
|
},
|
|
1534
|
+
async startTelegramWalletFlow(flowOptions = {}) {
|
|
1535
|
+
try {
|
|
1536
|
+
const storage = await this.bootstrapTelegram();
|
|
1537
|
+
if (!storage.supported) {
|
|
1538
|
+
return walletViewFromCapability({
|
|
1539
|
+
...notConnectedWalletCapability(state.error ?? TELEGRAM_MOBILE_REQUIRED),
|
|
1540
|
+
status: 'unsupported'
|
|
1541
|
+
}, message);
|
|
1542
|
+
}
|
|
1543
|
+
const resolvedTelegramOptions = mergeTelegramConnectOptions(options.defaultConnectOptions, flowOptions);
|
|
1544
|
+
let capability = await this.checkWallet();
|
|
1545
|
+
let openedView = null;
|
|
1546
|
+
if (capability.status === 'ready' || capability.status === 'unsupported') {
|
|
1547
|
+
return walletViewFromCapability(capability, message);
|
|
1548
|
+
}
|
|
1549
|
+
if (capability.status === 'pending') {
|
|
1550
|
+
if (capability.bindUrl && resolvedTelegramOptions.openLink !== false) {
|
|
1551
|
+
openFlowUrl(capability.bindUrl, options, flowOptions, telegramWebApp());
|
|
1552
|
+
}
|
|
1553
|
+
openedView = walletViewFromCapability(capability, message);
|
|
1554
|
+
}
|
|
1555
|
+
else {
|
|
1556
|
+
const next = await this.connectTelegram({
|
|
1557
|
+
...resolvedTelegramOptions,
|
|
1558
|
+
replaceWallet: capability.needsLocalKey ? true : resolvedTelegramOptions.replaceWallet,
|
|
1559
|
+
openLink: flowOptions.openExternal ? false : resolvedTelegramOptions.openLink
|
|
1560
|
+
});
|
|
1561
|
+
if (next.status === 'pending') {
|
|
1562
|
+
if (next.bindUrl && flowOptions.openExternal) {
|
|
1563
|
+
flowOptions.openExternal(next.bindUrl);
|
|
1564
|
+
}
|
|
1565
|
+
openedView = walletViewFromCapability(pendingWalletCapabilityFromState(next), message);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
if (flowOptions.waitForReady === false) {
|
|
1569
|
+
return openedView ?? this.refreshWallet();
|
|
1570
|
+
}
|
|
1571
|
+
const timeoutMs = flowOptions.timeoutMs ?? 120000;
|
|
1572
|
+
const pollIntervalMs = flowOptions.pollIntervalMs ?? 1500;
|
|
1573
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
1574
|
+
do {
|
|
1575
|
+
capability = await this.checkWallet();
|
|
1576
|
+
if (capability.status !== 'pending') {
|
|
1577
|
+
return walletViewFromCapability(capability, message);
|
|
1578
|
+
}
|
|
1579
|
+
if (Date.now() >= deadline) {
|
|
1580
|
+
return walletViewFromCapability(capability, message);
|
|
1581
|
+
}
|
|
1582
|
+
await delay(pollIntervalMs);
|
|
1583
|
+
} while (true);
|
|
1584
|
+
}
|
|
1585
|
+
catch (error) {
|
|
1586
|
+
const normalized = normalizeEosConnectError(error);
|
|
1587
|
+
publish({
|
|
1588
|
+
...state,
|
|
1589
|
+
status: 'error',
|
|
1590
|
+
error: normalized.message
|
|
1591
|
+
});
|
|
1592
|
+
return walletViewFromError(normalized, message);
|
|
1593
|
+
}
|
|
1594
|
+
},
|
|
1595
|
+
async enableQuickPay(flowOptions = {}) {
|
|
1596
|
+
return quickPayFromView(await this.startTelegramWalletFlow(flowOptions));
|
|
1597
|
+
},
|
|
1440
1598
|
async connectTokenPocket(tokenPocketOptions = {}) {
|
|
1441
1599
|
const paymentKey = await generateEosConnectPaymentKey();
|
|
1442
1600
|
const next = await this.connect({
|
|
@@ -1450,7 +1608,7 @@ export function createEosConnect(options) {
|
|
|
1450
1608
|
}
|
|
1451
1609
|
await saveEosConnectPaymentKey(paymentKey.privateKey, telegramWebApp());
|
|
1452
1610
|
if (tokenPocketOptions.openLink !== false) {
|
|
1453
|
-
openExternalUrl(tokenPocketDappUrl(next.bindUrl), options, telegramWebApp());
|
|
1611
|
+
openExternalUrl(tokenPocketDappUrl(next.bindUrl, options.tokenPocketSource), options, telegramWebApp());
|
|
1454
1612
|
}
|
|
1455
1613
|
return next;
|
|
1456
1614
|
},
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface EosConnectTelegramWebApp {
|
|
2
|
+
initData?: string;
|
|
3
|
+
initDataUnsafe?: {
|
|
4
|
+
user?: {
|
|
5
|
+
language_code?: string;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
platform?: string;
|
|
9
|
+
version?: string;
|
|
10
|
+
openLink?(url: string): void;
|
|
11
|
+
SecureStorage?: {
|
|
12
|
+
setItem(key: string, value: string, callback?: (error: string | null, isStored?: boolean) => void): void;
|
|
13
|
+
getItem(key: string, callback: (error: string | null, value?: string | null) => void): void;
|
|
14
|
+
removeItem?(key: string, callback?: (error: string | null, isRemoved?: boolean) => void): void;
|
|
15
|
+
};
|
|
16
|
+
BiometricManager?: {
|
|
17
|
+
isInited?: boolean;
|
|
18
|
+
isBiometricAvailable?: boolean;
|
|
19
|
+
isAccessRequested?: boolean;
|
|
20
|
+
isAccessGranted?: boolean;
|
|
21
|
+
isBiometricTokenSaved?: boolean;
|
|
22
|
+
init(callback?: () => void): void;
|
|
23
|
+
requestAccess?(params: {
|
|
24
|
+
reason?: string;
|
|
25
|
+
}, callback?: (isGranted: boolean) => void): void;
|
|
26
|
+
authenticate(params: {
|
|
27
|
+
reason?: string;
|
|
28
|
+
}, callback: (isAuthenticated: boolean, biometricToken?: string) => void): void;
|
|
29
|
+
updateBiometricToken(token: string, callback?: (isUpdated: boolean) => void): void;
|
|
30
|
+
openSettings?(): void;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export declare const EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL = "https://telegram.org/js/telegram-web-app.js";
|
|
34
|
+
export declare function getEosConnectTelegramWebApp(): EosConnectTelegramWebApp | null;
|
|
35
|
+
export declare function loadEosConnectTelegramWebAppSdk(doc?: Document | null | undefined): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL = 'https://telegram.org/js/telegram-web-app.js';
|
|
2
|
+
let telegramWebAppSdkLoadPromise = null;
|
|
3
|
+
export function getEosConnectTelegramWebApp() {
|
|
4
|
+
const maybeGlobal = globalThis;
|
|
5
|
+
return maybeGlobal.window?.Telegram?.WebApp ?? maybeGlobal.Telegram?.WebApp ?? null;
|
|
6
|
+
}
|
|
7
|
+
export function loadEosConnectTelegramWebAppSdk(doc = globalThis.document) {
|
|
8
|
+
if (getEosConnectTelegramWebApp()) {
|
|
9
|
+
return Promise.resolve();
|
|
10
|
+
}
|
|
11
|
+
if (telegramWebAppSdkLoadPromise) {
|
|
12
|
+
return telegramWebAppSdkLoadPromise;
|
|
13
|
+
}
|
|
14
|
+
if (!doc?.head) {
|
|
15
|
+
return Promise.reject(new Error('Document is not available to load Telegram WebApp SDK'));
|
|
16
|
+
}
|
|
17
|
+
telegramWebAppSdkLoadPromise = new Promise((resolve, reject) => {
|
|
18
|
+
const finish = () => resolve();
|
|
19
|
+
const fail = () => {
|
|
20
|
+
telegramWebAppSdkLoadPromise = null;
|
|
21
|
+
reject(new Error('Failed to load Telegram WebApp SDK'));
|
|
22
|
+
};
|
|
23
|
+
const existing = doc.querySelector(`script[src="${EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL}"]`);
|
|
24
|
+
if (existing) {
|
|
25
|
+
existing.addEventListener('load', finish, { once: true });
|
|
26
|
+
existing.addEventListener('error', fail, { once: true });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const script = doc.createElement('script');
|
|
30
|
+
script.src = EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL;
|
|
31
|
+
script.async = true;
|
|
32
|
+
script.onload = finish;
|
|
33
|
+
script.onerror = fail;
|
|
34
|
+
doc.head.appendChild(script);
|
|
35
|
+
});
|
|
36
|
+
return telegramWebAppSdkLoadPromise;
|
|
37
|
+
}
|