@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/src/index.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vkma.dev/bridge — an independent VK Bridge for VK Mini Apps.
|
|
3
|
+
*
|
|
4
|
+
* The default export is a ready singleton; `createVKBridge` builds additional
|
|
5
|
+
* instances. Every instance carries an always-on tap (see `onSend`/`onEvent`
|
|
6
|
+
* and `tap`), which is what the VKMA devtools observe — no opt-in required.
|
|
7
|
+
*
|
|
8
|
+
* Merely importing this module publishes the page-wide devtools handle on
|
|
9
|
+
* `globalThis.__vkmaDevtoolsBridge` (`{ tap, send }`), so the devtools
|
|
10
|
+
* collector — loaded as a separate script, never sharing a module graph with
|
|
11
|
+
* the app — can observe and drive the app's own bridge instance.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
15
|
+
import { createVKBridge, type VkmaBridgeOptions } from "./bridge.ts";
|
|
16
|
+
import { createTap, type BridgeTap, type BridgeTapEvent } from "./tap.ts";
|
|
17
|
+
|
|
18
|
+
export { createVKBridge, type RequestIdPolicy, type VkmaBridgeOptions } from "./bridge.ts";
|
|
19
|
+
import type { VkmaBridge } from "./types.ts";
|
|
20
|
+
export { applyMiddleware, type Middleware, type MiddlewareAPI } from "./middleware.ts";
|
|
21
|
+
export { parseURLSearchParamsForGetLaunchParams, type LaunchParams } from "./launch-params.ts";
|
|
22
|
+
export { createTap } from "./tap.ts";
|
|
23
|
+
export type {
|
|
24
|
+
SendOptions,
|
|
25
|
+
VKBridge,
|
|
26
|
+
VKBridgeErrorEvent,
|
|
27
|
+
VKBridgeEvent,
|
|
28
|
+
VKBridgeEventBase,
|
|
29
|
+
VKBridgeIOEvent,
|
|
30
|
+
VKBridgeReceiveOnlyEvent,
|
|
31
|
+
VKBridgeResultEvent,
|
|
32
|
+
VKBridgeSend,
|
|
33
|
+
VKBridgeSubscribeHandler,
|
|
34
|
+
VkmaBridge,
|
|
35
|
+
AnyIOMethodName,
|
|
36
|
+
AnyMethodName,
|
|
37
|
+
AnyReceiveMethodName,
|
|
38
|
+
AnyReceiveOnlyMethodName,
|
|
39
|
+
AnyRequestMethodName,
|
|
40
|
+
AnyRequestOnlyMethodName,
|
|
41
|
+
ErrorData,
|
|
42
|
+
ErrorDataAPIError,
|
|
43
|
+
ErrorDataAuthError,
|
|
44
|
+
ErrorDataClientError,
|
|
45
|
+
FailedResponseEventName,
|
|
46
|
+
RequestIdProp,
|
|
47
|
+
RequestProps,
|
|
48
|
+
ReceiveData,
|
|
49
|
+
ResultResponseEventName,
|
|
50
|
+
} from "./types.ts";
|
|
51
|
+
export type {
|
|
52
|
+
RequestMethodName,
|
|
53
|
+
ReceiveMethodName,
|
|
54
|
+
RequestOnlyMethodName,
|
|
55
|
+
ReceiveOnlyMethodName,
|
|
56
|
+
MethodName,
|
|
57
|
+
IOMethodName,
|
|
58
|
+
WidgetType,
|
|
59
|
+
} from "./deprecated.ts";
|
|
60
|
+
export type { ReceiveDataMap, ReceiveEventMap, RequestPropsMap } from "@vkma.dev/bridge-schema";
|
|
61
|
+
export * from "@vkma.dev/bridge-schema";
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The devtools bridge handle shared by every copy of this module on the page,
|
|
65
|
+
* exposed on `globalThis` under a stable key so the devtools collector —
|
|
66
|
+
* loaded as a separate script, never sharing a module graph with the app —
|
|
67
|
+
* can observe and drive the app's own bridge instance:
|
|
68
|
+
*
|
|
69
|
+
* - `tap` — replay-buffered stream of sends, paired responses and events
|
|
70
|
+
* - `send` — execute a bridge send inside the app (devtools "execute")
|
|
71
|
+
*/
|
|
72
|
+
const GLOBAL_KEY = "__vkmaDevtoolsBridge";
|
|
73
|
+
|
|
74
|
+
export interface DevtoolsBridgeHandle {
|
|
75
|
+
tap: BridgeTap;
|
|
76
|
+
send: (name: string, params?: Record<string, unknown>) => Promise<unknown>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const globalScope = globalThis as typeof globalThis & {
|
|
80
|
+
[GLOBAL_KEY]?: DevtoolsBridgeHandle;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
function sharedTap(): BridgeTap {
|
|
84
|
+
const existing = globalScope[GLOBAL_KEY];
|
|
85
|
+
if (existing) {
|
|
86
|
+
return existing.tap;
|
|
87
|
+
}
|
|
88
|
+
const tap = createTap();
|
|
89
|
+
globalScope[GLOBAL_KEY] = {
|
|
90
|
+
tap,
|
|
91
|
+
// The collector executes arbitrary method names — the handle stays
|
|
92
|
+
// stringly typed by design.
|
|
93
|
+
send: (name, params) => bridge.send(name as never, params as never),
|
|
94
|
+
};
|
|
95
|
+
return tap;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Options of the page-wide default instance: it shares the global tap. */
|
|
99
|
+
const defaultOptions: VkmaBridgeOptions = {
|
|
100
|
+
tap: sharedTap(),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const bridge: VkmaBridge = createVKBridge(packageJson.version, defaultOptions);
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Subscribe to outgoing `send` calls of the default instance.
|
|
107
|
+
*/
|
|
108
|
+
export function onSend(
|
|
109
|
+
listener: (event: BridgeTapEvent & { direction: "out" }) => void,
|
|
110
|
+
): () => void {
|
|
111
|
+
return bridge.onSend(listener);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Subscribe to everything incoming on the default instance: paired responses
|
|
116
|
+
* and unsolicited events.
|
|
117
|
+
*/
|
|
118
|
+
export function onEvent(
|
|
119
|
+
listener: (event: BridgeTapEvent & { direction: "in" }) => void,
|
|
120
|
+
): () => void {
|
|
121
|
+
return bridge.onEvent(listener);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** The shared tap of the default instance (buffered until first subscribe). */
|
|
125
|
+
export const bridgeTap: BridgeTap = bridge.tap;
|
|
126
|
+
|
|
127
|
+
/** The `globalThis` key the devtools collector looks the handle up by. */
|
|
128
|
+
export const devtoolsBridgeGlobalKey = GLOBAL_KEY;
|
|
129
|
+
|
|
130
|
+
export { bridge as default };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Launch params: parsing the `vk_*` query string every mini app is opened
|
|
3
|
+
* with, into the typed shape of the catalogue's `GetLaunchParamsResponse`
|
|
4
|
+
* plus the extra keys only present in the URL form.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { GetLaunchParamsResponse } from "@vkma.dev/bridge-schema";
|
|
8
|
+
|
|
9
|
+
const LANGUAGES = new Set(["ru", "uk", "ua", "en", "be", "kz", "pt", "es"]);
|
|
10
|
+
|
|
11
|
+
const GROUP_ROLES = new Set(["admin", "editor", "member", "moder", "none"]);
|
|
12
|
+
|
|
13
|
+
const PLATFORMS = new Set([
|
|
14
|
+
"desktop_web",
|
|
15
|
+
"desktop_web_messenger",
|
|
16
|
+
"desktop_app_messenger",
|
|
17
|
+
"mobile_web",
|
|
18
|
+
"mobile_android",
|
|
19
|
+
"mobile_android_messenger",
|
|
20
|
+
"mobile_iphone",
|
|
21
|
+
"mobile_iphone_messenger",
|
|
22
|
+
"mobile_ipad",
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Launch params as they appear in the URL — a superset of
|
|
27
|
+
* `GetLaunchParamsResponse` with the keys the host only sends via the query
|
|
28
|
+
* string.
|
|
29
|
+
*/
|
|
30
|
+
export interface LaunchParams extends GetLaunchParamsResponse {
|
|
31
|
+
vk_chat_id: string;
|
|
32
|
+
vk_is_recommended: number;
|
|
33
|
+
vk_profile_id: number;
|
|
34
|
+
vk_has_profile_button: number;
|
|
35
|
+
vk_testing_group_id: number;
|
|
36
|
+
odr_enabled: undefined | 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parses launch params out of a query string (à la
|
|
41
|
+
* `location.search.slice(1)`), field by field, keeping only the known keys
|
|
42
|
+
* with validated values.
|
|
43
|
+
*
|
|
44
|
+
* @see https://dev.vk.ru/mini-apps/development/launch-params
|
|
45
|
+
*/
|
|
46
|
+
export const parseURLSearchParamsForGetLaunchParams = (
|
|
47
|
+
searchParams: string,
|
|
48
|
+
): Partial<LaunchParams> => {
|
|
49
|
+
const launchParams: Partial<LaunchParams> = {};
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const parsedSearchParams = new URLSearchParams(searchParams);
|
|
53
|
+
|
|
54
|
+
const convertToggleStateFromStringToNumber = (value: string): 0 | 1 | undefined => {
|
|
55
|
+
switch (value) {
|
|
56
|
+
case "0":
|
|
57
|
+
return 0;
|
|
58
|
+
case "1":
|
|
59
|
+
return 1;
|
|
60
|
+
default:
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
parsedSearchParams.forEach((value, query) => {
|
|
66
|
+
switch (query) {
|
|
67
|
+
case "vk_ts":
|
|
68
|
+
case "vk_is_recommended":
|
|
69
|
+
case "vk_profile_id":
|
|
70
|
+
case "vk_has_profile_button":
|
|
71
|
+
case "vk_testing_group_id":
|
|
72
|
+
case "vk_user_id":
|
|
73
|
+
case "vk_app_id":
|
|
74
|
+
case "vk_group_id":
|
|
75
|
+
launchParams[query] = Number(value);
|
|
76
|
+
break;
|
|
77
|
+
case "sign":
|
|
78
|
+
case "vk_chat_id":
|
|
79
|
+
case "vk_ref":
|
|
80
|
+
case "vk_access_token_settings":
|
|
81
|
+
launchParams[query] = value;
|
|
82
|
+
break;
|
|
83
|
+
case "odr_enabled":
|
|
84
|
+
launchParams.odr_enabled = value === "1" ? 1 : undefined;
|
|
85
|
+
break;
|
|
86
|
+
case "vk_is_app_user":
|
|
87
|
+
case "vk_are_notifications_enabled":
|
|
88
|
+
case "vk_is_favorite": {
|
|
89
|
+
launchParams[query] = convertToggleStateFromStringToNumber(value);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case "vk_language": {
|
|
93
|
+
launchParams.vk_language = LANGUAGES.has(value)
|
|
94
|
+
? (value as Partial<LaunchParams>["vk_language"])
|
|
95
|
+
: undefined;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "vk_viewer_group_role": {
|
|
99
|
+
launchParams.vk_viewer_group_role = GROUP_ROLES.has(value)
|
|
100
|
+
? (value as Partial<LaunchParams>["vk_viewer_group_role"])
|
|
101
|
+
: undefined;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case "vk_platform": {
|
|
105
|
+
launchParams.vk_platform = PLATFORMS.has(value)
|
|
106
|
+
? (value as Partial<LaunchParams>["vk_platform"])
|
|
107
|
+
: undefined;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.warn(error);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return launchParams;
|
|
117
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redux-style middleware over `send`: compose logging, metrics or caching
|
|
3
|
+
* around the dispatch without touching the transport.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { VKBridge, VKBridgeSend, VKBridgeSubscribeHandler } from "./types.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* API that can use middleware.
|
|
10
|
+
*/
|
|
11
|
+
export interface MiddlewareAPI<
|
|
12
|
+
S extends VKBridgeSend = VKBridgeSend,
|
|
13
|
+
L extends VKBridgeSubscribeHandler = VKBridgeSubscribeHandler,
|
|
14
|
+
> {
|
|
15
|
+
send: S;
|
|
16
|
+
subscribe(listener: L): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A middleware is a higher-order function that composes a dispatch function
|
|
21
|
+
* to return a new `send` function.
|
|
22
|
+
*/
|
|
23
|
+
export type Middleware<S extends VKBridgeSend = VKBridgeSend> = (
|
|
24
|
+
api: MiddlewareAPI<S>,
|
|
25
|
+
) => (next: S) => S;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Creates the VK Bridge enhancer that applies middleware to the `send`
|
|
29
|
+
* method. This is handy for a variety of tasks such as logging every sent
|
|
30
|
+
* event.
|
|
31
|
+
*
|
|
32
|
+
* @param middlewares The middleware chain to be applied.
|
|
33
|
+
* @returns The VK Bridge enhancer applying the middleware.
|
|
34
|
+
*/
|
|
35
|
+
export function applyMiddleware(
|
|
36
|
+
...middlewares: Array<Middleware | undefined | null>
|
|
37
|
+
): (bridge: VKBridge) => VKBridge {
|
|
38
|
+
if (middlewares.includes(undefined) || middlewares.includes(null)) {
|
|
39
|
+
return applyMiddleware(
|
|
40
|
+
...middlewares.filter((item): item is Middleware => typeof item === "function"),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return bridge => {
|
|
45
|
+
if (middlewares.length === 0) {
|
|
46
|
+
return bridge;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let send: VKBridgeSend = () => {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"Sending events while constructing your middleware is not allowed. " +
|
|
52
|
+
"Other middleware would not be applied to this send.",
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const middlewareAPI: MiddlewareAPI = {
|
|
57
|
+
subscribe: bridge.subscribe,
|
|
58
|
+
send: ((...args: Parameters<VKBridgeSend>) => bridge.send(...args)) as VKBridgeSend,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const chain = middlewares
|
|
62
|
+
.filter((item): item is Middleware => typeof item === "function")
|
|
63
|
+
.map(middleware => middleware(middlewareAPI))
|
|
64
|
+
.reduce((a, b) => next => a(b(next)));
|
|
65
|
+
|
|
66
|
+
send = chain(bridge.send);
|
|
67
|
+
|
|
68
|
+
return { ...bridge, send };
|
|
69
|
+
};
|
|
70
|
+
}
|
package/src/tap.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure tap machinery: a tiny fan-out hub with a bounded replay buffer,
|
|
3
|
+
* detached from vk-bridge so it is unit-testable and tree-shakeable.
|
|
4
|
+
*
|
|
5
|
+
* The bridge wrapper always emits into the tap. When no devtools collector
|
|
6
|
+
* is attached (production), the buffer fills up once and every later emit
|
|
7
|
+
* costs a dropped-head push — effectively free.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface BridgeTapEvent {
|
|
11
|
+
/** Monotonic within a page load; pairs a `response` with its `send`. */
|
|
12
|
+
id: number;
|
|
13
|
+
ts: number;
|
|
14
|
+
/** `out` — the app called send; `in` — VK sent something to the app. */
|
|
15
|
+
direction: "out" | "in";
|
|
16
|
+
/** `send` (out), `response` (in, paired), `event` (in, unsolicited). */
|
|
17
|
+
kind: "send" | "response" | "event";
|
|
18
|
+
name: string;
|
|
19
|
+
payload?: unknown;
|
|
20
|
+
/** Response pairing: the id of the originating `send` event. */
|
|
21
|
+
reqId?: number;
|
|
22
|
+
/** Only for `response`: whether the promise resolved or rejected. */
|
|
23
|
+
ok?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface BridgeTap {
|
|
27
|
+
emit(event: Omit<BridgeTapEvent, "id" | "ts"> & { ts?: number }): number;
|
|
28
|
+
subscribe(listener: (event: BridgeTapEvent) => void): () => void;
|
|
29
|
+
/** Events buffered before the first subscriber attached, oldest first. */
|
|
30
|
+
drain(): BridgeTapEvent[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const DEFAULT_BUFFER_LIMIT = 500;
|
|
34
|
+
|
|
35
|
+
export function createTap(limit: number = DEFAULT_BUFFER_LIMIT): BridgeTap {
|
|
36
|
+
let nextId = 0;
|
|
37
|
+
let buffer: BridgeTapEvent[] | undefined = [];
|
|
38
|
+
const listeners = new Set<(event: BridgeTapEvent) => void>();
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
emit(partial) {
|
|
42
|
+
const event: BridgeTapEvent = {
|
|
43
|
+
...partial,
|
|
44
|
+
id: ++nextId,
|
|
45
|
+
ts: partial.ts ?? Date.now(),
|
|
46
|
+
};
|
|
47
|
+
if (listeners.size === 0) {
|
|
48
|
+
// No collector yet (production or devtools not loaded): keep a
|
|
49
|
+
// bounded replay so a late-attaching collector still sees recent
|
|
50
|
+
// history, then stop growing work at the cap.
|
|
51
|
+
if (buffer && buffer.length >= limit) {
|
|
52
|
+
buffer.shift();
|
|
53
|
+
}
|
|
54
|
+
buffer?.push(event);
|
|
55
|
+
return event.id;
|
|
56
|
+
}
|
|
57
|
+
for (const listener of listeners) {
|
|
58
|
+
listener(event);
|
|
59
|
+
}
|
|
60
|
+
return event.id;
|
|
61
|
+
},
|
|
62
|
+
subscribe(listener) {
|
|
63
|
+
listeners.add(listener);
|
|
64
|
+
const replay = buffer ?? [];
|
|
65
|
+
buffer = undefined;
|
|
66
|
+
for (const event of replay) {
|
|
67
|
+
listener(event);
|
|
68
|
+
}
|
|
69
|
+
return () => {
|
|
70
|
+
listeners.delete(listener);
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
drain() {
|
|
74
|
+
return buffer ? [...buffer] : [];
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge machinery types, built on top of the @vkma.dev/bridge-schema
|
|
3
|
+
* catalogue. The payload types and the three catalogue maps
|
|
4
|
+
* (`RequestPropsMap` / `ReceiveDataMap` / `ReceiveEventMap`) are re-exported
|
|
5
|
+
* from the schema package by the public entrypoint; everything here is the
|
|
6
|
+
* send/subscribe/event plumbing around them.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ReceiveDataMap, ReceiveEventMap, RequestPropsMap } from "@vkma.dev/bridge-schema";
|
|
10
|
+
import type { BridgeTap, BridgeTapEvent } from "./tap.ts";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Name of a method that can be sent.
|
|
14
|
+
*/
|
|
15
|
+
export type AnyRequestMethodName = keyof RequestPropsMap;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Name of a method that can be received.
|
|
19
|
+
*/
|
|
20
|
+
export type AnyReceiveMethodName = keyof ReceiveDataMap;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Name of a method that can be only sent.
|
|
24
|
+
*/
|
|
25
|
+
export type AnyRequestOnlyMethodName = Exclude<AnyRequestMethodName, AnyReceiveMethodName>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Name of a method that can be only received.
|
|
29
|
+
*/
|
|
30
|
+
export type AnyReceiveOnlyMethodName = Exclude<AnyReceiveMethodName, AnyRequestMethodName>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Type of any method name.
|
|
34
|
+
*/
|
|
35
|
+
export type AnyMethodName = AnyRequestMethodName | AnyReceiveMethodName;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The name of the method that can be both sent and received.
|
|
39
|
+
*/
|
|
40
|
+
export type AnyIOMethodName = AnyRequestMethodName & AnyReceiveMethodName;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Getter of request properties of a method.
|
|
44
|
+
*/
|
|
45
|
+
export type RequestProps<M extends AnyRequestMethodName = AnyRequestMethodName> =
|
|
46
|
+
RequestPropsMap[M];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Getter of response data of a method.
|
|
50
|
+
*/
|
|
51
|
+
export type ReceiveData<M extends AnyReceiveMethodName> = ReceiveDataMap[M];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Property for matching a sent request with the received message.
|
|
55
|
+
*/
|
|
56
|
+
export type RequestIdProp = { request_id?: number | string };
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Extra per-send controls on top of the classic two-argument call.
|
|
60
|
+
*/
|
|
61
|
+
export interface SendOptions {
|
|
62
|
+
/** Reject the promise if no response arrives within this many milliseconds. */
|
|
63
|
+
timeout?: number;
|
|
64
|
+
/** Reject the promise when the signal aborts. */
|
|
65
|
+
signal?: AbortSignal;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Type of send function for methods that have props.
|
|
70
|
+
*
|
|
71
|
+
* @param method The method (event) name to send.
|
|
72
|
+
* @param props Method properties.
|
|
73
|
+
* @param options Timeout / abort controls.
|
|
74
|
+
* @returns The Promise object with response data.
|
|
75
|
+
*/
|
|
76
|
+
export type VKBridgeSend = <K extends AnyRequestMethodName>(
|
|
77
|
+
method: K,
|
|
78
|
+
props?: RequestProps<K> & RequestIdProp,
|
|
79
|
+
options?: SendOptions,
|
|
80
|
+
) => Promise<K extends AnyReceiveMethodName ? ReceiveData<K> : void>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Name of the Result response event of a method (per the catalogue wiring).
|
|
84
|
+
*/
|
|
85
|
+
export type ResultResponseEventName<M extends AnyRequestMethodName> =
|
|
86
|
+
M extends keyof ReceiveEventMap ? ReceiveEventMap[M]["result"] : never;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Name of the Failed response event of a method (per the catalogue wiring).
|
|
90
|
+
*/
|
|
91
|
+
export type FailedResponseEventName<M extends AnyRequestMethodName> =
|
|
92
|
+
M extends keyof ReceiveEventMap ? ReceiveEventMap[M]["failed"] : never;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Client error data.
|
|
96
|
+
*/
|
|
97
|
+
export type ErrorDataClientError = {
|
|
98
|
+
error_code: number;
|
|
99
|
+
error_reason: string;
|
|
100
|
+
error_description?: string;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* API error data.
|
|
105
|
+
*/
|
|
106
|
+
export type ErrorDataAPIError = {
|
|
107
|
+
error_code: number;
|
|
108
|
+
error_msg: string;
|
|
109
|
+
request_params: string[];
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Auth error data.
|
|
114
|
+
*/
|
|
115
|
+
export type ErrorDataAuthError = {
|
|
116
|
+
error_code: number;
|
|
117
|
+
error_reason: string;
|
|
118
|
+
error_description?: string[];
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Error data of a Failed response event.
|
|
123
|
+
*/
|
|
124
|
+
export type ErrorData =
|
|
125
|
+
| {
|
|
126
|
+
error_type: "client_error";
|
|
127
|
+
error_data: ErrorDataClientError;
|
|
128
|
+
request_id?: number | string;
|
|
129
|
+
}
|
|
130
|
+
| {
|
|
131
|
+
error_type: "api_error";
|
|
132
|
+
error_data: ErrorDataAPIError;
|
|
133
|
+
request_id?: number | string;
|
|
134
|
+
}
|
|
135
|
+
| {
|
|
136
|
+
error_type: "auth_error";
|
|
137
|
+
error_data: ErrorDataAuthError;
|
|
138
|
+
request_id?: number | string;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Generic event type for creating event types.
|
|
143
|
+
*/
|
|
144
|
+
export type VKBridgeEventBase<Type extends string, Data> = {
|
|
145
|
+
detail: {
|
|
146
|
+
type: Type;
|
|
147
|
+
data: Data;
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Type of error event data.
|
|
153
|
+
*/
|
|
154
|
+
export type VKBridgeErrorEvent<M extends AnyReceiveMethodName> = VKBridgeEventBase<
|
|
155
|
+
M extends AnyRequestMethodName ? FailedResponseEventName<M> : never,
|
|
156
|
+
ErrorData
|
|
157
|
+
>;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Type of event that is a response to a request.
|
|
161
|
+
*/
|
|
162
|
+
export type VKBridgeIOEvent<M extends AnyIOMethodName> = {
|
|
163
|
+
[K in M]: VKBridgeEventBase<ResultResponseEventName<K>, ReceiveData<K> & RequestIdProp>;
|
|
164
|
+
}[M];
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Type of event that is not a response to a request.
|
|
168
|
+
*/
|
|
169
|
+
export type VKBridgeReceiveOnlyEvent<M extends AnyReceiveOnlyMethodName> = {
|
|
170
|
+
[K in M]: VKBridgeEventBase<K, ReceiveData<K>>;
|
|
171
|
+
}[M];
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Type of result event data.
|
|
175
|
+
*/
|
|
176
|
+
export type VKBridgeResultEvent<M extends AnyReceiveMethodName> = M extends AnyReceiveOnlyMethodName
|
|
177
|
+
? VKBridgeReceiveOnlyEvent<M>
|
|
178
|
+
: M extends AnyIOMethodName
|
|
179
|
+
? VKBridgeIOEvent<M>
|
|
180
|
+
: never;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* VK Bridge event.
|
|
184
|
+
*/
|
|
185
|
+
export type VKBridgeEvent<M extends AnyReceiveMethodName> =
|
|
186
|
+
| VKBridgeErrorEvent<M>
|
|
187
|
+
| VKBridgeResultEvent<M>;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Type of function that can be subscribed to VK Bridge events.
|
|
191
|
+
*/
|
|
192
|
+
export type VKBridgeSubscribeHandler = (event: VKBridgeEvent<AnyReceiveMethodName>) => void;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* VK Bridge interface — the classic drop-in surface.
|
|
196
|
+
*/
|
|
197
|
+
export interface VKBridge {
|
|
198
|
+
/**
|
|
199
|
+
* Sends an event to the runtime env and returns the Promise object with
|
|
200
|
+
* response data. In the case of Android/iOS application env is the
|
|
201
|
+
* application itself. In the case of the browser, the parent frame in
|
|
202
|
+
* which the event handlers is located.
|
|
203
|
+
*
|
|
204
|
+
* @param method The method (event) name to send.
|
|
205
|
+
* @param [props] Method properties.
|
|
206
|
+
* @param [options] Timeout / abort controls.
|
|
207
|
+
* @returns The Promise object with response data.
|
|
208
|
+
*/
|
|
209
|
+
send: VKBridgeSend;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @alias send
|
|
213
|
+
* @deprecated
|
|
214
|
+
*/
|
|
215
|
+
sendPromise: VKBridgeSend;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Adds an event listener. It will be called any time a data is received.
|
|
219
|
+
*
|
|
220
|
+
* @param listener A callback to be invoked on every event receive.
|
|
221
|
+
*/
|
|
222
|
+
subscribe: (listener: VKBridgeSubscribeHandler) => void;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Removes an event listener which has been subscribed for event listening.
|
|
226
|
+
*
|
|
227
|
+
* @param listener A callback to unsubscribe.
|
|
228
|
+
*/
|
|
229
|
+
unsubscribe: (listener: VKBridgeSubscribeHandler) => void;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Checks if a method is supported on runtime platform.
|
|
233
|
+
*
|
|
234
|
+
* @param method Method (event) name to check.
|
|
235
|
+
* @returns Result of checking.
|
|
236
|
+
* @deprecated This method is deprecated. Use supportsAsync instead.
|
|
237
|
+
*/
|
|
238
|
+
supports: <K extends AnyRequestMethodName>(method: K) => boolean;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Checks if a method is supported on runtime platform.
|
|
242
|
+
*
|
|
243
|
+
* @param method Method (event) name to check.
|
|
244
|
+
* @returns The Promise object with result of checking.
|
|
245
|
+
*/
|
|
246
|
+
supportsAsync: <K extends AnyRequestMethodName>(method: K) => Promise<boolean>;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Checks whether the runtime is a WebView.
|
|
250
|
+
*/
|
|
251
|
+
isWebView: () => boolean;
|
|
252
|
+
|
|
253
|
+
isIframe: () => boolean;
|
|
254
|
+
|
|
255
|
+
isEmbedded: () => boolean;
|
|
256
|
+
|
|
257
|
+
isStandalone: () => boolean;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* The full instance surface: the classic VK Bridge plus the always-on tap
|
|
262
|
+
* and its subscription helpers.
|
|
263
|
+
*/
|
|
264
|
+
export interface VkmaBridge extends VKBridge {
|
|
265
|
+
/** The replay-buffered stream of sends, paired responses and events. */
|
|
266
|
+
tap: BridgeTap;
|
|
267
|
+
/** Subscribe to outgoing `send` calls. */
|
|
268
|
+
onSend: (listener: (event: BridgeTapEvent & { direction: "out" }) => void) => () => void;
|
|
269
|
+
/** Subscribe to everything incoming: paired responses and unsolicited events. */
|
|
270
|
+
onEvent: (listener: (event: BridgeTapEvent & { direction: "in" }) => void) => () => void;
|
|
271
|
+
}
|