@eos3/connect 0.1.0 → 0.1.1

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
@@ -15,20 +15,28 @@ npm install @eos3/connect
15
15
 
16
16
  The SDK expects a browser runtime with `fetch`, Web Crypto, and Telegram WebApp
17
17
  APIs when real wallet creation or payment signing is used.
18
+ It does not bundle Telegram's script into the main SDK bundle; call
19
+ `loadEosConnectTelegramWebAppSdk()` or include Telegram's official
20
+ `https://telegram.org/js/telegram-web-app.js` script before wallet flows.
18
21
 
19
22
  ## Minimal Setup
20
23
 
21
24
  ```ts
22
25
  import {
23
26
  createEosConnect,
27
+ getEosConnectTelegramWebApp,
24
28
  isEosConnectError,
29
+ loadEosConnectTelegramWebAppSdk,
25
30
  normalizeEosConnectError
26
31
  } from '@eos3/connect';
27
32
 
28
- const telegramWebApp = window.Telegram?.WebApp;
33
+ await loadEosConnectTelegramWebAppSdk().catch(() => undefined);
34
+ const telegramWebApp = getEosConnectTelegramWebApp();
29
35
 
30
36
  const eosConnect = createEosConnect({
31
37
  network: 'testnet',
38
+ apiBaseUrl: 'https://your-wallet-api.example.com',
39
+ botUsername: 'your_bot',
32
40
  telegramWebApp
33
41
  });
34
42
 
@@ -39,14 +47,13 @@ eosConnect.subscribe((state) => {
39
47
  await eosConnect.checkWallet();
40
48
  ```
41
49
 
42
- `network` can be `testnet` or `mainnet`. It selects the default API base URL,
43
- browser signing RPC failover list, chain id metadata, and balance asset. You can
44
- still override `apiBaseUrl`, `rpcUrls`, or `balanceAsset` when running your own
45
- deployment.
46
-
47
- For now, the testnet preset uses `https://eospasskey.aiexsat.com` as its hosted
48
- API. The mainnet preset keeps the same hosted API placeholder until a separate
49
- mainnet endpoint is assigned.
50
+ `network` can be `testnet` or `mainnet`. It selects browser signing RPC
51
+ failover list, chain id metadata, and balance asset. The SDK does not include a
52
+ hosted wallet API or a Telegram bot. If `apiBaseUrl` is omitted, requests use
53
+ same-origin paths such as `/api/tg-wallet/me`.
54
+ When `botUsername` is set, the SDK sends it as `x-telegram-bot-username` so a
55
+ shared backend can choose the correct Telegram bot token for `initData`
56
+ verification.
50
57
 
51
58
  ## Connect a Telegram Wallet
52
59
 
@@ -79,6 +86,19 @@ Do not fall back to `localStorage` for the private key. If Telegram
79
86
  SecureStorage or BiometricManager is missing, ask the user to open the Mini App
80
87
  in a supported Telegram mobile client.
81
88
 
89
+ Before showing a real connect action, prefer the async storage check. It calls
90
+ `BiometricManager.init()` before reading Telegram's capability flags:
91
+
92
+ ```ts
93
+ import { checkEosConnectTelegramPayStorage } from '@eos3/connect';
94
+
95
+ const storage = await checkEosConnectTelegramPayStorage(telegramWebApp);
96
+
97
+ if (!storage.supported) {
98
+ console.table(storage.diagnostics);
99
+ }
100
+ ```
101
+
82
102
  ## Check Readiness
83
103
 
84
104
  ```ts
@@ -178,6 +198,7 @@ await fetch('https://wallet.example.com/api/market/push', {
178
198
  - `client.subscribe(listener)`: subscribes to state changes.
179
199
  - `client.restore()`: loads wallet state from the API.
180
200
  - `client.checkWallet()`: checks server wallet plus local key readiness.
201
+ - `checkEosConnectTelegramPayStorage(app)`: initializes Telegram biometrics and returns secure storage diagnostics.
181
202
  - `client.connectTelegram(options)`: starts or resumes Telegram binding.
182
203
  - `client.connectTokenPocket(options)`: starts TokenPocket binding.
183
204
  - `client.pay(options)`: builds, signs, confirms, and pushes a paylimit payment.
@@ -194,10 +215,9 @@ console.log(EOS_CONNECT_NETWORKS.mainnet.chainId);
194
215
 
195
216
  Preset values:
196
217
 
197
- - `testnet`: Jungle4 chain id, Jungle4 RPC failover list, hosted testnet API
198
- `https://eospasskey.aiexsat.com`, and default asset `core.vaulta:A:4`.
199
- - `mainnet`: EOS mainnet chain id, mainnet RPC failover list, hosted API
200
- placeholder `https://eospasskey.aiexsat.com`, and default asset
218
+ - `testnet`: Jungle4 chain id, Jungle4 RPC failover list, and default asset
219
+ `core.vaulta:A:4`.
220
+ - `mainnet`: EOS mainnet chain id, mainnet RPC failover list, and default asset
201
221
  `core.vaulta:A:4`.
