hm-tracking-sdk 0.2.2 → 0.2.3

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.
@@ -36,22 +36,34 @@ export function isTelegramEnv() {
36
36
  if (!tg.initDataUnsafe || typeof tg.initDataUnsafe !== "object") {
37
37
  return false;
38
38
  }
39
- // 3. 进一步验证:检查 initDataUnsafe.user 或 initData 属性
40
- // 这两个属性在真实的 Telegram 环境中应该存在
41
- const hasUser = tg.initDataUnsafe.user && typeof tg.initDataUnsafe.user === "object";
42
- const hasInitData = 'initData' in tg;
43
- if (hasUser || hasInitData) {
44
- // 如果 platform 存在且是明显无效的值,可能是手动注入的对象
45
- const platform = tg.platform;
46
- if (platform !== undefined && platform !== null && typeof platform === "string") {
47
- const invalidPlatforms = ['fake', 'mock', 'test'];
48
- if (invalidPlatforms.includes(platform.toLowerCase())) {
49
- return false;
50
- }
39
+ // 3. 严格验证:必须同时满足以下条件才认为是真实的 Telegram 环境
40
+ // - initDataUnsafe.user 必须存在且是对象,且必须有有效的 id
41
+ // - 或者 initData 必须存在且是有效的字符串(非空)
42
+ const hasValidUser = tg.initDataUnsafe.user &&
43
+ typeof tg.initDataUnsafe.user === "object" &&
44
+ typeof tg.initDataUnsafe.user.id === "number" &&
45
+ tg.initDataUnsafe.user.id > 0;
46
+ const hasValidInitData = 'initData' in tg &&
47
+ typeof tg.initData === "string" &&
48
+ tg.initData.length > 0;
49
+ // 必须至少有一个有效标识
50
+ if (!hasValidUser && !hasValidInitData) {
51
+ return false;
52
+ }
53
+ // 4. 如果 platform 存在且是明显无效的值,可能是手动注入的对象
54
+ const platform = tg.platform;
55
+ if (platform !== undefined && platform !== null && typeof platform === "string") {
56
+ const invalidPlatforms = ['fake', 'mock', 'test'];
57
+ if (invalidPlatforms.includes(platform.toLowerCase())) {
58
+ return false;
51
59
  }
52
- return true;
53
60
  }
54
- return false;
61
+ // 5. 额外检查:如果 initDataUnsafe 是空对象且没有其他有效标识,可能是 mock 对象
62
+ const initDataUnsafeKeys = Object.keys(tg.initDataUnsafe || {});
63
+ if (initDataUnsafeKeys.length === 0 && !hasValidInitData) {
64
+ return false;
65
+ }
66
+ return true;
55
67
  }
56
68
  catch (error) {
57
69
  console.warn("环境检测异常", error);
@@ -1 +1 @@
1
- {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/sdk/telegram.ts"],"names":[],"mappings":"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","sourcesContent":["import WebApp from \"@twa-dev/sdk\";\r\nimport type { TelegramUserInfo } from \"./types.js\";\r\n\r\n/**\r\n * 尝试获取启动参数,检查是否在 Telegram 环境中\r\n */\r\nfunction retrieveLaunchParams() {\r\n if (!WebApp.initData || WebApp.initData === \"\") {\r\n throw new Error(\"未能提取启动参数,不在 Telegram 环境中\");\r\n }\r\n return WebApp.initData;\r\n}\r\n\r\n// 单独拆分一个函数用来获取数据,不要让它影响环境判断\r\nexport function getLaunchParams() {\r\n const tg = (window as any).Telegram.WebApp;\r\n if (!tg.initData) {\r\n // 这里可以结合上一个问题的解决方案,尝试从 sessionStorage 读取\r\n const cached = sessionStorage.getItem('tg_init_data');\r\n if (cached) return cached;\r\n \r\n console.warn(\"当前在 Telegram 环境,但没有 initData (可能是页面刷新导致的)\");\r\n return \"\";\r\n }\r\n return tg.initData;\r\n}\r\n\r\nexport function isTelegramEnv(): boolean {\r\n try {\r\n // 1. 基础对象检查\r\n if (\r\n typeof window === \"undefined\" ||\r\n !(window as any).Telegram ||\r\n !(window as any).Telegram.WebApp\r\n ) {\r\n return false;\r\n }\r\n\r\n const tg = (window as any).Telegram.WebApp;\r\n \r\n // 2. 检查 initDataUnsafe - 这是 Telegram 环境最可靠的标识\r\n // initDataUnsafe 是 Telegram 特有的对象,包含用户信息和认证数据\r\n // 如果 initDataUnsafe 存在且是对象,基本可以确定在 Telegram 环境中\r\n if (!tg.initDataUnsafe || typeof tg.initDataUnsafe !== \"object\") {\r\n return false;\r\n }\r\n\r\n // 3. 进一步验证:检查 initDataUnsafe.user 或 initData 属性\r\n // 这两个属性在真实的 Telegram 环境中应该存在\r\n const hasUser = tg.initDataUnsafe.user && typeof tg.initDataUnsafe.user === \"object\";\r\n const hasInitData = 'initData' in tg;\r\n \r\n if (hasUser || hasInitData) {\r\n // 如果 platform 存在且是明显无效的值,可能是手动注入的对象\r\n const platform = tg.platform;\r\n if (platform !== undefined && platform !== null && typeof platform === \"string\") {\r\n const invalidPlatforms = ['fake', 'mock', 'test'];\r\n if (invalidPlatforms.includes(platform.toLowerCase())) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n return false;\r\n } catch (error) {\r\n console.warn(\"环境检测异常\", error);\r\n return false;\r\n }\r\n}\r\n\r\nexport function getTelegramUserUnsafe(): TelegramUserInfo | null {\r\n try {\r\n // 确保 WebApp 对象存在\r\n if (!WebApp || !WebApp.initDataUnsafe) {\r\n return null;\r\n }\r\n\r\n const initDataUnsafe = WebApp.initDataUnsafe;\r\n\r\n // 验证用户信息的基本结构\r\n if (!initDataUnsafe.user || !initDataUnsafe.user.id) {\r\n console.warn(\"Telegram用户信息结构不完整\");\r\n return null;\r\n }\r\n\r\n // 确保包含必要字段\r\n const userInfo = {\r\n user: {\r\n id: initDataUnsafe.user.id,\r\n firstName: initDataUnsafe.user.first_name || \"\",\r\n lastName: initDataUnsafe.user.last_name || \"\",\r\n username: initDataUnsafe.user.username,\r\n photoUrl: initDataUnsafe.user.photo_url || \"\",\r\n languageCode: initDataUnsafe.user.language_code,\r\n isPremium: initDataUnsafe.user.is_premium || false,\r\n allowsWriteToPm: initDataUnsafe.user.allows_write_to_pm || false,\r\n },\r\n authDate: new Date().toISOString(),\r\n hash: initDataUnsafe.hash || \"\",\r\n startParam: initDataUnsafe.start_param,\r\n chatType: initDataUnsafe.chat_type,\r\n chatInstance: initDataUnsafe.chat_instance,\r\n };\r\n\r\n return userInfo as TelegramUserInfo;\r\n } catch (error) {\r\n console.warn(\"获取Telegram用户信息失败:\", error);\r\n return null;\r\n }\r\n}\r\n\r\n/** Cookie 工具 **/\r\nfunction readCookie(name: string): string | null {\r\n if (typeof document === \"undefined\") return null;\r\n const match = document.cookie.match(\r\n new RegExp(\r\n \"(?:^|; )\" + name.replace(/([.$?*|{}()\\[\\]\\\\/+^])/g, \"\\\\$1\") + \"=([^;]*)\"\r\n )\r\n );\r\n return match ? decodeURIComponent(match[1]) : null;\r\n}\r\n\r\nfunction writeCookie(name: string, value: string, days = 365 * 2) {\r\n if (typeof document === \"undefined\") return;\r\n const date = new Date();\r\n date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\r\n const expires = \"; expires=\" + date.toUTCString();\r\n document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(\r\n value\r\n )}${expires}; path=/`;\r\n}\r\n\r\nfunction generateNumericId(): number {\r\n // 生成稳定的数值 ID(53-bit 安全整数范围内)\r\n const rand = Math.floor(Math.random() * 1e9);\r\n const time = Date.now() % 1e9;\r\n const id = Number(\r\n String(time).padStart(9, \"0\") + String(rand).padStart(9, \"0\")\r\n );\r\n return id;\r\n}\r\n\r\n/**\r\n * 基于 Cookie 的匿名浏览器用户(非 Telegram 环境使用)\r\n * - 会在 cookie 中持久化 uid,下次复用\r\n */\r\nexport function getAnonymousBrowserUser(\r\n cookieName = \"tg_tracking_uid\"\r\n): TelegramUserInfo {\r\n let uidStr = readCookie(cookieName);\r\n if (!uidStr) {\r\n const uid = generateNumericId();\r\n uidStr = String(uid);\r\n writeCookie(cookieName, uidStr);\r\n }\r\n const uidNum =\r\n Number(uidStr.replace(/\\D/g, \"\").slice(0, 15)) || generateNumericId();\r\n const lang =\r\n (typeof navigator !== \"undefined\" &&\r\n (navigator.language || (navigator as any).userLanguage)) ||\r\n \"en\";\r\n\r\n return {\r\n user: {\r\n id: uidNum,\r\n firstName: \"Guest\",\r\n lastName: \"\",\r\n username: `guest_${uidStr.slice(-6)}`,\r\n languageCode: lang.toLowerCase(),\r\n isPremium: false,\r\n allowsWriteToPm: false,\r\n },\r\n authDate: new Date().toISOString(),\r\n hash: \"anonymous_cookie_user\",\r\n startParam: \"browser_guest\",\r\n chatType: \"sender\",\r\n chatInstance: \"\",\r\n } as TelegramUserInfo;\r\n}\r\n\r\n/**\r\n * 获取默认的 mock 用户信息(保留旧逻辑)\r\n */\r\nexport function getDefaultMockUser(): TelegramUserInfo {\r\n return {\r\n user: {\r\n id: 2077220643,\r\n firstName: \"Mock\",\r\n lastName: \"User\",\r\n username: \"mock_user_demo\",\r\n languageCode: \"zh-hans\",\r\n isPremium: true,\r\n allowsWriteToPm: true,\r\n },\r\n authDate: new Date().toISOString(),\r\n hash: \"mock_hash_for_demo_purpose\",\r\n startParam: \"demo_start_param\",\r\n chatType: \"sender\",\r\n chatInstance: \"-245769840322609948\",\r\n } as TelegramUserInfo;\r\n}\r\n"]}
1
+ {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/sdk/telegram.ts"],"names":[],"mappings":"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","sourcesContent":["import WebApp from \"@twa-dev/sdk\";\r\nimport type { TelegramUserInfo } from \"./types.js\";\r\n\r\n/**\r\n * 尝试获取启动参数,检查是否在 Telegram 环境中\r\n */\r\nfunction retrieveLaunchParams() {\r\n if (!WebApp.initData || WebApp.initData === \"\") {\r\n throw new Error(\"未能提取启动参数,不在 Telegram 环境中\");\r\n }\r\n return WebApp.initData;\r\n}\r\n\r\n// 单独拆分一个函数用来获取数据,不要让它影响环境判断\r\nexport function getLaunchParams() {\r\n const tg = (window as any).Telegram.WebApp;\r\n if (!tg.initData) {\r\n // 这里可以结合上一个问题的解决方案,尝试从 sessionStorage 读取\r\n const cached = sessionStorage.getItem('tg_init_data');\r\n if (cached) return cached;\r\n \r\n console.warn(\"当前在 Telegram 环境,但没有 initData (可能是页面刷新导致的)\");\r\n return \"\";\r\n }\r\n return tg.initData;\r\n}\r\n\r\nexport function isTelegramEnv(): boolean {\r\n try {\r\n // 1. 基础对象检查\r\n if (\r\n typeof window === \"undefined\" ||\r\n !(window as any).Telegram ||\r\n !(window as any).Telegram.WebApp\r\n ) {\r\n return false;\r\n }\r\n\r\n const tg = (window as any).Telegram.WebApp;\r\n \r\n // 2. 检查 initDataUnsafe - 这是 Telegram 环境最可靠的标识\r\n // initDataUnsafe 是 Telegram 特有的对象,包含用户信息和认证数据\r\n // 如果 initDataUnsafe 存在且是对象,基本可以确定在 Telegram 环境中\r\n if (!tg.initDataUnsafe || typeof tg.initDataUnsafe !== \"object\") {\r\n return false;\r\n }\r\n\r\n // 3. 严格验证:必须同时满足以下条件才认为是真实的 Telegram 环境\r\n // - initDataUnsafe.user 必须存在且是对象,且必须有有效的 id\r\n // - 或者 initData 必须存在且是有效的字符串(非空)\r\n const hasValidUser = \r\n tg.initDataUnsafe.user && \r\n typeof tg.initDataUnsafe.user === \"object\" &&\r\n typeof tg.initDataUnsafe.user.id === \"number\" &&\r\n tg.initDataUnsafe.user.id > 0;\r\n \r\n const hasValidInitData = \r\n 'initData' in tg && \r\n typeof tg.initData === \"string\" && \r\n tg.initData.length > 0;\r\n \r\n // 必须至少有一个有效标识\r\n if (!hasValidUser && !hasValidInitData) {\r\n return false;\r\n }\r\n\r\n // 4. 如果 platform 存在且是明显无效的值,可能是手动注入的对象\r\n const platform = tg.platform;\r\n if (platform !== undefined && platform !== null && typeof platform === \"string\") {\r\n const invalidPlatforms = ['fake', 'mock', 'test'];\r\n if (invalidPlatforms.includes(platform.toLowerCase())) {\r\n return false;\r\n }\r\n }\r\n\r\n // 5. 额外检查:如果 initDataUnsafe 是空对象且没有其他有效标识,可能是 mock 对象\r\n const initDataUnsafeKeys = Object.keys(tg.initDataUnsafe || {});\r\n if (initDataUnsafeKeys.length === 0 && !hasValidInitData) {\r\n return false;\r\n }\r\n\r\n return true;\r\n } catch (error) {\r\n console.warn(\"环境检测异常\", error);\r\n return false;\r\n }\r\n}\r\n\r\nexport function getTelegramUserUnsafe(): TelegramUserInfo | null {\r\n try {\r\n // 确保 WebApp 对象存在\r\n if (!WebApp || !WebApp.initDataUnsafe) {\r\n return null;\r\n }\r\n\r\n const initDataUnsafe = WebApp.initDataUnsafe;\r\n\r\n // 验证用户信息的基本结构\r\n if (!initDataUnsafe.user || !initDataUnsafe.user.id) {\r\n console.warn(\"Telegram用户信息结构不完整\");\r\n return null;\r\n }\r\n\r\n // 确保包含必要字段\r\n const userInfo = {\r\n user: {\r\n id: initDataUnsafe.user.id,\r\n firstName: initDataUnsafe.user.first_name || \"\",\r\n lastName: initDataUnsafe.user.last_name || \"\",\r\n username: initDataUnsafe.user.username,\r\n photoUrl: initDataUnsafe.user.photo_url || \"\",\r\n languageCode: initDataUnsafe.user.language_code,\r\n isPremium: initDataUnsafe.user.is_premium || false,\r\n allowsWriteToPm: initDataUnsafe.user.allows_write_to_pm || false,\r\n },\r\n authDate: new Date().toISOString(),\r\n hash: initDataUnsafe.hash || \"\",\r\n startParam: initDataUnsafe.start_param,\r\n chatType: initDataUnsafe.chat_type,\r\n chatInstance: initDataUnsafe.chat_instance,\r\n };\r\n\r\n return userInfo as TelegramUserInfo;\r\n } catch (error) {\r\n console.warn(\"获取Telegram用户信息失败:\", error);\r\n return null;\r\n }\r\n}\r\n\r\n/** Cookie 工具 **/\r\nfunction readCookie(name: string): string | null {\r\n if (typeof document === \"undefined\") return null;\r\n const match = document.cookie.match(\r\n new RegExp(\r\n \"(?:^|; )\" + name.replace(/([.$?*|{}()\\[\\]\\\\/+^])/g, \"\\\\$1\") + \"=([^;]*)\"\r\n )\r\n );\r\n return match ? decodeURIComponent(match[1]) : null;\r\n}\r\n\r\nfunction writeCookie(name: string, value: string, days = 365 * 2) {\r\n if (typeof document === \"undefined\") return;\r\n const date = new Date();\r\n date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\r\n const expires = \"; expires=\" + date.toUTCString();\r\n document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(\r\n value\r\n )}${expires}; path=/`;\r\n}\r\n\r\nfunction generateNumericId(): number {\r\n // 生成稳定的数值 ID(53-bit 安全整数范围内)\r\n const rand = Math.floor(Math.random() * 1e9);\r\n const time = Date.now() % 1e9;\r\n const id = Number(\r\n String(time).padStart(9, \"0\") + String(rand).padStart(9, \"0\")\r\n );\r\n return id;\r\n}\r\n\r\n/**\r\n * 基于 Cookie 的匿名浏览器用户(非 Telegram 环境使用)\r\n * - 会在 cookie 中持久化 uid,下次复用\r\n */\r\nexport function getAnonymousBrowserUser(\r\n cookieName = \"tg_tracking_uid\"\r\n): TelegramUserInfo {\r\n let uidStr = readCookie(cookieName);\r\n if (!uidStr) {\r\n const uid = generateNumericId();\r\n uidStr = String(uid);\r\n writeCookie(cookieName, uidStr);\r\n }\r\n const uidNum =\r\n Number(uidStr.replace(/\\D/g, \"\").slice(0, 15)) || generateNumericId();\r\n const lang =\r\n (typeof navigator !== \"undefined\" &&\r\n (navigator.language || (navigator as any).userLanguage)) ||\r\n \"en\";\r\n\r\n return {\r\n user: {\r\n id: uidNum,\r\n firstName: \"Guest\",\r\n lastName: \"\",\r\n username: `guest_${uidStr.slice(-6)}`,\r\n languageCode: lang.toLowerCase(),\r\n isPremium: false,\r\n allowsWriteToPm: false,\r\n },\r\n authDate: new Date().toISOString(),\r\n hash: \"anonymous_cookie_user\",\r\n startParam: \"browser_guest\",\r\n chatType: \"sender\",\r\n chatInstance: \"\",\r\n } as TelegramUserInfo;\r\n}\r\n\r\n/**\r\n * 获取默认的 mock 用户信息(保留旧逻辑)\r\n */\r\nexport function getDefaultMockUser(): TelegramUserInfo {\r\n return {\r\n user: {\r\n id: 2077220643,\r\n firstName: \"Mock\",\r\n lastName: \"User\",\r\n username: \"mock_user_demo\",\r\n languageCode: \"zh-hans\",\r\n isPremium: true,\r\n allowsWriteToPm: true,\r\n },\r\n authDate: new Date().toISOString(),\r\n hash: \"mock_hash_for_demo_purpose\",\r\n startParam: \"demo_start_param\",\r\n chatType: \"sender\",\r\n chatInstance: \"-245769840322609948\",\r\n } as TelegramUserInfo;\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hm-tracking-sdk",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "private": false,
5
5
  "description": "Telegram tracking SDK for Web/Miniapp with TON/Stars payment integration.",
6
6
  "license": "MIT",