@casys/mcp-bridge 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/esm/_dnt.shims.d.ts +2 -0
  2. package/esm/_dnt.shims.d.ts.map +1 -0
  3. package/esm/_dnt.shims.js +57 -0
  4. package/esm/adapters/base-adapter.d.ts +25 -0
  5. package/esm/adapters/base-adapter.d.ts.map +1 -0
  6. package/esm/adapters/base-adapter.js +86 -0
  7. package/esm/adapters/line/adapter.d.ts +11 -0
  8. package/esm/adapters/line/adapter.d.ts.map +1 -0
  9. package/esm/adapters/line/adapter.js +10 -0
  10. package/esm/adapters/line/types.d.ts +25 -0
  11. package/esm/adapters/line/types.d.ts.map +1 -0
  12. package/esm/adapters/line/types.js +4 -0
  13. package/esm/adapters/telegram/adapter.d.ts +11 -0
  14. package/esm/adapters/telegram/adapter.d.ts.map +1 -0
  15. package/esm/adapters/telegram/adapter.js +10 -0
  16. package/esm/adapters/telegram/platform-adapter.d.ts +40 -0
  17. package/esm/adapters/telegram/platform-adapter.d.ts.map +1 -0
  18. package/esm/adapters/telegram/platform-adapter.js +214 -0
  19. package/esm/adapters/telegram/sdk-bridge.d.ts +8 -0
  20. package/esm/adapters/telegram/sdk-bridge.d.ts.map +1 -0
  21. package/esm/adapters/telegram/sdk-bridge.js +22 -0
  22. package/esm/adapters/telegram/types.d.ts +93 -0
  23. package/esm/adapters/telegram/types.d.ts.map +1 -0
  24. package/esm/adapters/telegram/types.js +6 -0
  25. package/esm/client/bridge.js +424 -0
  26. package/esm/core/adapter.d.ts +88 -0
  27. package/esm/core/adapter.d.ts.map +1 -0
  28. package/esm/core/adapter.js +10 -0
  29. package/esm/core/bridge-client.d.ts +77 -0
  30. package/esm/core/bridge-client.d.ts.map +1 -0
  31. package/esm/core/bridge-client.js +275 -0
  32. package/esm/core/message-router.d.ts +71 -0
  33. package/esm/core/message-router.d.ts.map +1 -0
  34. package/esm/core/message-router.js +187 -0
  35. package/esm/core/protocol.d.ts +116 -0
  36. package/esm/core/protocol.d.ts.map +1 -0
  37. package/esm/core/protocol.js +203 -0
  38. package/esm/core/resource-resolver.d.ts +27 -0
  39. package/esm/core/resource-resolver.d.ts.map +1 -0
  40. package/esm/core/resource-resolver.js +85 -0
  41. package/esm/core/transport.d.ts +46 -0
  42. package/esm/core/transport.d.ts.map +1 -0
  43. package/esm/core/transport.js +85 -0
  44. package/esm/core/types.d.ts +187 -0
  45. package/esm/core/types.d.ts.map +1 -0
  46. package/esm/core/types.js +35 -0
  47. package/esm/mod.d.ts +36 -0
  48. package/esm/mod.d.ts.map +1 -0
  49. package/esm/mod.js +33 -0
  50. package/esm/package.json +3 -0
  51. package/esm/resource-server/csp.d.ts +36 -0
  52. package/esm/resource-server/csp.d.ts.map +1 -0
  53. package/esm/resource-server/csp.js +36 -0
  54. package/esm/resource-server/injector.d.ts +18 -0
  55. package/esm/resource-server/injector.d.ts.map +1 -0
  56. package/esm/resource-server/injector.js +39 -0
  57. package/esm/resource-server/server.d.ts +107 -0
  58. package/esm/resource-server/server.d.ts.map +1 -0
  59. package/esm/resource-server/server.js +483 -0
  60. package/esm/resource-server/session.d.ts +60 -0
  61. package/esm/resource-server/session.d.ts.map +1 -0
  62. package/esm/resource-server/session.js +86 -0
  63. package/esm/resource-server/telegram-auth.d.ts +45 -0
  64. package/esm/resource-server/telegram-auth.d.ts.map +1 -0
  65. package/esm/resource-server/telegram-auth.js +161 -0
  66. package/package.json +31 -0
  67. package/script/_dnt.shims.d.ts +2 -0
  68. package/script/_dnt.shims.d.ts.map +1 -0
  69. package/script/_dnt.shims.js +60 -0
  70. package/script/adapters/base-adapter.d.ts +25 -0
  71. package/script/adapters/base-adapter.d.ts.map +1 -0
  72. package/script/adapters/base-adapter.js +113 -0
  73. package/script/adapters/line/adapter.d.ts +11 -0
  74. package/script/adapters/line/adapter.d.ts.map +1 -0
  75. package/script/adapters/line/adapter.js +14 -0
  76. package/script/adapters/line/types.d.ts +25 -0
  77. package/script/adapters/line/types.d.ts.map +1 -0
  78. package/script/adapters/line/types.js +5 -0
  79. package/script/adapters/telegram/adapter.d.ts +11 -0
  80. package/script/adapters/telegram/adapter.d.ts.map +1 -0
  81. package/script/adapters/telegram/adapter.js +14 -0
  82. package/script/adapters/telegram/platform-adapter.d.ts +40 -0
  83. package/script/adapters/telegram/platform-adapter.d.ts.map +1 -0
  84. package/script/adapters/telegram/platform-adapter.js +241 -0
  85. package/script/adapters/telegram/sdk-bridge.d.ts +8 -0
  86. package/script/adapters/telegram/sdk-bridge.d.ts.map +1 -0
  87. package/script/adapters/telegram/sdk-bridge.js +48 -0
  88. package/script/adapters/telegram/types.d.ts +93 -0
  89. package/script/adapters/telegram/types.d.ts.map +1 -0
  90. package/script/adapters/telegram/types.js +7 -0
  91. package/script/client/bridge.js +424 -0
  92. package/script/core/adapter.d.ts +88 -0
  93. package/script/core/adapter.d.ts.map +1 -0
  94. package/script/core/adapter.js +11 -0
  95. package/script/core/bridge-client.d.ts +77 -0
  96. package/script/core/bridge-client.d.ts.map +1 -0
  97. package/script/core/bridge-client.js +302 -0
  98. package/script/core/message-router.d.ts +71 -0
  99. package/script/core/message-router.d.ts.map +1 -0
  100. package/script/core/message-router.js +191 -0
  101. package/script/core/protocol.d.ts +116 -0
  102. package/script/core/protocol.d.ts.map +1 -0
  103. package/script/core/protocol.js +230 -0
  104. package/script/core/resource-resolver.d.ts +27 -0
  105. package/script/core/resource-resolver.d.ts.map +1 -0
  106. package/script/core/resource-resolver.js +89 -0
  107. package/script/core/transport.d.ts +46 -0
  108. package/script/core/transport.d.ts.map +1 -0
  109. package/script/core/transport.js +112 -0
  110. package/script/core/types.d.ts +187 -0
  111. package/script/core/types.d.ts.map +1 -0
  112. package/script/core/types.js +38 -0
  113. package/script/mod.d.ts +36 -0
  114. package/script/mod.d.ts.map +1 -0
  115. package/script/mod.js +76 -0
  116. package/script/package.json +3 -0
  117. package/script/resource-server/csp.d.ts +36 -0
  118. package/script/resource-server/csp.d.ts.map +1 -0
  119. package/script/resource-server/csp.js +39 -0
  120. package/script/resource-server/injector.d.ts +18 -0
  121. package/script/resource-server/injector.d.ts.map +1 -0
  122. package/script/resource-server/injector.js +42 -0
  123. package/script/resource-server/server.d.ts +107 -0
  124. package/script/resource-server/server.d.ts.map +1 -0
  125. package/script/resource-server/server.js +487 -0
  126. package/script/resource-server/session.d.ts +60 -0
  127. package/script/resource-server/session.d.ts.map +1 -0
  128. package/script/resource-server/session.js +90 -0
  129. package/script/resource-server/telegram-auth.d.ts +45 -0
  130. package/script/resource-server/telegram-auth.d.ts.map +1 -0
  131. package/script/resource-server/telegram-auth.js +164 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Telegram Mini App initData HMAC-SHA256 server-side validation.