202
222
 
203
223
  Explicit options always win:
package/dist/index.d.ts CHANGED
@@ -39,6 +39,9 @@ export interface EosConnectTelegramWebApp {
39
39
  openSettings?(): void;
40
40
  };
41
41
  }
42
+ export declare const EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL = "https://telegram.org/js/telegram-web-app.js";
43
+ export declare function getEosConnectTelegramWebApp(): EosConnectTelegramWebApp | null;
44
+ export declare function loadEosConnectTelegramWebAppSdk(doc?: Document | null | undefined): Promise<void>;
42
45
  export interface EosConnectState {
43
46
  status: EosConnectStatus;
44
47
  provider: EosConnectProviderId | null;
@@ -86,7 +89,6 @@ export interface EosConnectWalletSetupState {
86
89
  export interface EosConnectNetworkConfig {
87
90
  id: EosConnectNetwork;
88
91
  name: string;
89
- apiBaseUrl: string;
90
92
  chainId: string;
91
93
  rpcUrls: readonly string[];
92
94
  balanceAsset: EosConnectBalanceAsset;
@@ -107,11 +109,13 @@ export interface EosConnectOptions {
107
109
  export interface EosConnectConnectOptions {
108
110
  provider: EosConnectProviderId;
109
111
  publicKey?: string;
112
+ botUsername?: string;
110
113
  assetLimits?: PayLimitAssetConfig[];
111
114
  replaceWallet?: boolean;
112
115
  openLink?: boolean;
113
116
  }
114
117
  export interface EosConnectTelegramOptions {
118
+ botUsername?: string;
115
119
  assetLimits?: PayLimitAssetConfig[];
116
120
  replaceWallet?: boolean;
117
121
  openLink?: boolean;
@@ -138,6 +142,11 @@ export interface EosConnectTelegramDeviceDiagnostic {
138
142
  ok: boolean;
139
143
  detail: string;
140
144
  }
145
+ export interface EosConnectTelegramPayStorageCheck {
146
+ supported: boolean;
147
+ biometricInitialized: boolean;
148
+ diagnostics: EosConnectTelegramDeviceDiagnostic[];
149
+ }
141
150
  export interface EosConnectTelegramBiometricSettingsResult {
142
151
  opened: boolean;
143
152
  message: string;
@@ -195,10 +204,10 @@ export interface EosConnectWalletInfo {
195
204
  botPermission?: string | null;
196
205
  }
197
206
  export declare const EOS_CONNECT_PRIVATE_KEY_STORAGE = "tg_eos_wallet_pay_key_v1";
198
- export declare const EOS_CONNECT_DEFAULT_API_BASE_URL = "https://eospasskey.aiexsat.com";
199
207
  export declare const EOS_CONNECT_NETWORKS: Record<EosConnectNetwork, EosConnectNetworkConfig>;
200
208
  export declare function eosConnectTelegramPayStorageDiagnostics(app: EosConnectTelegramWebApp): EosConnectTelegramDeviceDiagnostic[];
201
209
  export declare function supportsEosConnectTelegramPayStorage(app: EosConnectTelegramWebApp): boolean;
210
+ export declare function checkEosConnectTelegramPayStorage(app: EosConnectTelegramWebApp, timeoutMs?: number): Promise<EosConnectTelegramPayStorageCheck>;
202
211
  export declare function initEosConnectTelegramBiometricManager(app: EosConnectTelegramWebApp, timeoutMs?: number): Promise<boolean>;
203
212
  export declare function openEosConnectTelegramBiometricSettings(app: EosConnectTelegramWebApp): Promise<EosConnectTelegramBiometricSettingsResult>;
204
213
  export declare function eosConnectWalletSetupState(wallet: EosConnectWalletInfo, env?: EosConnectWalletSetupEnv): EosConnectWalletSetupState;
package/dist/index.js CHANGED
@@ -1,4 +1,41 @@
1
1
  import { ABI, PrivateKey, Serializer, Transaction } from '@wharfkit/antelope';
2
+ export const EOS_CONNECT_TELEGRAM_WEB_APP_SDK_URL = 'https://telegram.org/js/telegram-web-app.js';
3
+ let telegramWebAppSdkLoadPromise = null;
4
+ export function getEosConnectTelegramWebApp() {
5
+ const maybeGlobal = globalThis;
6
+ return maybeGlobal.window?.Telegram?.WebApp ?? maybeGlobal.Telegram?.WebApp ?? null;
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
+ }
2
39
  export class EosConnectError extends Error {
3
40
  code;
4
41
  rawMessage;
@@ -22,12 +59,10 @@ const defaultWalletSetupEnv = {
22
59
  canStorePayKey: true
23
60
  };
24
61
  export const EOS_CONNECT_PRIVATE_KEY_STORAGE = 'tg_eos_wallet_pay_key_v1';
25
- export const EOS_CONNECT_DEFAULT_API_BASE_URL = 'https://eospasskey.aiexsat.com';
26
62
  export const EOS_CONNECT_NETWORKS = {
27
63
  testnet: {
28
64
  id: 'testnet',
29
65
  name: 'Jungle4 Testnet',
30
- apiBaseUrl: 'https://eospasskey.aiexsat.com',
31
66
  chainId: '73e4385a2708e6d7048834fbc1079f2fabb17b3c125b146af438971e90716c4d',
32
67
  rpcUrls: [
33
68
  'https://jungle4.cryptolions.io:443',
@@ -46,7 +81,6 @@ export const EOS_CONNECT_NETWORKS = {
46
81
  mainnet: {
47
82
  id: 'mainnet',
48
83
  name: 'EOS Mainnet',
49
- apiBaseUrl: 'https://eospasskey.aiexsat.com',
50
84
  chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906',
51
85
  rpcUrls: [
52
86
  'https://eos.eoseyes.com',
@@ -183,6 +217,21 @@ export function eosConnectTelegramPayStorageDiagnostics(app) {
183
217
  export function supportsEosConnectTelegramPayStorage(app) {
184
218
  return eosConnectTelegramPayStorageDiagnostics(app).every((item) => item.ok);
185
219
  }
220
+ export async function checkEosConnectTelegramPayStorage(app, timeoutMs = 5000) {
221
+ let biometricInitialized = false;
222
+ try {
223
+ biometricInitialized = await initEosConnectTelegramBiometricManager(app, timeoutMs);
224
+ }
225
+ catch {
226
+ biometricInitialized = false;
227
+ }
228
+ const diagnostics = eosConnectTelegramPayStorageDiagnostics(app);
229
+ return {
230
+ supported: diagnostics.every((item) => item.ok),
231
+ biometricInitialized,
232
+ diagnostics
233
+ };
234
+ }
186
235
  export async function initEosConnectTelegramBiometricManager(app, timeoutMs = 5000) {
187
236
  const biometric = app.BiometricManager;
188
237
  if (typeof biometric?.init !== 'function') {
@@ -316,13 +365,13 @@ export function eosConnectWalletSetupState(wallet, env = defaultWalletSetupEnv)
316
365
  reason: wallet.bindingError ?? null
317
366
  };
318
367
  }
319
- function openExternalUrl(url, options) {
368
+ function openExternalUrl(url, options, telegramWebApp = options.telegramWebApp) {
320
369
  if (options.openExternal) {
321
370
  options.openExternal(url);
322
371
  return;
323
372
  }
324
- if (!url.startsWith('tpdapp://') && options.telegramWebApp?.openLink) {
325
- options.telegramWebApp.openLink(url);
373
+ if (!url.startsWith('tpdapp://') && telegramWebApp?.openLink) {
374
+ telegramWebApp.openLink(url);
326
375
  return;
327
376
  }
328
377
  globalThis.location?.assign(url);
@@ -1149,10 +1198,26 @@ function walletCapabilityToState(capability) {
1149
1198
  localPublicKey: capability.localPublicKey
1150
1199
  };
1151
1200
  }
1201
+ function notConnectedWalletCapability(reason = null) {
1202
+ return {
1203
+ status: 'not_connected',
1204
+ hasWallet: false,
1205
+ canUse: false,
1206
+ needsLocalKey: false,
1207
+ account: null,
1208
+ balance: null,
1209
+ bindId: null,
1210
+ bindUrl: null,
1211
+ expectedPublicKey: null,
1212
+ localPublicKey: null,
1213
+ reason,
1214
+ wallet: null
1215
+ };
1216
+ }
1152
1217
  export function createEosConnect(options) {
1153
1218
  const fetchImpl = options.fetch ?? fetch;
1154
1219
  const networkConfig = options.network ? EOS_CONNECT_NETWORKS[options.network] : null;
1155
- const apiBaseUrl = normalizeBaseUrl(options.apiBaseUrl ?? networkConfig?.apiBaseUrl ?? EOS_CONNECT_DEFAULT_API_BASE_URL);
1220
+ const apiBaseUrl = normalizeBaseUrl(options.apiBaseUrl ?? '');
1156
1221
  const balanceAsset = options.balanceAsset ?? networkConfig?.balanceAsset;
1157
1222
  const rpcUrls = parseRpcUrls(options.rpcUrls ?? networkConfig?.rpcUrls);
1158
1223
  const listeners = new Set();
@@ -1162,8 +1227,14 @@ export function createEosConnect(options) {
1162
1227
  listeners.forEach((listener) => listener(state));
1163
1228
  return state;
1164
1229
  }
1230
+ function telegramWebApp() {
1231
+ return options.telegramWebApp === undefined ? getEosConnectTelegramWebApp() : options.telegramWebApp;
1232
+ }
1165
1233
  function initData() {
1166
- return options.telegramWebApp?.initData ?? '';
1234
+ return telegramWebApp()?.initData ?? '';
1235
+ }
1236
+ function botUsernameHeader() {
1237
+ return options.botUsername ? { 'x-telegram-bot-username': options.botUsername } : {};
1167
1238
  }
1168
1239
  async function request(path, requestOptions) {
1169
1240
  let response;
@@ -1172,6 +1243,7 @@ export function createEosConnect(options) {
1172
1243
  ...requestOptions,
1173
1244
  headers: {
1174
1245
  'content-type': 'application/json',
1246
+ ...botUsernameHeader(),
1175
1247
  ...(requestOptions?.headers ?? {})
1176
1248
  }
1177
1249
  });
@@ -1214,29 +1286,32 @@ export function createEosConnect(options) {
1214
1286
  async checkWallet() {
1215
1287
  if (!initData()) {
1216
1288
  const capability = {
1217
- status: 'unsupported',
1218
- hasWallet: false,
1219
- canUse: false,
1220
- needsLocalKey: false,
1221
- account: null,
1222
- balance: null,
1223
- bindId: null,
1224
- bindUrl: null,
1225
- expectedPublicKey: null,
1226
- localPublicKey: null,
1227
- reason: 'Telegram initData is missing',
1228
- wallet: null
1289
+ ...notConnectedWalletCapability('Telegram initData is missing'),
1290
+ status: 'unsupported'
1229
1291
  };
1230
1292
  publish(walletCapabilityToState(capability));
1231
1293
  return capability;
1232
1294
  }
1233
- const wallet = await request(`/api/tg-wallet/me${balanceQuery(balanceAsset)}`, {
1234
- headers: {
1235
- 'x-telegram-init-data': initData()
1295
+ let wallet;
1296
+ try {
1297
+ wallet = await request(`/api/tg-wallet/me${balanceQuery(balanceAsset)}`, {
1298
+ headers: {
1299
+ 'x-telegram-init-data': initData()
1300
+ }
1301
+ });
1302
+ }
1303
+ catch (error) {
1304
+ const normalized = normalizeEosConnectError(error);
1305
+ if (normalized.code === 'SESSION_EXPIRED' &&
1306
+ normalized.rawMessage.toLowerCase().includes('telegram session not found')) {
1307
+ const capability = notConnectedWalletCapability();
1308
+ publish(walletCapabilityToState(capability));
1309
+ return capability;
1236
1310
  }
1237
- });
1311
+ throw normalized;
1312
+ }
1238
1313
  const localPublicKey = wallet.quickPublicKey
1239
- ? await loadEosConnectStoredPublicKey(options.telegramWebApp)
1314
+ ? await loadEosConnectStoredPublicKey(telegramWebApp())
1240
1315
  : null;
1241
1316
  const capability = walletCapability(wallet, localPublicKey);
1242
1317
  publish(walletCapabilityToState(capability));
@@ -1266,8 +1341,8 @@ export function createEosConnect(options) {
1266
1341
  initData: initData(),
1267
1342
  botPublicKey: connectOptions.provider === 'telegram' ? connectOptions.publicKey : undefined,
1268
1343
  tgpayPublicKey: connectOptions.provider === 'tokenpocket' ? connectOptions.publicKey : undefined,
1269
- botUsername: options.botUsername || undefined,
1270
- deviceLabel: options.deviceLabel || telegramDeviceLabel(options.telegramWebApp),
1344
+ botUsername: connectOptions.botUsername || options.botUsername || undefined,
1345
+ deviceLabel: options.deviceLabel || telegramDeviceLabel(telegramWebApp()),
1271
1346
  assetLimits: connectOptions.assetLimits,
1272
1347
  replaceWallet: connectOptions.provider === 'telegram' ? connectOptions.replaceWallet || undefined : undefined
1273
1348
  })
@@ -1297,7 +1372,7 @@ export function createEosConnect(options) {
1297
1372
  error: null
1298
1373
  });
1299
1374
  if (connectOptions.openLink !== false) {
1300
- openExternalUrl(connectOptions.provider === 'tokenpocket' ? tokenPocketDappUrl(bind.bindUrl) : bind.bindUrl, options);
1375
+ openExternalUrl(connectOptions.provider === 'tokenpocket' ? tokenPocketDappUrl(bind.bindUrl) : bind.bindUrl, options, telegramWebApp());
1301
1376
  }
1302
1377
  return next;
1303
1378
  },
@@ -1306,6 +1381,7 @@ export function createEosConnect(options) {
1306
1381
  const next = await this.connect({
1307
1382
  provider: 'telegram',
1308
1383
  publicKey: paymentKey.publicKey,
1384
+ botUsername: telegramOptions.botUsername,
1309
1385
  assetLimits: telegramOptions.assetLimits,
1310
1386
  replaceWallet: telegramOptions.replaceWallet,
1311
1387
  openLink: false
@@ -1317,10 +1393,10 @@ export function createEosConnect(options) {
1317
1393
  throw new Error('EOS Connect did not return a binding request');
1318
1394
  }
1319
1395
  if (!next.reused) {
1320
- await saveEosConnectPaymentKey(paymentKey.privateKey, options.telegramWebApp);
1396
+ await saveEosConnectPaymentKey(paymentKey.privateKey, telegramWebApp());
1321
1397
  }
1322
1398
  if (telegramOptions.openLink !== false) {
1323
- openExternalUrl(next.bindUrl, options);
1399
+ openExternalUrl(next.bindUrl, options, telegramWebApp());
1324
1400
  }
1325
1401
  return next;
1326
1402
  },
@@ -1335,9 +1411,9 @@ export function createEosConnect(options) {
1335
1411
  if (!next.bindUrl || !next.bindId) {
1336
1412
  throw new Error('EOS Connect did not return a TokenPocket binding request');
1337
1413
  }
1338
- await saveEosConnectPaymentKey(paymentKey.privateKey, options.telegramWebApp);
1414
+ await saveEosConnectPaymentKey(paymentKey.privateKey, telegramWebApp());
1339
1415
  if (tokenPocketOptions.openLink !== false) {
1340
- openExternalUrl(tokenPocketDappUrl(next.bindUrl), options);
1416
+ openExternalUrl(tokenPocketDappUrl(next.bindUrl), options, telegramWebApp());
1341
1417
  }
1342
1418
  return next;
1343
1419
  },
@@ -1365,7 +1441,7 @@ export function createEosConnect(options) {
1365
1441
  }
1366
1442
  const signer = options.signTransaction ?? signEosConnectTransaction;
1367
1443
  const signedTransaction = await signer(built.transaction, {
1368
- telegramWebApp: options.telegramWebApp,
1444
+ telegramWebApp: telegramWebApp(),
1369
1445
  rpcUrls,
1370
1446
  fetch: fetchImpl
1371
1447
  });
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@eos3/connect",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Framework-neutral browser SDK for EOS Passkey Connect in Telegram Mini Apps.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/HuangLittleOrange/eos3app.git",
10
+ "directory": "packages/connect"
11
+ },
7
12
  "main": "dist/index.js",
8
13
  "types": "dist/index.d.ts",
9
14
  "files": [
@@ -26,8 +31,10 @@
26
31
  }
27
32
  },
28
33
  "scripts": {
34
+ "prebuild": "npm run build -w @eos3/shared",
29
35
  "build": "tsc -p tsconfig.json",
30
36
  "test": "vitest run",
37
+ "pretypecheck": "npm run build -w @eos3/shared",
31
38
  "typecheck": "tsc -p tsconfig.json --noEmit"
32
39
  },
33
40
  "dependencies": {