@vkma.dev/bridge 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +83 -2
- package/dist/bridge.d.ts +38 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +384 -0
- package/dist/bridge.js.map +1 -0
- package/dist/deprecated.d.ts +47 -0
- package/dist/deprecated.d.ts.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/launch-params.d.ts +25 -0
- package/dist/launch-params.d.ts.map +1 -0
- package/dist/launch-params.js +91 -0
- package/dist/launch-params.js.map +1 -0
- package/dist/middleware.d.ts +25 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +31 -0
- package/dist/middleware.js.map +1 -0
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/tap.d.ts +35 -0
- package/dist/tap.d.ts.map +1 -0
- package/dist/tap.js +39 -0
- package/dist/tap.js.map +1 -0
- package/dist/types.d.ts +214 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +42 -3
- package/src/bridge.ts +594 -0
- package/src/deprecated.ts +61 -0
- package/src/index.ts +130 -0
- package/src/launch-params.ts +117 -0
- package/src/middleware.ts +70 -0
- package/src/tap.ts +77 -0
- package/src/types.ts +271 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pajecawav
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,84 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @vkma.dev/bridge
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Independent VK Bridge for VK Mini Apps. Drop-in classic API (`send` / `subscribe` / `supportsAsync` / …) plus a built-in observability tap, per-send timeout/abort and a configurable `request_id` policy.
|
|
4
|
+
|
|
5
|
+
Types come from [`@vkma.dev/bridge-schema`](../bridge-schema) — the catalogue of every platform event as data, with an open interface for your own events.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @vkma.dev/bridge
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Use
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import bridge from "@vkma.dev/bridge";
|
|
17
|
+
|
|
18
|
+
await bridge.send("VKWebAppInit");
|
|
19
|
+
const user = await bridge.send("VKWebAppGetUserInfo");
|
|
20
|
+
|
|
21
|
+
bridge.subscribe(event => {
|
|
22
|
+
// event.detail.type / event.detail.data — every event from the host
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or build isolated instances (own tap, own pairing state):
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { createVKBridge } from "@vkma.dev/bridge";
|
|
30
|
+
|
|
31
|
+
const bridge = createVKBridge(version, {
|
|
32
|
+
requestId: { generator: sequence => `req-${sequence}` },
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Beyond the classic API
|
|
37
|
+
|
|
38
|
+
Everything lives on the instance — no extra imports:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// Every outgoing send / incoming event, always on, replayed to late subscribers
|
|
42
|
+
const off = bridge.onSend(event => log(event.name, event.payload));
|
|
43
|
+
const off2 = bridge.onEvent(event => log(event.name, event.ok));
|
|
44
|
+
|
|
45
|
+
// Per-send controls
|
|
46
|
+
await bridge.send("VKWebAppGetUserInfo", undefined, { timeout: 5000 });
|
|
47
|
+
await bridge.send("VKWebAppShowWallPostBox", props, { signal: controller.signal });
|
|
48
|
+
|
|
49
|
+
// request_id policy (default: auto-inject __vkma_<n>, that's what pairing uses)
|
|
50
|
+
createVKBridge(version, { requestId: { inject: false } });
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The page-wide default instance also publishes the devtools handle on `globalThis.__vkmaDevtoolsBridge` (`{ tap, send }`) — that's the contract the [VKMA devtools](../devtools) collector observes. Importing the package is enough; no opt-in.
|
|
54
|
+
|
|
55
|
+
## Types & custom events
|
|
56
|
+
|
|
57
|
+
All payload types and the three catalogue maps are re-exported here. To teach the bridge your own (or your proxy backend's) events, extend the schema package — `send`, `subscribe` and every consumer of the types pick it up:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
declare module "@vkma.dev/bridge-schema" {
|
|
61
|
+
interface RequestPropsMap {
|
|
62
|
+
VKWebAppMyCustomMethod: { foo: string };
|
|
63
|
+
}
|
|
64
|
+
interface ReceiveDataMap {
|
|
65
|
+
VKWebAppMyCustomMethodResult: { bar: number };
|
|
66
|
+
}
|
|
67
|
+
interface ReceiveEventMap {
|
|
68
|
+
VKWebAppMyCustomMethod: {
|
|
69
|
+
result: "VKWebAppMyCustomMethodResult";
|
|
70
|
+
failed: "VKWebAppMyCustomMethodFailed";
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
See [`@vkma.dev/bridge-schema`](../bridge-schema) for the rules (augment the schema package root; extend only, no overrides).
|
|
77
|
+
|
|
78
|
+
## Transports
|
|
79
|
+
|
|
80
|
+
Web (iframe `postMessage` with the `vk-connect` envelope), Android WebView, iOS WebView and React Native WebView — with receive-side `message` / `VKWebAppEvent` listeners to match. Web hosts are exercised by the unit suite and the playground e2e; the mobile WebView transports follow the platform contracts and deserve a manual pass on a real device before a release (see `AGENTS.md` at the repo root).
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT.
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { BridgeTap } from "./tap.js";
|
|
2
|
+
import { VkmaBridge } from "./types.js";
|
|
3
|
+
//#region src/bridge.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* request_id policy of a bridge instance.
|
|
6
|
+
*/
|
|
7
|
+
export interface RequestIdPolicy {
|
|
8
|
+
/**
|
|
9
|
+
* Own generator of outgoing request ids; receives an incrementing
|
|
10
|
+
* sequence. The default mints `__vkma_<n>` — the ids the devtools tap
|
|
11
|
+
* pairs responses by.
|
|
12
|
+
*/
|
|
13
|
+
generator?: (sequence: number) => string | number;
|
|
14
|
+
/**
|
|
15
|
+
* Turn the auto-injection off: sends pass caller props untouched, so
|
|
16
|
+
* promise pairing only works for calls that provide their own
|
|
17
|
+
* `request_id`. Default: on.
|
|
18
|
+
*/
|
|
19
|
+
inject?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface VkmaBridgeOptions {
|
|
22
|
+
/** Outgoing request_id policy. */
|
|
23
|
+
requestId?: RequestIdPolicy;
|
|
24
|
+
/** Inject a shared tap (the default instance passes the page-wide one). */
|
|
25
|
+
tap?: BridgeTap;
|
|
26
|
+
/** Version string reported to the web host in the vk-connect envelope. */
|
|
27
|
+
version?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a VK Bridge instance: transport dispatch, subscription fan-out,
|
|
31
|
+
* promise pairing and the always-on tap.
|
|
32
|
+
*
|
|
33
|
+
* @param version Version of the package (reported to the web host).
|
|
34
|
+
* @param [options] Tap sharing and the request_id policy.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createVKBridge(version: string, options?: VkmaBridgeOptions): VkmaBridge;
|
|
37
|
+
//#endregion
|
|
38
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","names":[],"sources":["../src/bridge.ts"],"mappings":";;;;;;iBA6JiB;;;;;;EAMhB,aAAa;;;;;;EAMb;;iBAGgB;;EAEhB,YAAY;;EAEZ,MAAM;;EAEN;;;;;;;;;wBAkBe,eAAe,iBAAiB,UAAS,oBAAyB"}
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { createTap } from "./tap.js";
|
|
2
|
+
//#region src/bridge.ts
|
|
3
|
+
/**
|
|
4
|
+
* The bridge core: transport dispatch, subscription fan-out, promise pairing
|
|
5
|
+
* and the always-on tap.
|
|
6
|
+
*
|
|
7
|
+
* Transports (checked lazily on every call, unlike the load-time caches of
|
|
8
|
+
* the reference implementation — same in practice, testable in unit tests):
|
|
9
|
+
*
|
|
10
|
+
* - Android WebView: `window.AndroidBridge[method](JSON.stringify(props))`
|
|
11
|
+
* - iOS WebView: `window.webkit.messageHandlers[method].postMessage(props)`
|
|
12
|
+
* - React Native WebView: `window.ReactNativeWebView.postMessage(JSON)`
|
|
13
|
+
* - Web (iframe on vk.ru / m.vk.ru): `parent.postMessage` with the
|
|
14
|
+
* `type: "vk-connect"` envelope; receive side listens to `message`
|
|
15
|
+
* - WebViews receive via `CustomEvent("VKWebAppEvent")`
|
|
16
|
+
*
|
|
17
|
+
* The wire format is the platform interface — the host clients on the other
|
|
18
|
+
* side of these bridges define it, which is why the envelopes above are
|
|
19
|
+
* reproduced exactly.
|
|
20
|
+
*/
|
|
21
|
+
/** Methods supported on the desktop web hosts. */
|
|
22
|
+
const DESKTOP_METHODS = /* @__PURE__ */ new Set([
|
|
23
|
+
"VKWebAppInit",
|
|
24
|
+
"VKWebAppGetCommunityAuthToken",
|
|
25
|
+
"VKWebAppAddToCommunity",
|
|
26
|
+
"VKWebAppAddToHomeScreenInfo",
|
|
27
|
+
"VKWebAppClose",
|
|
28
|
+
"VKWebAppCopyText",
|
|
29
|
+
"VKWebAppCreateHash",
|
|
30
|
+
"VKWebAppGetUserInfo",
|
|
31
|
+
"VKWebAppSetLocation",
|
|
32
|
+
"VKWebAppSendToClient",
|
|
33
|
+
"VKWebAppGetClientVersion",
|
|
34
|
+
"VKWebAppGetPhoneNumber",
|
|
35
|
+
"VKWebAppGetEmail",
|
|
36
|
+
"VKWebAppGetGroupInfo",
|
|
37
|
+
"VKWebAppGetGeodata",
|
|
38
|
+
"VKWebAppGetCommunityToken",
|
|
39
|
+
"VKWebAppGetConfig",
|
|
40
|
+
"VKWebAppGetLaunchParams",
|
|
41
|
+
"VKWebAppSetTitle",
|
|
42
|
+
"VKWebAppGetAuthToken",
|
|
43
|
+
"VKWebAppCallAPIMethod",
|
|
44
|
+
"VKWebAppJoinGroup",
|
|
45
|
+
"VKWebAppLeaveGroup",
|
|
46
|
+
"VKWebAppAllowMessagesFromGroup",
|
|
47
|
+
"VKWebAppDenyNotifications",
|
|
48
|
+
"VKWebAppAllowNotifications",
|
|
49
|
+
"VKWebAppOpenPayForm",
|
|
50
|
+
"VKWebAppOpenApp",
|
|
51
|
+
"VKWebAppShare",
|
|
52
|
+
"VKWebAppShowWallPostBox",
|
|
53
|
+
"VKWebAppScroll",
|
|
54
|
+
"VKWebAppShowOrderBox",
|
|
55
|
+
"VKWebAppShowLeaderBoardBox",
|
|
56
|
+
"VKWebAppShowInviteBox",
|
|
57
|
+
"VKWebAppShowRequestBox",
|
|
58
|
+
"VKWebAppAddToFavorites",
|
|
59
|
+
"VKWebAppShowStoryBox",
|
|
60
|
+
"VKWebAppStorageGet",
|
|
61
|
+
"VKWebAppStorageGetKeys",
|
|
62
|
+
"VKWebAppStorageSet",
|
|
63
|
+
"VKWebAppFlashGetInfo",
|
|
64
|
+
"VKWebAppSubscribeStoryApp",
|
|
65
|
+
"VKWebAppOpenWallPost",
|
|
66
|
+
"VKWebAppCheckAllowedScopes",
|
|
67
|
+
"VKWebAppCheckBannerAd",
|
|
68
|
+
"VKWebAppHideBannerAd",
|
|
69
|
+
"VKWebAppShowBannerAd",
|
|
70
|
+
"VKWebAppCheckNativeAds",
|
|
71
|
+
"VKWebAppShowNativeAds",
|
|
72
|
+
"VKWebAppRetargetingPixel",
|
|
73
|
+
"VKWebAppConversionHit",
|
|
74
|
+
"VKWebAppShowSubscriptionBox",
|
|
75
|
+
"VKWebAppCheckSurvey",
|
|
76
|
+
"VKWebAppShowSurvey",
|
|
77
|
+
"VKWebAppScrollTop",
|
|
78
|
+
"VKWebAppScrollTopStart",
|
|
79
|
+
"VKWebAppScrollTopStop",
|
|
80
|
+
"VKWebAppShowSlidesSheet",
|
|
81
|
+
"VKWebAppTranslate",
|
|
82
|
+
"VKWebAppRecommend",
|
|
83
|
+
"VKWebAppAddToProfile",
|
|
84
|
+
"VKWebAppGetFriends",
|
|
85
|
+
...isDesktopVk() ? [
|
|
86
|
+
"VKWebAppResizeWindow",
|
|
87
|
+
"VKWebAppAddToMenu",
|
|
88
|
+
"VKWebAppShowInstallPushBox",
|
|
89
|
+
"VKWebAppShowCommunityWidgetPreviewBox",
|
|
90
|
+
"VKWebAppCallStart",
|
|
91
|
+
"VKWebAppCallJoin",
|
|
92
|
+
"VKWebAppCallGetStatus"
|
|
93
|
+
] : ["VKWebAppShowImages"]
|
|
94
|
+
]);
|
|
95
|
+
function clientWindow() {
|
|
96
|
+
return typeof window === "undefined" ? void 0 : window;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The native side of the host (AndroidBridge / webkit / ReactNativeWebView)
|
|
100
|
+
* lives on the window but is not part of any DOM typing — tests install
|
|
101
|
+
* fakes under the same keys.
|
|
102
|
+
*/
|
|
103
|
+
function hostGlobal() {
|
|
104
|
+
const win = clientWindow();
|
|
105
|
+
return win === void 0 ? void 0 : win;
|
|
106
|
+
}
|
|
107
|
+
function isClientSide() {
|
|
108
|
+
return typeof window !== "undefined";
|
|
109
|
+
}
|
|
110
|
+
function isAndroidWebview() {
|
|
111
|
+
return Boolean(hostGlobal()?.["AndroidBridge"]);
|
|
112
|
+
}
|
|
113
|
+
function isIosWebview() {
|
|
114
|
+
const webkit = hostGlobal()?.["webkit"];
|
|
115
|
+
return Boolean(webkit?.messageHandlers?.["VKWebAppClose"]);
|
|
116
|
+
}
|
|
117
|
+
function isReactNativeWebview() {
|
|
118
|
+
const reactNative = hostGlobal()?.["ReactNativeWebView"];
|
|
119
|
+
return Boolean(reactNative && typeof reactNative.postMessage === "function");
|
|
120
|
+
}
|
|
121
|
+
function isWeb() {
|
|
122
|
+
return isClientSide() && !isAndroidWebview() && !isIosWebview();
|
|
123
|
+
}
|
|
124
|
+
function isMvk() {
|
|
125
|
+
return isWeb() && /(^\?|&)vk_platform=mobile_web(&|$)/.test(clientWindow()?.location.search ?? "");
|
|
126
|
+
}
|
|
127
|
+
function isDesktopVk() {
|
|
128
|
+
return isWeb() && !isMvk();
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Creates a VK Bridge instance: transport dispatch, subscription fan-out,
|
|
132
|
+
* promise pairing and the always-on tap.
|
|
133
|
+
*
|
|
134
|
+
* @param version Version of the package (reported to the web host).
|
|
135
|
+
* @param [options] Tap sharing and the request_id policy.
|
|
136
|
+
*/
|
|
137
|
+
function createVKBridge(version, options = {}) {
|
|
138
|
+
const tap = options.tap ?? createTap();
|
|
139
|
+
const requestIdPolicy = options.requestId ?? {};
|
|
140
|
+
/** Current frame id, assigned by the host via VKWebAppSettings. */
|
|
141
|
+
let webFrameId;
|
|
142
|
+
/** Functions subscribed to bridge events. */
|
|
143
|
+
const subscribers = [];
|
|
144
|
+
/** Pending promise controllers by outgoing request_id. */
|
|
145
|
+
const pendingRequests = /* @__PURE__ */ new Map();
|
|
146
|
+
let requestCounter = 0;
|
|
147
|
+
let supportedHandlers;
|
|
148
|
+
const isPlainObject = (value) => typeof value === "object" && value !== null;
|
|
149
|
+
function sendThroughTransport(method, props) {
|
|
150
|
+
const host = hostGlobal();
|
|
151
|
+
const android = host?.["AndroidBridge"];
|
|
152
|
+
if (typeof android?.[method] === "function") {
|
|
153
|
+
android[method](JSON.stringify(props));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const iosHandlers = (host?.["webkit"])?.messageHandlers;
|
|
157
|
+
if (typeof iosHandlers?.[method]?.postMessage === "function") {
|
|
158
|
+
iosHandlers[method].postMessage(props);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (isReactNativeWebview()) {
|
|
162
|
+
(host?.["ReactNativeWebView"]).postMessage(JSON.stringify({
|
|
163
|
+
handler: method,
|
|
164
|
+
params: props
|
|
165
|
+
}));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const win = clientWindow();
|
|
169
|
+
const parent = win?.parent;
|
|
170
|
+
if (win && parent && typeof parent.postMessage === "function") parent.postMessage({
|
|
171
|
+
handler: method,
|
|
172
|
+
params: props,
|
|
173
|
+
type: "vk-connect",
|
|
174
|
+
webFrameId,
|
|
175
|
+
connectVersion: version
|
|
176
|
+
}, "*");
|
|
177
|
+
}
|
|
178
|
+
function handleEvent(event) {
|
|
179
|
+
if (isIosWebview() || isAndroidWebview()) {
|
|
180
|
+
deliver(event);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
let bridgeEventData = event?.data;
|
|
184
|
+
if (!isWeb() || !bridgeEventData) return;
|
|
185
|
+
if (isReactNativeWebview() && typeof bridgeEventData === "string") try {
|
|
186
|
+
bridgeEventData = JSON.parse(bridgeEventData);
|
|
187
|
+
} catch {}
|
|
188
|
+
if (!isPlainObject(bridgeEventData)) return;
|
|
189
|
+
const { type, data, frameId } = bridgeEventData;
|
|
190
|
+
if (!type) return;
|
|
191
|
+
if (type === "VKWebAppSettings") {
|
|
192
|
+
webFrameId = typeof frameId === "string" ? frameId : webFrameId;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
deliver({ detail: {
|
|
196
|
+
type,
|
|
197
|
+
data
|
|
198
|
+
} });
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Upstream parity: every incoming event reaches `[...subscribers]` —
|
|
202
|
+
* paired responses included, with the raw wire data (upstream's
|
|
203
|
+
* promisifySend is itself a subscriber and strips request_id only for
|
|
204
|
+
* the promise). Snapshot iteration: a handler may unsubscribe mid-fan.
|
|
205
|
+
*/
|
|
206
|
+
function fanOutToSubscribers(type, data) {
|
|
207
|
+
const out = { detail: {
|
|
208
|
+
type,
|
|
209
|
+
data
|
|
210
|
+
} };
|
|
211
|
+
for (const listener of subscribers.slice()) listener(out);
|
|
212
|
+
}
|
|
213
|
+
/** Fan an incoming event out to the tap and to the subscribers. */
|
|
214
|
+
function deliver(event) {
|
|
215
|
+
const { type, data } = event.detail ?? {};
|
|
216
|
+
if (typeof type !== "string") return;
|
|
217
|
+
if (isPlainObject(data)) {
|
|
218
|
+
const wireRequestId = data["request_id"];
|
|
219
|
+
if (typeof wireRequestId !== "string" && typeof wireRequestId !== "number") {
|
|
220
|
+
tap.emit({
|
|
221
|
+
direction: "in",
|
|
222
|
+
kind: "event",
|
|
223
|
+
name: type,
|
|
224
|
+
payload: data
|
|
225
|
+
});
|
|
226
|
+
fanOutToSubscribers(type, data);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const requestId = String(wireRequestId);
|
|
230
|
+
const pending = pendingRequests.get(requestId);
|
|
231
|
+
if (pending) {
|
|
232
|
+
pendingRequests.delete(requestId);
|
|
233
|
+
const { request_id: _stripped, ...payload } = data;
|
|
234
|
+
const ok = !("error_type" in data);
|
|
235
|
+
pending.cleanup();
|
|
236
|
+
tap.emit({
|
|
237
|
+
direction: "in",
|
|
238
|
+
kind: "response",
|
|
239
|
+
name: type,
|
|
240
|
+
payload,
|
|
241
|
+
reqId: pending.tapId,
|
|
242
|
+
ok
|
|
243
|
+
});
|
|
244
|
+
if (ok) pending.resolve(payload);
|
|
245
|
+
else pending.reject(payload);
|
|
246
|
+
fanOutToSubscribers(type, data);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
tap.emit({
|
|
251
|
+
direction: "in",
|
|
252
|
+
kind: "event",
|
|
253
|
+
name: type,
|
|
254
|
+
payload: data
|
|
255
|
+
});
|
|
256
|
+
fanOutToSubscribers(type, data);
|
|
257
|
+
}
|
|
258
|
+
function subscribe(listener) {
|
|
259
|
+
subscribers.push(listener);
|
|
260
|
+
}
|
|
261
|
+
function unsubscribe(listener) {
|
|
262
|
+
const index = subscribers.indexOf(listener);
|
|
263
|
+
if (index > -1) subscribers.splice(index, 1);
|
|
264
|
+
}
|
|
265
|
+
if (isClientSide()) {
|
|
266
|
+
const win = clientWindow();
|
|
267
|
+
if (isReactNativeWebview() && /(android)/i.test(win?.navigator.userAgent ?? "")) document.addEventListener("message", handleEvent);
|
|
268
|
+
else if (win && "addEventListener" in win) win.addEventListener(isWeb() ? "message" : "VKWebAppEvent", handleEvent);
|
|
269
|
+
}
|
|
270
|
+
const send = ((method, props, sendOptions) => {
|
|
271
|
+
return new Promise((resolve, reject) => {
|
|
272
|
+
const signal = sendOptions?.signal;
|
|
273
|
+
if (signal?.aborted) {
|
|
274
|
+
const error = /* @__PURE__ */ new Error(`VK Bridge send "${method}" aborted`);
|
|
275
|
+
error.name = "AbortError";
|
|
276
|
+
reject(error);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const sourceProps = { ...props };
|
|
280
|
+
const explicitId = typeof sourceProps["request_id"] === "string" || typeof sourceProps["request_id"] === "number" ? sourceProps["request_id"] : void 0;
|
|
281
|
+
let requestId;
|
|
282
|
+
if (explicitId !== void 0) requestId = explicitId;
|
|
283
|
+
else if (requestIdPolicy.inject !== false) {
|
|
284
|
+
const sequence = ++requestCounter;
|
|
285
|
+
requestId = requestIdPolicy.generator ? requestIdPolicy.generator(sequence) : `__vkma_${sequence}`;
|
|
286
|
+
}
|
|
287
|
+
const wireProps = requestId === void 0 ? sourceProps : {
|
|
288
|
+
...sourceProps,
|
|
289
|
+
request_id: requestId
|
|
290
|
+
};
|
|
291
|
+
const tapId = tap.emit({
|
|
292
|
+
direction: "out",
|
|
293
|
+
kind: "send",
|
|
294
|
+
name: method,
|
|
295
|
+
payload: wireProps
|
|
296
|
+
});
|
|
297
|
+
let timer;
|
|
298
|
+
let signalHandler;
|
|
299
|
+
const cleanup = () => {
|
|
300
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
301
|
+
if (signal && signalHandler) signal.removeEventListener("abort", signalHandler);
|
|
302
|
+
};
|
|
303
|
+
const timeoutReject = () => {
|
|
304
|
+
if (requestId !== void 0 && !pendingRequests.delete(String(requestId))) return;
|
|
305
|
+
cleanup();
|
|
306
|
+
const error = /* @__PURE__ */ new Error(`VK Bridge send "${method}" timed out after ${String(sendOptions?.timeout)}ms`);
|
|
307
|
+
error.name = "TimeoutError";
|
|
308
|
+
reject(error);
|
|
309
|
+
};
|
|
310
|
+
const abortReject = () => {
|
|
311
|
+
if (requestId !== void 0 && !pendingRequests.delete(String(requestId))) return;
|
|
312
|
+
cleanup();
|
|
313
|
+
const error = /* @__PURE__ */ new Error(`VK Bridge send "${method}" aborted`);
|
|
314
|
+
error.name = "AbortError";
|
|
315
|
+
reject(error);
|
|
316
|
+
};
|
|
317
|
+
if (requestId !== void 0) pendingRequests.set(String(requestId), {
|
|
318
|
+
resolve,
|
|
319
|
+
reject,
|
|
320
|
+
tapId,
|
|
321
|
+
options: sendOptions ?? {},
|
|
322
|
+
cleanup
|
|
323
|
+
});
|
|
324
|
+
if (sendOptions?.timeout !== void 0) timer = setTimeout(timeoutReject, sendOptions.timeout);
|
|
325
|
+
if (signal) {
|
|
326
|
+
signalHandler = abortReject;
|
|
327
|
+
signal.addEventListener("abort", signalHandler);
|
|
328
|
+
}
|
|
329
|
+
sendThroughTransport(method, wireProps);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
subscribe((event) => {
|
|
333
|
+
if (event.detail?.type === "SetSupportedHandlers" && isPlainObject(event.detail.data)) {
|
|
334
|
+
const handlers = event.detail.data.supportedHandlers;
|
|
335
|
+
if (Array.isArray(handlers)) supportedHandlers = new Set(handlers.filter((name) => typeof name === "string"));
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
function supportsInner(method) {
|
|
339
|
+
if (isAndroidWebview()) return typeof (hostGlobal()?.["AndroidBridge"])?.[method] === "function";
|
|
340
|
+
if (isIosWebview()) return typeof ((hostGlobal()?.["webkit"])?.messageHandlers)?.[method]?.postMessage === "function";
|
|
341
|
+
if (isWeb()) return DESKTOP_METHODS.has(method);
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
const bridge = {
|
|
345
|
+
send,
|
|
346
|
+
sendPromise: send,
|
|
347
|
+
subscribe,
|
|
348
|
+
unsubscribe,
|
|
349
|
+
supports: (method) => {
|
|
350
|
+
console.warn("bridge.supports method is deprecated. Use bridge.supportsAsync instead.");
|
|
351
|
+
return supportsInner(method);
|
|
352
|
+
},
|
|
353
|
+
supportsAsync: async (method) => {
|
|
354
|
+
if (isAndroidWebview() || isIosWebview()) return supportsInner(method);
|
|
355
|
+
if (supportedHandlers) return supportedHandlers.has(method);
|
|
356
|
+
try {
|
|
357
|
+
const response = await send("SetSupportedHandlers");
|
|
358
|
+
supportedHandlers = new Set(response.supportedHandlers ?? ["VKWebAppInit"]);
|
|
359
|
+
} catch {
|
|
360
|
+
supportedHandlers = /* @__PURE__ */ new Set(["VKWebAppInit"]);
|
|
361
|
+
}
|
|
362
|
+
return supportedHandlers.has(method);
|
|
363
|
+
},
|
|
364
|
+
isWebView: () => isIosWebview() || isAndroidWebview(),
|
|
365
|
+
isIframe: () => {
|
|
366
|
+
const win = clientWindow();
|
|
367
|
+
return Boolean(win && win.parent !== win);
|
|
368
|
+
},
|
|
369
|
+
isEmbedded: () => bridge.isWebView() || bridge.isIframe(),
|
|
370
|
+
isStandalone: () => !bridge.isEmbedded(),
|
|
371
|
+
tap,
|
|
372
|
+
onSend: (listener) => tap.subscribe((event) => {
|
|
373
|
+
if (event.direction === "out") listener(event);
|
|
374
|
+
}),
|
|
375
|
+
onEvent: (listener) => tap.subscribe((event) => {
|
|
376
|
+
if (event.direction === "in") listener(event);
|
|
377
|
+
})
|
|
378
|
+
};
|
|
379
|
+
return bridge;
|
|
380
|
+
}
|
|
381
|
+
//#endregion
|
|
382
|
+
export { createVKBridge, isAndroidWebview, isClientSide, isDesktopVk, isIosWebview, isMvk, isReactNativeWebview, isWeb };
|
|
383
|
+
|
|
384
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","names":[],"sources":["../src/bridge.ts"],"sourcesContent":["/**\n * The bridge core: transport dispatch, subscription fan-out, promise pairing\n * and the always-on tap.\n *\n * Transports (checked lazily on every call, unlike the load-time caches of\n * the reference implementation — same in practice, testable in unit tests):\n *\n * - Android WebView: `window.AndroidBridge[method](JSON.stringify(props))`\n * - iOS WebView: `window.webkit.messageHandlers[method].postMessage(props)`\n * - React Native WebView: `window.ReactNativeWebView.postMessage(JSON)`\n * - Web (iframe on vk.ru / m.vk.ru): `parent.postMessage` with the\n * `type: \"vk-connect\"` envelope; receive side listens to `message`\n * - WebViews receive via `CustomEvent(\"VKWebAppEvent\")`\n *\n * The wire format is the platform interface — the host clients on the other\n * side of these bridges define it, which is why the envelopes above are\n * reproduced exactly.\n */\n\nimport { createTap, type BridgeTap, type BridgeTapEvent } from \"./tap.ts\";\nimport type { SendOptions, VKBridgeSend, VKBridgeSubscribeHandler, VkmaBridge } from \"./types.ts\";\n\n/** Methods supported on the desktop web hosts. */\nconst DESKTOP_METHODS = new Set([\n\t\"VKWebAppInit\",\n\t\"VKWebAppGetCommunityAuthToken\",\n\t\"VKWebAppAddToCommunity\",\n\t\"VKWebAppAddToHomeScreenInfo\",\n\t\"VKWebAppClose\",\n\t\"VKWebAppCopyText\",\n\t\"VKWebAppCreateHash\",\n\t\"VKWebAppGetUserInfo\",\n\t\"VKWebAppSetLocation\",\n\t\"VKWebAppSendToClient\",\n\t\"VKWebAppGetClientVersion\",\n\t\"VKWebAppGetPhoneNumber\",\n\t\"VKWebAppGetEmail\",\n\t\"VKWebAppGetGroupInfo\",\n\t\"VKWebAppGetGeodata\",\n\t\"VKWebAppGetCommunityToken\",\n\t\"VKWebAppGetConfig\",\n\t\"VKWebAppGetLaunchParams\",\n\t\"VKWebAppSetTitle\",\n\t\"VKWebAppGetAuthToken\",\n\t\"VKWebAppCallAPIMethod\",\n\t\"VKWebAppJoinGroup\",\n\t\"VKWebAppLeaveGroup\",\n\t\"VKWebAppAllowMessagesFromGroup\",\n\t\"VKWebAppDenyNotifications\",\n\t\"VKWebAppAllowNotifications\",\n\t\"VKWebAppOpenPayForm\",\n\t\"VKWebAppOpenApp\",\n\t\"VKWebAppShare\",\n\t\"VKWebAppShowWallPostBox\",\n\t\"VKWebAppScroll\",\n\t\"VKWebAppShowOrderBox\",\n\t\"VKWebAppShowLeaderBoardBox\",\n\t\"VKWebAppShowInviteBox\",\n\t\"VKWebAppShowRequestBox\",\n\t\"VKWebAppAddToFavorites\",\n\t\"VKWebAppShowStoryBox\",\n\t\"VKWebAppStorageGet\",\n\t\"VKWebAppStorageGetKeys\",\n\t\"VKWebAppStorageSet\",\n\t\"VKWebAppFlashGetInfo\",\n\t\"VKWebAppSubscribeStoryApp\",\n\t\"VKWebAppOpenWallPost\",\n\t\"VKWebAppCheckAllowedScopes\",\n\t\"VKWebAppCheckBannerAd\",\n\t\"VKWebAppHideBannerAd\",\n\t\"VKWebAppShowBannerAd\",\n\t\"VKWebAppCheckNativeAds\",\n\t\"VKWebAppShowNativeAds\",\n\t\"VKWebAppRetargetingPixel\",\n\t\"VKWebAppConversionHit\",\n\t\"VKWebAppShowSubscriptionBox\",\n\t\"VKWebAppCheckSurvey\",\n\t\"VKWebAppShowSurvey\",\n\t\"VKWebAppScrollTop\",\n\t\"VKWebAppScrollTopStart\",\n\t\"VKWebAppScrollTopStop\",\n\t\"VKWebAppShowSlidesSheet\",\n\t\"VKWebAppTranslate\",\n\t\"VKWebAppRecommend\",\n\t\"VKWebAppAddToProfile\",\n\t\"VKWebAppGetFriends\",\n\t// Desktop web specific events\n\t...(isDesktopVk()\n\t\t? [\n\t\t\t\t\"VKWebAppResizeWindow\",\n\t\t\t\t\"VKWebAppAddToMenu\",\n\t\t\t\t\"VKWebAppShowInstallPushBox\",\n\t\t\t\t\"VKWebAppShowCommunityWidgetPreviewBox\",\n\t\t\t\t\"VKWebAppCallStart\",\n\t\t\t\t\"VKWebAppCallJoin\",\n\t\t\t\t\"VKWebAppCallGetStatus\",\n\t\t\t]\n\t\t: [\"VKWebAppShowImages\"]),\n]);\n\n// ------------------------------------------------------------- environment\n\nfunction clientWindow(): (Window & typeof globalThis) | undefined {\n\treturn typeof window === \"undefined\" ? undefined : window;\n}\n\n/**\n * The native side of the host (AndroidBridge / webkit / ReactNativeWebView)\n * lives on the window but is not part of any DOM typing — tests install\n * fakes under the same keys.\n */\nfunction hostGlobal(): Record<string, unknown> | undefined {\n\tconst win = clientWindow();\n\treturn win === undefined ? undefined : (win as unknown as Record<string, unknown>);\n}\n\nexport function isClientSide(): boolean {\n\treturn typeof window !== \"undefined\";\n}\n\nexport function isAndroidWebview(): boolean {\n\treturn Boolean(hostGlobal()?.[\"AndroidBridge\"]);\n}\n\nexport function isIosWebview(): boolean {\n\tconst webkit = hostGlobal()?.[\"webkit\"] as\n\t\t| { messageHandlers?: Record<string, { postMessage?: unknown }> }\n\t\t| undefined;\n\treturn Boolean(webkit?.messageHandlers?.[\"VKWebAppClose\"]);\n}\n\nexport function isReactNativeWebview(): boolean {\n\tconst reactNative = hostGlobal()?.[\"ReactNativeWebView\"] as\n\t\t| { postMessage?: unknown }\n\t\t| undefined;\n\treturn Boolean(reactNative && typeof reactNative.postMessage === \"function\");\n}\n\nexport function isWeb(): boolean {\n\treturn isClientSide() && !isAndroidWebview() && !isIosWebview();\n}\n\nexport function isMvk(): boolean {\n\treturn (\n\t\tisWeb() && /(^\\?|&)vk_platform=mobile_web(&|$)/.test(clientWindow()?.location.search ?? \"\")\n\t);\n}\n\nexport function isDesktopVk(): boolean {\n\treturn isWeb() && !isMvk();\n}\n\n// -------------------------------------------------------------- the bridge\n\n/**\n * request_id policy of a bridge instance.\n */\nexport interface RequestIdPolicy {\n\t/**\n\t * Own generator of outgoing request ids; receives an incrementing\n\t * sequence. The default mints `__vkma_<n>` — the ids the devtools tap\n\t * pairs responses by.\n\t */\n\tgenerator?: (sequence: number) => string | number;\n\t/**\n\t * Turn the auto-injection off: sends pass caller props untouched, so\n\t * promise pairing only works for calls that provide their own\n\t * `request_id`. Default: on.\n\t */\n\tinject?: boolean;\n}\n\nexport interface VkmaBridgeOptions {\n\t/** Outgoing request_id policy. */\n\trequestId?: RequestIdPolicy;\n\t/** Inject a shared tap (the default instance passes the page-wide one). */\n\ttap?: BridgeTap;\n\t/** Version string reported to the web host in the vk-connect envelope. */\n\tversion?: string;\n}\n\ninterface PendingRequest {\n\tresolve: (value: unknown) => void;\n\treject: (reason: unknown) => void;\n\ttapId: number;\n\toptions: SendOptions;\n\tcleanup: () => void;\n}\n\n/**\n * Creates a VK Bridge instance: transport dispatch, subscription fan-out,\n * promise pairing and the always-on tap.\n *\n * @param version Version of the package (reported to the web host).\n * @param [options] Tap sharing and the request_id policy.\n */\nexport function createVKBridge(version: string, options: VkmaBridgeOptions = {}): VkmaBridge {\n\tconst tap = options.tap ?? createTap();\n\tconst requestIdPolicy = options.requestId ?? {};\n\n\t/** Current frame id, assigned by the host via VKWebAppSettings. */\n\tlet webFrameId: string | undefined;\n\n\t/** Functions subscribed to bridge events. */\n\tconst subscribers: VKBridgeSubscribeHandler[] = [];\n\n\t/** Pending promise controllers by outgoing request_id. */\n\tconst pendingRequests = new Map<string, PendingRequest>();\n\n\tlet requestCounter = 0;\n\tlet supportedHandlers: Set<string> | undefined;\n\n\tconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n\t\ttypeof value === \"object\" && value !== null;\n\n\t// ------------------------------------------------------------- transports\n\n\tfunction sendThroughTransport(method: string, props: Record<string, unknown>): void {\n\t\tconst host = hostGlobal();\n\t\tconst android = host?.[\"AndroidBridge\"] as\n\t\t\t| Record<string, ((serializedData: string) => void) | undefined>\n\t\t\t| undefined;\n\t\t// Sending data through the Android bridge\n\t\tif (typeof android?.[method] === \"function\") {\n\t\t\tandroid[method](JSON.stringify(props));\n\t\t\treturn;\n\t\t}\n\n\t\tconst iosHandlers = (\n\t\t\thost?.[\"webkit\"] as\n\t\t\t\t| { messageHandlers?: Record<string, { postMessage?: unknown }> }\n\t\t\t\t| undefined\n\t\t)?.messageHandlers;\n\t\t// Sending data through the iOS bridge\n\t\tif (typeof iosHandlers?.[method]?.postMessage === \"function\") {\n\t\t\t// Not a window.postMessage — the native handler takes no targetOrigin.\n\t\t\t// oxlint-disable-next-line unicorn/require-post-message-target-origin\n\t\t\t(iosHandlers[method].postMessage as (data: unknown) => void)(props);\n\t\t\treturn;\n\t\t}\n\n\t\t// Sending data through the React Native bridge\n\t\tif (isReactNativeWebview()) {\n\t\t\tconst reactNative = host?.[\"ReactNativeWebView\"] as {\n\t\t\t\tpostMessage: (data: string) => void;\n\t\t\t};\n\t\t\t// Not a window.postMessage — the RN handler takes no targetOrigin.\n\t\t\t// oxlint-disable-next-line unicorn/require-post-message-target-origin\n\t\t\treactNative.postMessage(JSON.stringify({ handler: method, params: props }));\n\t\t\treturn;\n\t\t}\n\n\t\t// Sending data through the web bridge (the parent frame)\n\t\tconst win = clientWindow();\n\t\tconst parent = win?.parent;\n\t\tif (win && parent && typeof parent.postMessage === \"function\") {\n\t\t\t// The mini app does not know the host origin ahead of time (vk.ru,\n\t\t\t// m.vk.ru, mobile clients) — \"*\" is the wire contract here.\n\t\t\t// oxlint-disable-next-line unicorn/require-post-message-target-origin\n\t\t\tparent.postMessage(\n\t\t\t\t{\n\t\t\t\t\thandler: method,\n\t\t\t\t\tparams: props,\n\t\t\t\t\ttype: \"vk-connect\",\n\t\t\t\t\twebFrameId,\n\t\t\t\t\tconnectVersion: version,\n\t\t\t\t},\n\t\t\t\t\"*\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// ------------------------------------------------------------- event intake\n\n\tfunction handleEvent(event: unknown): void {\n\t\tif (isIosWebview() || isAndroidWebview()) {\n\t\t\t// WebViews: the native layer dispatches ready-made events\n\t\t\tdeliver(event as { detail?: { type?: unknown; data?: unknown } });\n\t\t\treturn;\n\t\t}\n\n\t\tlet bridgeEventData = (event as { data?: unknown } | undefined)?.data;\n\t\tif (!isWeb() || !bridgeEventData) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (isReactNativeWebview() && typeof bridgeEventData === \"string\") {\n\t\t\ttry {\n\t\t\t\tbridgeEventData = JSON.parse(bridgeEventData) as unknown;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (!isPlainObject(bridgeEventData)) {\n\t\t\treturn;\n\t\t}\n\t\tconst { type, data, frameId } = bridgeEventData as {\n\t\t\ttype?: unknown;\n\t\t\tdata?: unknown;\n\t\t\tframeId?: unknown;\n\t\t};\n\t\tif (!type) {\n\t\t\treturn;\n\t\t}\n\n\t\t// The host assigns this iframe its frame id — internal protocol,\n\t\t// not delivered to subscribers.\n\t\tif (type === \"VKWebAppSettings\") {\n\t\t\twebFrameId = typeof frameId === \"string\" ? frameId : webFrameId;\n\t\t\treturn;\n\t\t}\n\n\t\tdeliver({ detail: { type, data } });\n\t}\n\n\t/**\n\t * Upstream parity: every incoming event reaches `[...subscribers]` —\n\t * paired responses included, with the raw wire data (upstream's\n\t * promisifySend is itself a subscriber and strips request_id only for\n\t * the promise). Snapshot iteration: a handler may unsubscribe mid-fan.\n\t */\n\tfunction fanOutToSubscribers(type: string, data: unknown): void {\n\t\t// The wire type is stringly here by design — handleEvent dispatches\n\t\t// arbitrary host envelopes; the public subscribe surface narrows it.\n\t\t// The slice is a snapshot: a handler may unsubscribe mid-fan-out,\n\t\t// and shifting live iteration would skip its neighbours (upstream\n\t\t// copies the array for the same reason).\n\t\tconst out = { detail: { type, data } } as Parameters<VKBridgeSubscribeHandler>[0];\n\t\tfor (const listener of subscribers.slice()) {\n\t\t\tlistener(out);\n\t\t}\n\t}\n\n\t/** Fan an incoming event out to the tap and to the subscribers. */\n\tfunction deliver(event: { detail?: { type?: unknown; data?: unknown } }): void {\n\t\tconst { type, data } = event.detail ?? {};\n\t\tif (typeof type !== \"string\") {\n\t\t\treturn;\n\t\t}\n\n\t\t// A payload carrying one of our pending request ids is the paired\n\t\t// response to a send; everything else is an unsolicited event.\n\t\t// The wire contract types request_id as a string or a number.\n\t\tif (isPlainObject(data)) {\n\t\t\tconst wireRequestId = data[\"request_id\"];\n\t\t\tif (typeof wireRequestId !== \"string\" && typeof wireRequestId !== \"number\") {\n\t\t\t\ttap.emit({ direction: \"in\", kind: \"event\", name: type, payload: data });\n\t\t\t\tfanOutToSubscribers(type, data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst requestId = String(wireRequestId);\n\t\t\tconst pending = pendingRequests.get(requestId);\n\t\t\tif (pending) {\n\t\t\t\tpendingRequests.delete(requestId);\n\t\t\t\tconst { request_id: _stripped, ...payload } = data;\n\t\t\t\tconst ok = !(\"error_type\" in data);\n\t\t\t\tpending.cleanup();\n\t\t\t\ttap.emit({\n\t\t\t\t\tdirection: \"in\",\n\t\t\t\t\tkind: \"response\",\n\t\t\t\t\tname: type,\n\t\t\t\t\tpayload,\n\t\t\t\t\treqId: pending.tapId,\n\t\t\t\t\tok,\n\t\t\t\t});\n\t\t\t\tif (ok) {\n\t\t\t\t\tpending.resolve(payload);\n\t\t\t\t} else {\n\t\t\t\t\tpending.reject(payload);\n\t\t\t\t}\n\t\t\t\t// After the pairing listener's job (the promise is settled\n\t\t\t\t// already, like upstream's first-registered pairing handler).\n\t\t\t\tfanOutToSubscribers(type, data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\ttap.emit({ direction: \"in\", kind: \"event\", name: type, payload: data });\n\t\tfanOutToSubscribers(type, data);\n\t}\n\n\tfunction subscribe(listener: VKBridgeSubscribeHandler): void {\n\t\tsubscribers.push(listener);\n\t}\n\n\tfunction unsubscribe(listener: VKBridgeSubscribeHandler): void {\n\t\tconst index = subscribers.indexOf(listener);\n\t\tif (index > -1) {\n\t\t\tsubscribers.splice(index, 1);\n\t\t}\n\t}\n\n\t// Listening for messages from the runtime env. React Native on Android\n\t// dispatches on the document, everything else on the window.\n\tif (isClientSide()) {\n\t\tconst win = clientWindow();\n\t\tif (isReactNativeWebview() && /(android)/i.test(win?.navigator.userAgent ?? \"\")) {\n\t\t\tdocument.addEventListener(\"message\", handleEvent);\n\t\t} else if (win && \"addEventListener\" in win) {\n\t\t\twin.addEventListener(isWeb() ? \"message\" : \"VKWebAppEvent\", handleEvent);\n\t\t}\n\t}\n\n\t// ------------------------------------------------------------ send + tap\n\n\tconst send: VKBridgeSend = ((\n\t\tmethod: string,\n\t\tprops?: Record<string, unknown>,\n\t\tsendOptions?: SendOptions,\n\t) => {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst signal = sendOptions?.signal;\n\t\t\t// A pre-aborted signal rejects before anything happens: no wire\n\t\t\t// send, no tap entry, no pending slot (the tap reflects reality).\n\t\t\tif (signal?.aborted) {\n\t\t\t\tconst error = new Error(`VK Bridge send \"${method}\" aborted`);\n\t\t\t\terror.name = \"AbortError\";\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst sourceProps: Record<string, unknown> = { ...props };\n\t\t\tconst explicitId =\n\t\t\t\ttypeof sourceProps[\"request_id\"] === \"string\" ||\n\t\t\t\ttypeof sourceProps[\"request_id\"] === \"number\"\n\t\t\t\t\t? sourceProps[\"request_id\"]\n\t\t\t\t\t: undefined;\n\t\t\tlet requestId: string | number | undefined;\n\t\t\tif (explicitId !== undefined) {\n\t\t\t\trequestId = explicitId;\n\t\t\t} else if (requestIdPolicy.inject !== false) {\n\t\t\t\tconst sequence = ++requestCounter;\n\t\t\t\trequestId = requestIdPolicy.generator\n\t\t\t\t\t? requestIdPolicy.generator(sequence)\n\t\t\t\t\t: `__vkma_${sequence}`;\n\t\t\t}\n\n\t\t\t// The wire props are a separate object: the tap payload must not\n\t\t\t// mutate under a listener that observed the emit.\n\t\t\tconst wireProps =\n\t\t\t\trequestId === undefined ? sourceProps : { ...sourceProps, request_id: requestId };\n\n\t\t\tconst tapId = tap.emit({\n\t\t\t\tdirection: \"out\",\n\t\t\t\tkind: \"send\",\n\t\t\t\tname: method,\n\t\t\t\tpayload: wireProps,\n\t\t\t});\n\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet signalHandler: (() => void) | undefined;\n\n\t\t\tconst cleanup = (): void => {\n\t\t\t\tif (timer !== undefined) {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t}\n\t\t\t\tif (signal && signalHandler) {\n\t\t\t\t\tsignal.removeEventListener(\"abort\", signalHandler);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Timeout and abort must fire even for unpaired sends (no\n\t\t\t// pending slot to consult — e.g. inject: false without a caller\n\t\t\t// request_id): the caller asked for a bounded call. For paired\n\t\t\t// sends the pending entry doubles as the \"already answered\"\n\t\t\t// guard against a double rejection.\n\t\t\tconst timeoutReject = (): void => {\n\t\t\t\tif (requestId !== undefined && !pendingRequests.delete(String(requestId))) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcleanup();\n\t\t\t\tconst error = new Error(\n\t\t\t\t\t`VK Bridge send \"${method}\" timed out after ${String(sendOptions?.timeout)}ms`,\n\t\t\t\t);\n\t\t\t\terror.name = \"TimeoutError\";\n\t\t\t\treject(error);\n\t\t\t};\n\n\t\t\tconst abortReject = (): void => {\n\t\t\t\tif (requestId !== undefined && !pendingRequests.delete(String(requestId))) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcleanup();\n\t\t\t\tconst error = new Error(`VK Bridge send \"${method}\" aborted`);\n\t\t\t\terror.name = \"AbortError\";\n\t\t\t\treject(error);\n\t\t\t};\n\n\t\t\tif (requestId !== undefined) {\n\t\t\t\tpendingRequests.set(String(requestId), {\n\t\t\t\t\tresolve: resolve as (value: unknown) => void,\n\t\t\t\t\treject,\n\t\t\t\t\ttapId,\n\t\t\t\t\toptions: sendOptions ?? {},\n\t\t\t\t\tcleanup,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (sendOptions?.timeout !== undefined) {\n\t\t\t\ttimer = setTimeout(timeoutReject, sendOptions.timeout);\n\t\t\t}\n\t\t\tif (signal) {\n\t\t\t\tsignalHandler = abortReject;\n\t\t\t\tsignal.addEventListener(\"abort\", signalHandler);\n\t\t\t}\n\n\t\t\tsendThroughTransport(method, wireProps);\n\t\t});\n\t}) as VKBridgeSend;\n\n\t// The cache behind supportsAsync, fed by both the SetSupportedHandlers\n\t// response and the unsolicited pushes of the same name.\n\tsubscribe((event: { detail?: { type?: unknown; data?: unknown } }) => {\n\t\tif (event.detail?.type === \"SetSupportedHandlers\" && isPlainObject(event.detail.data)) {\n\t\t\tconst handlers = (event.detail.data as { supportedHandlers?: unknown })\n\t\t\t\t.supportedHandlers;\n\t\t\tif (Array.isArray(handlers)) {\n\t\t\t\tsupportedHandlers = new Set(\n\t\t\t\t\thandlers.filter((name): name is string => typeof name === \"string\"),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tfunction supportsInner(method: string): boolean {\n\t\tif (isAndroidWebview()) {\n\t\t\tconst android = hostGlobal()?.[\"AndroidBridge\"] as\n\t\t\t\t| Record<string, ((serializedData: string) => void) | undefined>\n\t\t\t\t| undefined;\n\t\t\treturn typeof android?.[method] === \"function\";\n\t\t}\n\t\tif (isIosWebview()) {\n\t\t\tconst handlers = (\n\t\t\t\thostGlobal()?.[\"webkit\"] as\n\t\t\t\t\t| { messageHandlers?: Record<string, { postMessage?: unknown }> }\n\t\t\t\t\t| undefined\n\t\t\t)?.messageHandlers;\n\t\t\treturn typeof handlers?.[method]?.postMessage === \"function\";\n\t\t}\n\t\tif (isWeb()) {\n\t\t\treturn DESKTOP_METHODS.has(method);\n\t\t}\n\t\treturn false;\n\t}\n\n\tconst bridge: VkmaBridge = {\n\t\tsend,\n\t\tsendPromise: send,\n\t\tsubscribe,\n\t\tunsubscribe,\n\t\tsupports: (method: string) => {\n\t\t\tconsole.warn(\"bridge.supports method is deprecated. Use bridge.supportsAsync instead.\");\n\t\t\treturn supportsInner(method);\n\t\t},\n\t\tsupportsAsync: async (method: string) => {\n\t\t\tif (isAndroidWebview() || isIosWebview()) {\n\t\t\t\treturn supportsInner(method);\n\t\t\t}\n\t\t\tif (supportedHandlers) {\n\t\t\t\treturn supportedHandlers.has(method);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = (await send(\"SetSupportedHandlers\")) as {\n\t\t\t\t\tsupportedHandlers?: string[];\n\t\t\t\t};\n\t\t\t\tsupportedHandlers = new Set(response.supportedHandlers ?? [\"VKWebAppInit\"]);\n\t\t\t} catch {\n\t\t\t\tsupportedHandlers = new Set([\"VKWebAppInit\"]);\n\t\t\t}\n\t\t\treturn supportedHandlers.has(method);\n\t\t},\n\t\tisWebView: () => isIosWebview() || isAndroidWebview(),\n\t\tisIframe: () => {\n\t\t\tconst win = clientWindow();\n\t\t\treturn Boolean(win && win.parent !== win);\n\t\t},\n\t\tisEmbedded: () => bridge.isWebView() || bridge.isIframe(),\n\t\tisStandalone: () => !bridge.isEmbedded(),\n\t\ttap,\n\t\tonSend: listener =>\n\t\t\ttap.subscribe(event => {\n\t\t\t\tif (event.direction === \"out\") {\n\t\t\t\t\tlistener(event as BridgeTapEvent & { direction: \"out\" });\n\t\t\t\t}\n\t\t\t}),\n\t\tonEvent: listener =>\n\t\t\ttap.subscribe(event => {\n\t\t\t\tif (event.direction === \"in\") {\n\t\t\t\t\tlistener(event as BridgeTapEvent & { direction: \"in\" });\n\t\t\t\t}\n\t\t\t}),\n\t};\n\n\treturn bridge;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { AnyIOMethodName, AnyReceiveMethodName, AnyReceiveOnlyMethodName, AnyRequestMethodName, AnyRequestOnlyMethodName } from "./types.js";
|
|
2
|
+
import { CommunityWidgetType } from "@vkma.dev/bridge-schema";
|
|
3
|
+
//#region src/deprecated.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Name of a method that can be sent.
|
|
6
|
+
* @alias AnyRequestMethodName
|
|
7
|
+
* @deprecated
|
|
8
|
+
*/
|
|
9
|
+
export type RequestMethodName = AnyRequestMethodName;
|
|
10
|
+
/**
|
|
11
|
+
* Name of a method that can be received.
|
|
12
|
+
* @alias AnyReceiveMethodName
|
|
13
|
+
* @deprecated
|
|
14
|
+
*/
|
|
15
|
+
export type ReceiveMethodName = AnyReceiveMethodName;
|
|
16
|
+
/**
|
|
17
|
+
* Name of a method that can be only sent.
|
|
18
|
+
* @alias AnyRequestOnlyMethodName
|
|
19
|
+
* @deprecated
|
|
20
|
+
*/
|
|
21
|
+
export type RequestOnlyMethodName = AnyRequestOnlyMethodName;
|
|
22
|
+
/**
|
|
23
|
+
* Name of a method that can be only received.
|
|
24
|
+
* @alias AnyReceiveOnlyMethodName
|
|
25
|
+
* @deprecated
|
|
26
|
+
*/
|
|
27
|
+
export type ReceiveOnlyMethodName = AnyReceiveOnlyMethodName;
|
|
28
|
+
/**
|
|
29
|
+
* Type of any method name.
|
|
30
|
+
* @alias AnyMethodName
|
|
31
|
+
* @deprecated
|
|
32
|
+
*/
|
|
33
|
+
export type MethodName = AnyRequestMethodName | AnyReceiveMethodName;
|
|
34
|
+
/**
|
|
35
|
+
* The name of the method that can be both sent and received.
|
|
36
|
+
* @alias AnyIOMethodName
|
|
37
|
+
* @deprecated
|
|
38
|
+
*/
|
|
39
|
+
export type IOMethodName = AnyIOMethodName;
|
|
40
|
+
/**
|
|
41
|
+
* Community widget type
|
|
42
|
+
* @alias CommunityWidgetType
|
|
43
|
+
* @deprecated
|
|
44
|
+
*/
|
|
45
|
+
export type WidgetType = CommunityWidgetType;
|
|
46
|
+
//#endregion
|
|
47
|
+
//# sourceMappingURL=deprecated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deprecated.d.ts","names":[],"sources":["../src/deprecated.ts"],"mappings":";;;;;;;;YAkBY,oBAAoB;;;;;;YAOpB,oBAAoB;;;;;;YAOpB,wBAAwB;;;;;;YAOxB,wBAAwB;;;;;;YAOxB,aAAa,uBAAuB;;;;;;YAOpC,eAAe;;;;;;YAOf,aAAa"}
|