3
+ *
4
+ * Implements the algorithm documented at:
5
+ * @see https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app
6
+ *
7
+ * Uses the Web Crypto API exclusively (works in Deno and Node.js 18+).
8
+ */
9
+ /** Default maximum age for auth_date: 24 hours. */
10
+ const DEFAULT_MAX_AGE_SECONDS = 86_400;
11
+ // ---------------------------------------------------------------------------
12
+ // Public API
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * Validate Telegram Mini App `initData`.
16
+ *
17
+ * Algorithm:
18
+ * 1. Parse the initData query string.
19
+ * 2. Extract and remove the `hash` parameter.
20
+ * 3. Sort remaining key=value pairs alphabetically by key.
21
+ * 4. Join them with `\n` to form data_check_string.
22
+ * 5. Derive secret_key = HMAC-SHA256(key="WebAppData", data=botToken).
23
+ * 6. Compute expected = HMAC-SHA256(key=secret_key, data=data_check_string).
24
+ * 7. Compare hex(expected) with hash using constant-time comparison.
25
+ * 8. Check auth_date freshness.
26
+ *
27
+ * @param initData - The raw initData query string from Telegram.
28
+ * @param botToken - The bot token used to sign the data.
29
+ * @param maxAgeSeconds - Maximum acceptable age of auth_date. Defaults to 86400 (24h).
30
+ * @returns A promise resolving to the validation result.
31
+ */
32
+ export async function validateTelegramInitData(initData, botToken, maxAgeSeconds = DEFAULT_MAX_AGE_SECONDS) {
33
+ // -----------------------------------------------------------------------
34
+ // 1. Input validation (fail-fast)
35
+ // -----------------------------------------------------------------------
36
+ if (!initData || typeof initData !== "string") {
37
+ return { valid: false, error: "initData is required and must be a non-empty string" };
38
+ }
39
+ if (!botToken || typeof botToken !== "string") {
40
+ throw new Error("[telegram-auth] botToken is required. " +
41
+ "Provide the Telegram Bot token for HMAC-SHA256 validation.");
42
+ }
43
+ // -----------------------------------------------------------------------
44
+ // 2. Parse query string and extract hash
45
+ // -----------------------------------------------------------------------
46
+ const params = new URLSearchParams(initData);
47
+ const receivedHash = params.get("hash");
48
+ if (!receivedHash) {
49
+ return { valid: false, error: "Missing 'hash' parameter in initData" };
50
+ }
51
+ const authDateRaw = params.get("auth_date");
52
+ if (!authDateRaw) {
53
+ return { valid: false, error: "Missing 'auth_date' parameter in initData" };
54
+ }
55
+ const authDateUnix = parseInt(authDateRaw, 10);
56
+ if (isNaN(authDateUnix)) {
57
+ return { valid: false, error: "Invalid 'auth_date' parameter: not a valid integer" };
58
+ }
59
+ // -----------------------------------------------------------------------
60
+ // 3. Build data_check_string: sorted key=value pairs excluding `hash`
61
+ // -----------------------------------------------------------------------
62
+ params.delete("hash");
63
+ const pairs = [];
64
+ for (const [key, value] of params.entries()) {
65
+ pairs.push(`${key}=${value}`);
66
+ }
67
+ pairs.sort();
68
+ const dataCheckString = pairs.join("\n");
69
+ // -----------------------------------------------------------------------
70
+ // 4. Compute HMAC-SHA256 and compare
71
+ // -----------------------------------------------------------------------
72
+ const secretKey = await hmacSha256(new TextEncoder().encode("WebAppData"), new TextEncoder().encode(botToken));
73
+ const receivedHashBytes = hexToBytes(receivedHash);
74
+ if (!receivedHashBytes) {
75
+ return { valid: false, error: "Invalid 'hash' parameter: not valid hex" };
76
+ }
77
+ // Use crypto.subtle.verify for inherently timing-safe comparison
78
+ const verifyKey = await crypto.subtle.importKey("raw", secretKey, { name: "HMAC", hash: "SHA-256" }, false, ["verify"]);
79
+ const isValid = await crypto.subtle.verify("HMAC", verifyKey, receivedHashBytes, new TextEncoder().encode(dataCheckString));
80
+ if (!isValid) {
81
+ return { valid: false, error: "HMAC-SHA256 hash mismatch: initData signature is invalid" };
82
+ }
83
+ // -----------------------------------------------------------------------
84
+ // 5. Check auth_date freshness
85
+ // -----------------------------------------------------------------------
86
+ const authDate = new Date(authDateUnix * 1000);
87
+ const nowSeconds = Math.floor(Date.now() / 1000);
88
+ const ageSeconds = nowSeconds - authDateUnix;
89
+ if (ageSeconds > maxAgeSeconds) {
90
+ return {
91
+ valid: false,
92
+ error: `initData expired: auth_date is ${ageSeconds}s old, max allowed is ${maxAgeSeconds}s`,
93
+ };
94
+ }
95
+ if (ageSeconds < -60) {
96
+ // Allow 60s clock skew into the future, but reject beyond that
97
+ return {
98
+ valid: false,
99
+ error: `initData auth_date is ${-ageSeconds}s in the future (beyond 60s tolerance)`,
100
+ };
101
+ }
102
+ // -----------------------------------------------------------------------
103
+ // 6. Parse user data
104
+ // -----------------------------------------------------------------------
105
+ const result = {
106
+ valid: true,
107
+ authDate,
108
+ ...parseUserData(params.get("user")),
109
+ };
110
+ return result;
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // Internal helpers
114
+ // ---------------------------------------------------------------------------
115
+ /**
116
+ * Compute HMAC-SHA256 using Web Crypto API.
117
+ *
118
+ * @param key - The HMAC key as raw bytes.
119
+ * @param data - The message to sign.
120
+ * @returns The HMAC digest as a Uint8Array.
121
+ */
122
+ async function hmacSha256(key, data) {
123
+ const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
124
+ const signature = await crypto.subtle.sign("HMAC", cryptoKey, data);
125
+ return new Uint8Array(signature);
126
+ }
127
+ /** Convert a hex string to Uint8Array. Returns null if invalid hex. */
128
+ function hexToBytes(hex) {
129
+ if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex)) {
130
+ return null;
131
+ }
132
+ const bytes = new Uint8Array(hex.length / 2);
133
+ for (let i = 0; i < hex.length; i += 2) {
134
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
135
+ }
136
+ return bytes;
137
+ }
138
+ /**
139
+ * Parse the `user` JSON field from initData.
140
+ *
141
+ * Returns an object with userId, username, firstName, lastName if present.
142
+ * Returns an empty object if user data is absent or unparseable.
143
+ */
144
+ function parseUserData(userJson) {
145
+ if (!userJson)
146
+ return {};
147
+ try {
148
+ const user = JSON.parse(userJson);
149
+ return {
150
+ userId: typeof user.id === "number" ? user.id : undefined,
151
+ username: typeof user.username === "string" ? user.username : undefined,
152
+ firstName: typeof user.first_name === "string" ? user.first_name : undefined,
153
+ lastName: typeof user.last_name === "string" ? user.last_name : undefined,
154
+ };
155
+ }
156
+ catch {
157
+ // User JSON is optional data enrichment; a parsing failure here
158
+ // does not invalidate the HMAC signature itself.
159
+ return {};
160
+ }
161
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@casys/mcp-bridge",
3
+ "version": "0.2.0",
4
+ "description": "Bridge MCP Apps interactive UIs to messaging platforms (Telegram Mini Apps, LINE LIFF)",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "telegram",
9
+ "mini-apps",
10
+ "line",
11
+ "liff",
12
+ "bridge",
13
+ "messaging"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/Casys-AI/mcp-bridge"
18
+ },
19
+ "license": "MIT",
20
+ "main": "./script/mod.js",
21
+ "module": "./esm/mod.js",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./esm/mod.d.ts",
25
+ "import": "./esm/mod.js",
26
+ "require": "./script/mod.js"
27
+ }
28
+ },
29
+ "_generatedBy": "dnt@dev",
30
+ "types": "./esm/mod.d.ts"
31
+ }
@@ -0,0 +1,2 @@
1
+ export declare const dntGlobalThis: Omit<typeof globalThis, never>;
2
+ //# sourceMappingURL=_dnt.shims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_dnt.shims.d.ts","sourceRoot":"","sources":["../src/_dnt.shims.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,gCAA2C,CAAC"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dntGlobalThis = void 0;
4
+ const dntGlobals = {};
5
+ exports.dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
6
+ function createMergeProxy(baseObj, extObj) {
7
+ return new Proxy(baseObj, {
8
+ get(_target, prop, _receiver) {
9
+ if (prop in extObj) {
10
+ return extObj[prop];
11
+ }
12
+ else {
13
+ return baseObj[prop];
14
+ }
15
+ },
16
+ set(_target, prop, value) {
17
+ if (prop in extObj) {
18
+ delete extObj[prop];
19
+ }
20
+ baseObj[prop] = value;
21
+ return true;
22
+ },
23
+ deleteProperty(_target, prop) {
24
+ let success = false;
25
+ if (prop in extObj) {
26
+ delete extObj[prop];
27
+ success = true;
28
+ }
29
+ if (prop in baseObj) {
30
+ delete baseObj[prop];
31
+ success = true;
32
+ }
33
+ return success;
34
+ },
35
+ ownKeys(_target) {
36
+ const baseKeys = Reflect.ownKeys(baseObj);
37
+ const extKeys = Reflect.ownKeys(extObj);
38
+ const extKeysSet = new Set(extKeys);
39
+ return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
40
+ },
41
+ defineProperty(_target, prop, desc) {
42
+ if (prop in extObj) {
43
+ delete extObj[prop];
44
+ }
45
+ Reflect.defineProperty(baseObj, prop, desc);
46
+ return true;
47
+ },
48
+ getOwnPropertyDescriptor(_target, prop) {
49
+ if (prop in extObj) {
50
+ return Reflect.getOwnPropertyDescriptor(extObj, prop);
51
+ }
52
+ else {
53
+ return Reflect.getOwnPropertyDescriptor(baseObj, prop);
54
+ }
55
+ },
56
+ has(_target, prop) {
57
+ return prop in extObj || prop in baseObj;
58
+ },
59
+ });
60
+ }
@@ -0,0 +1,25 @@
1
+ import type { McpAppsAdapter, MessageHandler } from "../core/adapter.js";
2
+ import type { AdapterConfig, McpAppsMessage } from "../core/types.js";
3
+ /**
4
+ * Abstract base for postMessage-based platform adapters.
5
+ *
6
+ * Handles the common lifecycle:
7
+ * - `init()`: set up `message` event listener, derive targetOrigin from config
8
+ * - `sendToHost()`: forward JSON-RPC to parent frame via postMessage
9
+ * - `onMessageFromHost()`: register message handlers
10
+ * - `destroy()`: tear down listener and handlers
11
+ *
12
+ * Concrete adapters (Telegram, LINE) extend this and set `platform`.
13
+ */
14
+ export declare abstract class BasePostMessageAdapter implements McpAppsAdapter {
15
+ abstract readonly platform: string;
16
+ private initialized;
17
+ private handlers;
18
+ private boundListener;
19
+ private targetOrigin;
20
+ init(config: AdapterConfig): Promise<void>;
21
+ sendToHost(message: McpAppsMessage): void;
22
+ onMessageFromHost(handler: MessageHandler): void;
23
+ destroy(): void;
24
+ }
25
+ //# sourceMappingURL=base-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/base-adapter.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAMtE;;;;;;;;;;GAUG;AACH,8BAAsB,sBAAuB,YAAW,cAAc;IACpE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAEnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,YAAY,CAAO;IAE3B,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA6C1C,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAYzC,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIhD,OAAO,IAAI,IAAI;CAQhB"}
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.BasePostMessageAdapter = void 0;
27
+ /**
28
+ * Base postMessage adapter for platform integrations.
29
+ *
30
+ * Provides the common message interception and dispatch logic shared by
31
+ * all platform adapters that communicate via `window.parent.postMessage`.
32
+ *
33
+ * Subclasses only need to set their `platform` identifier.
34
+ */
35
+ const dntShim = __importStar(require("../_dnt.shims.js"));
36
+ // Cast globalThis to access browser-only APIs at runtime.
37
+ // deno-lint-ignore no-explicit-any
38
+ const _global = dntShim.dntGlobalThis;
39
+ /**
40
+ * Abstract base for postMessage-based platform adapters.
41
+ *
42
+ * Handles the common lifecycle:
43
+ * - `init()`: set up `message` event listener, derive targetOrigin from config
44
+ * - `sendToHost()`: forward JSON-RPC to parent frame via postMessage
45
+ * - `onMessageFromHost()`: register message handlers
46
+ * - `destroy()`: tear down listener and handlers
47
+ *
48
+ * Concrete adapters (Telegram, LINE) extend this and set `platform`.
49
+ */
50
+ class BasePostMessageAdapter {
51
+ initialized = false;
52
+ handlers = [];
53
+ boundListener = null;
54
+ targetOrigin = "*";
55
+ init(config) {
56
+ if (this.initialized) {
57
+ throw new Error(`[${this.platform}Adapter] Already initialized.`);
58
+ }
59
+ // Use resourceBaseUrl as targetOrigin instead of "*" (security)
60
+ if (config.resourceBaseUrl) {
61
+ try {
62
+ const url = new URL(config.resourceBaseUrl);
63
+ this.targetOrigin = url.origin;
64
+ }
65
+ catch {
66
+ console.warn(`[${this.platform}Adapter] Invalid resourceBaseUrl, falling back to '*' targetOrigin:`, config.resourceBaseUrl);
67
+ }
68
+ }
69
+ this.boundListener = ((event) => {
70
+ try {
71
+ // deno-lint-ignore no-explicit-any
72
+ const msgEvent = event;
73
+ const raw = msgEvent.data;
74
+ const data = typeof raw === "string" ? JSON.parse(raw) : raw;
75
+ if (data && typeof data === "object" && data.jsonrpc === "2.0") {
76
+ const message = data;
77
+ for (const handler of this.handlers) {
78
+ handler(message);
79
+ }
80
+ }
81
+ }
82
+ catch {
83
+ // Non-JSON messages are expected (other postMessage traffic),
84
+ // silently ignore to avoid log noise.
85
+ }
86
+ });
87
+ if (typeof _global.addEventListener === "function") {
88
+ _global.addEventListener("message", this.boundListener);
89
+ }
90
+ this.initialized = true;
91
+ return Promise.resolve();
92
+ }
93
+ sendToHost(message) {
94
+ if (!this.initialized) {
95
+ throw new Error(`[${this.platform}Adapter] Not initialized. Call init() first.`);
96
+ }
97
+ if (typeof _global.parent?.postMessage === "function") {
98
+ _global.parent.postMessage(JSON.stringify(message), this.targetOrigin);
99
+ }
100
+ }
101
+ onMessageFromHost(handler) {
102
+ this.handlers.push(handler);
103
+ }
104
+ destroy() {
105
+ if (this.boundListener && typeof _global.removeEventListener === "function") {
106
+ _global.removeEventListener("message", this.boundListener);
107
+ }
108
+ this.boundListener = null;
109
+ this.handlers = [];
110
+ this.initialized = false;
111
+ }
112
+ }
113
+ exports.BasePostMessageAdapter = BasePostMessageAdapter;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * LINE LIFF adapter for MCP Apps Bridge.
3
+ *
4
+ * Uses `postMessage` / `message` events to communicate with the LINE
5
+ * host WebView.
6
+ */
7
+ import { BasePostMessageAdapter } from "../base-adapter.js";
8
+ export declare class LineAdapter extends BasePostMessageAdapter {
9
+ readonly platform: "line";
10
+ }
11
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/line/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,qBAAa,WAAY,SAAQ,sBAAsB;IACrD,QAAQ,CAAC,QAAQ,SAAmB;CACrC"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * LINE LIFF adapter for MCP Apps Bridge.
4
+ *
5
+ * Uses `postMessage` / `message` events to communicate with the LINE
6
+ * host WebView.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.LineAdapter = void 0;
10
+ const base_adapter_js_1 = require("../base-adapter.js");
11
+ class LineAdapter extends base_adapter_js_1.BasePostMessageAdapter {
12
+ platform = "line";
13
+ }
14
+ exports.LineAdapter = LineAdapter;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * LINE LIFF specific types.
3
+ */
4
+ import type { AdapterConfig } from "../../core/types.js";
5
+ /** Configuration for the LINE LIFF adapter. */
6
+ export interface LineAdapterConfig extends AdapterConfig {
7
+ readonly platformOptions?: {
8
+ /** LINE LIFF App ID. */
9
+ readonly liffId?: string;
10
+ };
11
+ }
12
+ /**
13
+ * Subset of the LIFF SDK API.
14
+ * @see https://developers.line.biz/en/reference/liff/
15
+ */
16
+ export interface LiffSdk {
17
+ init(config: {
18
+ liffId: string;
19
+ }): Promise<void>;
20
+ isLoggedIn(): boolean;
21
+ getAccessToken(): string | null;
22
+ sendMessages(messages: readonly Record<string, unknown>[]): Promise<void>;
23
+ closeWindow(): void;
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/adapters/line/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,+CAA+C;AAC/C,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,QAAQ,CAAC,eAAe,CAAC,EAAE;QACzB,wBAAwB;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,IAAI,OAAO,CAAC;IACtB,cAAc,IAAI,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,CAAC,QAAQ,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,WAAW,IAAI,IAAI,CAAC;CACrB"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * LINE LIFF specific types.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Telegram Mini App adapter for MCP Apps Bridge.
3
+ *
4
+ * Uses `postMessage` / `message` events to communicate with the Telegram
5
+ * host WebView.
6
+ */
7
+ import { BasePostMessageAdapter } from "../base-adapter.js";
8
+ export declare class TelegramAdapter extends BasePostMessageAdapter {
9
+ readonly platform: "telegram";
10
+ }
11
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/telegram/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,qBAAa,eAAgB,SAAQ,sBAAsB;IACzD,QAAQ,CAAC,QAAQ,aAAuB;CACzC"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * Telegram Mini App adapter for MCP Apps Bridge.
4
+ *
5
+ * Uses `postMessage` / `message` events to communicate with the Telegram
6
+ * host WebView.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.TelegramAdapter = void 0;
10
+ const base_adapter_js_1 = require("../base-adapter.js");
11
+ class TelegramAdapter extends base_adapter_js_1.BasePostMessageAdapter {
12
+ platform = "telegram";
13
+ }
14
+ exports.TelegramAdapter = TelegramAdapter;
@@ -0,0 +1,40 @@
1
+ import type { LifecycleEventHandler, PlatformAdapter } from "../../core/adapter.js";
2
+ import type { ContainerDimensions, HostContext } from "../../core/types.js";
3
+ /**
4
+ * Maps Telegram WebApp SDK to the MCP Apps PlatformAdapter interface.
5
+ *
6
+ * Usage:
7
+ * ```ts
8
+ * const adapter = new TelegramPlatformAdapter();
9
+ * const client = new BridgeClient({ platform: adapter, ... });
10
+ * ```
11
+ */
12
+ export declare class TelegramPlatformAdapter implements PlatformAdapter {
13
+ readonly name: "telegram";
14
+ private tg;
15
+ private lifecycleHandlers;
16
+ private boundThemeHandler;
17
+ private boundViewportHandler;
18
+ private boundActivatedHandler;
19
+ private boundDeactivatedHandler;
20
+ initialize(): Promise<HostContext>;
21
+ getTheme(): "light" | "dark";
22
+ getContainerDimensions(): ContainerDimensions;
23
+ onLifecycleEvent(handler: LifecycleEventHandler): void;
24
+ openLink(url: string): Promise<void>;
25
+ sendMessage(text: string): Promise<void>;
26
+ getAuthData(): Record<string, unknown>;
27
+ /**
28
+ * Clean up Telegram event listeners.
29
+ * Call this when the bridge is destroyed.
30
+ */
31
+ destroy(): void;
32
+ private buildHostContext;
33
+ private buildStyles;
34
+ private buildSafeAreaInsets;
35
+ private getLocale;
36
+ private getTimeZone;
37
+ private setupEventListeners;
38
+ private emitLifecycleEvent;
39
+ }
40
+ //# sourceMappingURL=platform-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/telegram/platform-adapter.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EAIZ,MAAM,qBAAqB,CAAC;AAI7B;;;;;;;;GAQG;AACH,qBAAa,uBAAwB,YAAW,eAAe;IAC7D,QAAQ,CAAC,IAAI,aAAuB;IAEpC,OAAO,CAAC,EAAE,CAA+B;IACzC,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,qBAAqB,CAA6B;IAC1D,OAAO,CAAC,uBAAuB,CAA6B;IAE5D,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC;IAiBlC,QAAQ,IAAI,OAAO,GAAG,MAAM;IAO5B,sBAAsB,IAAI,mBAAmB;IAY7C,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAItD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxC,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAYtC;;;OAGG;IACH,OAAO,IAAI,IAAI;IAuBf,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,WAAW;IA2CnB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,mBAAmB;IAyB3B,OAAO,CAAC,kBAAkB;CAK3B"}