@nebula-rn/client 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chooseMedia/index.d.ts +22 -0
- package/dist/chooseMedia/index.js +4 -0
- package/dist/compressImage/index.d.ts +7 -0
- package/dist/compressImage/index.js +4 -0
- package/dist/descriptions.d.ts +9 -0
- package/dist/descriptions.js +259 -0
- package/dist/file.d.ts +51 -0
- package/dist/file.js +14 -0
- package/dist/getAppBaseInfo/index.d.ts +6 -0
- package/dist/getAppBaseInfo/index.js +4 -0
- package/dist/getClipboardData/index.d.ts +1 -0
- package/dist/getClipboardData/index.js +4 -0
- package/dist/getFileInfo/index.d.ts +9 -0
- package/dist/getFileInfo/index.js +4 -0
- package/dist/getFileSystemManager/index.d.ts +70 -0
- package/dist/getFileSystemManager/index.js +43 -0
- package/dist/getImageInfo/index.d.ts +16 -0
- package/dist/getImageInfo/index.js +20 -0
- package/dist/getLocation/index.d.ts +15 -0
- package/dist/getLocation/index.js +4 -0
- package/dist/getScreenBrightness/index.d.ts +1 -0
- package/dist/getScreenBrightness/index.js +4 -0
- package/dist/getStorage/index.d.ts +1 -0
- package/dist/getStorage/index.js +8 -0
- package/dist/getStorageInfo/index.d.ts +6 -0
- package/dist/getStorageInfo/index.js +12 -0
- package/dist/getSystemInfo/index.d.ts +1 -0
- package/dist/getSystemInfo/index.js +4 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +26 -0
- package/dist/location.d.ts +10 -0
- package/dist/location.js +18 -0
- package/dist/makePhoneCall/index.d.ts +1 -0
- package/dist/makePhoneCall/index.js +4 -0
- package/dist/media.d.ts +5 -0
- package/dist/media.js +8 -0
- package/dist/miniAppUpdate/index.d.ts +3 -0
- package/dist/miniAppUpdate/index.js +7 -0
- package/dist/network.d.ts +9 -0
- package/dist/network.js +15 -0
- package/dist/onUserCaptureScreen/index.d.ts +1 -0
- package/dist/onUserCaptureScreen/index.js +11 -0
- package/dist/previewImage/index.d.ts +8 -0
- package/dist/previewImage/index.js +4 -0
- package/dist/runtime/host.d.ts +41 -0
- package/dist/runtime/host.js +152 -0
- package/dist/scanCode/contract.d.ts +7 -0
- package/dist/scanCode/contract.js +8 -0
- package/dist/scanCode/icon_close.png +0 -0
- package/dist/scanCode/icon_pic.png +0 -0
- package/dist/scanCode/index.d.ts +6 -0
- package/dist/scanCode/index.js +72 -0
- package/dist/scanCode/types.d.ts +25 -0
- package/dist/scanCode/types.js +8 -0
- package/dist/sensors.d.ts +13 -0
- package/dist/sensors.js +15 -0
- package/dist/setClipboardData/index.d.ts +1 -0
- package/dist/setClipboardData/index.js +2 -0
- package/dist/setStorage/index.d.ts +5 -0
- package/dist/setStorage/index.js +5 -0
- package/dist/storage.d.ts +9 -0
- package/dist/storage.js +36 -0
- package/dist/uploadFile/index.d.ts +30 -0
- package/dist/uploadFile/index.js +6 -0
- package/package.json +77 -0
- package/src/chooseMedia/index.ts +36 -0
- package/src/compressImage/index.ts +14 -0
- package/src/descriptions.ts +294 -0
- package/src/file.ts +89 -0
- package/src/getAppBaseInfo/index.ts +10 -0
- package/src/getClipboardData/index.ts +5 -0
- package/src/getFileInfo/index.ts +17 -0
- package/src/getFileSystemManager/index.ts +141 -0
- package/src/getImageInfo/index.ts +40 -0
- package/src/getLocation/index.ts +23 -0
- package/src/getScreenBrightness/index.ts +5 -0
- package/src/getStorage/index.ts +10 -0
- package/src/getStorageInfo/index.ts +20 -0
- package/src/getSystemInfo/index.ts +5 -0
- package/src/index.ts +26 -0
- package/src/location.ts +40 -0
- package/src/makePhoneCall/index.ts +5 -0
- package/src/media.ts +19 -0
- package/src/miniAppUpdate/index.ts +20 -0
- package/src/network.ts +36 -0
- package/src/onUserCaptureScreen/index.ts +17 -0
- package/src/previewImage/index.tsx +13 -0
- package/src/runtime/host.ts +356 -0
- package/src/scanCode/contract.ts +20 -0
- package/src/scanCode/icon_close.png +0 -0
- package/src/scanCode/icon_pic.png +0 -0
- package/src/scanCode/index.tsx +127 -0
- package/src/scanCode/types.ts +38 -0
- package/src/sensors.ts +48 -0
- package/src/setClipboardData/index.ts +4 -0
- package/src/setStorage/index.ts +11 -0
- package/src/storage.ts +51 -0
- package/src/uploadFile/index.ts +57 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { invokeHostApi } from '../runtime/host';
|
|
2
|
+
|
|
3
|
+
type GetImageInfoOption = {
|
|
4
|
+
src: string;
|
|
5
|
+
success?: (res: Record<string, unknown>) => void;
|
|
6
|
+
fail?: (res: Record<string, unknown>) => void;
|
|
7
|
+
complete?: (res: Record<string, unknown>) => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type GetImageInfoSuccessResult = {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
path: string;
|
|
14
|
+
orientation: string;
|
|
15
|
+
type: string;
|
|
16
|
+
errMsg: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function getImageInfo(
|
|
20
|
+
option: GetImageInfoOption,
|
|
21
|
+
): Promise<GetImageInfoSuccessResult> {
|
|
22
|
+
const { src, success, fail, complete } = option;
|
|
23
|
+
|
|
24
|
+
return invokeHostApi<GetImageInfoSuccessResult>('getImageInfo', {
|
|
25
|
+
src,
|
|
26
|
+
})
|
|
27
|
+
.then(res => {
|
|
28
|
+
success?.(res);
|
|
29
|
+
complete?.(res);
|
|
30
|
+
return res;
|
|
31
|
+
})
|
|
32
|
+
.catch(error => {
|
|
33
|
+
const res = {
|
|
34
|
+
errMsg: error instanceof Error ? error.message : 'getImageInfo:fail',
|
|
35
|
+
};
|
|
36
|
+
fail?.(res);
|
|
37
|
+
complete?.(res);
|
|
38
|
+
throw res;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { invokeHostApi } from '../runtime/host';
|
|
2
|
+
|
|
3
|
+
export interface GetLocationOption {
|
|
4
|
+
altitude?: boolean;
|
|
5
|
+
isHighAccuracy?: boolean;
|
|
6
|
+
highAccuracyExpireTime?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface GetLocationResult {
|
|
10
|
+
latitude: number;
|
|
11
|
+
longitude: number;
|
|
12
|
+
speed: number;
|
|
13
|
+
accuracy: number;
|
|
14
|
+
altitude: number;
|
|
15
|
+
verticalAccuracy: number;
|
|
16
|
+
horizontalAccuracy: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const getLocation = (
|
|
20
|
+
options: GetLocationOption = {},
|
|
21
|
+
): Promise<GetLocationResult> => {
|
|
22
|
+
return invokeHostApi<GetLocationResult>('getLocation', options);
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { deserializeStorageValue, getStorageItem } from '../storage';
|
|
2
|
+
|
|
3
|
+
export const getStorage = async <T>(key: string): Promise<T> => {
|
|
4
|
+
const data = await getStorageItem(key);
|
|
5
|
+
if (data !== undefined && data !== null) {
|
|
6
|
+
return deserializeStorageValue<T>(data);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
throw new Error('getStorage:fail data not found');
|
|
10
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getStorageCurrentSize, getStorageKeys } from '../storage';
|
|
2
|
+
|
|
3
|
+
export interface GetStorageInfoResult {
|
|
4
|
+
keys: string[];
|
|
5
|
+
currentSize: number;
|
|
6
|
+
limitSize: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const getStorageInfo = async (): Promise<GetStorageInfoResult> => {
|
|
10
|
+
const [keys, currentSize] = await Promise.all([
|
|
11
|
+
getStorageKeys(),
|
|
12
|
+
getStorageCurrentSize(),
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
keys,
|
|
17
|
+
currentSize,
|
|
18
|
+
limitSize: 10240,
|
|
19
|
+
};
|
|
20
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export * from './chooseMedia';
|
|
2
|
+
export * from './compressImage';
|
|
3
|
+
export * from './descriptions';
|
|
4
|
+
export * from './file';
|
|
5
|
+
export * from './getAppBaseInfo';
|
|
6
|
+
export * from './getClipboardData';
|
|
7
|
+
export * from './getFileInfo';
|
|
8
|
+
export * from './getFileSystemManager';
|
|
9
|
+
export * from './getImageInfo';
|
|
10
|
+
export * from './getLocation';
|
|
11
|
+
export * from './getScreenBrightness';
|
|
12
|
+
export * from './getStorage';
|
|
13
|
+
export * from './getStorageInfo';
|
|
14
|
+
export * from './getSystemInfo';
|
|
15
|
+
export * from './location';
|
|
16
|
+
export * from './makePhoneCall';
|
|
17
|
+
export * from './media';
|
|
18
|
+
export * from './miniAppUpdate';
|
|
19
|
+
export * from './network';
|
|
20
|
+
export * from './onUserCaptureScreen';
|
|
21
|
+
export * from './previewImage';
|
|
22
|
+
export * from './scanCode';
|
|
23
|
+
export * from './sensors';
|
|
24
|
+
export * from './setClipboardData';
|
|
25
|
+
export * from './setStorage';
|
|
26
|
+
export * from './storage';
|
package/src/location.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { subscribeToHostEvent } from './runtime/host';
|
|
2
|
+
|
|
3
|
+
export interface LocationData {
|
|
4
|
+
accuracy: number;
|
|
5
|
+
altitude: number | null;
|
|
6
|
+
latitude: number;
|
|
7
|
+
longitude: number;
|
|
8
|
+
speed: number | null;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type UnsubscribeFn = () => void | Promise<void>;
|
|
13
|
+
|
|
14
|
+
export const onLocationChange = (
|
|
15
|
+
enableHighAccuracy: boolean = true,
|
|
16
|
+
onSuccess: (data: LocationData) => void,
|
|
17
|
+
onError?: (error: unknown) => void,
|
|
18
|
+
): UnsubscribeFn => {
|
|
19
|
+
let unsubscribePromise: Promise<void> | null = null;
|
|
20
|
+
|
|
21
|
+
const handle = subscribeToHostEvent<LocationData>(
|
|
22
|
+
'locationChange',
|
|
23
|
+
{
|
|
24
|
+
enableHighAccuracy,
|
|
25
|
+
},
|
|
26
|
+
onSuccess,
|
|
27
|
+
).catch(error => {
|
|
28
|
+
onError?.(error);
|
|
29
|
+
throw error;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return () => {
|
|
33
|
+
if (!unsubscribePromise) {
|
|
34
|
+
unsubscribePromise = handle
|
|
35
|
+
.then(subscription => subscription.unsubscribe())
|
|
36
|
+
.catch(() => {});
|
|
37
|
+
}
|
|
38
|
+
return unsubscribePromise;
|
|
39
|
+
};
|
|
40
|
+
};
|
package/src/media.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { invokeHostApi } from './runtime/host';
|
|
2
|
+
|
|
3
|
+
export type MediaType = 'photo' | 'video';
|
|
4
|
+
|
|
5
|
+
export interface SaveMediaOptions {
|
|
6
|
+
album?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const saveMedia = (
|
|
10
|
+
url: string,
|
|
11
|
+
type: MediaType,
|
|
12
|
+
options?: SaveMediaOptions,
|
|
13
|
+
) => {
|
|
14
|
+
return invokeHostApi<string>('saveMedia', {
|
|
15
|
+
url,
|
|
16
|
+
type,
|
|
17
|
+
album: options?.album,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MiniAppUpdateInfo } from '@nebula-rn/sdk';
|
|
2
|
+
import { invokeHostApi } from '../runtime/host';
|
|
3
|
+
|
|
4
|
+
export function getMiniAppUpdateInfo(): Promise<MiniAppUpdateInfo> {
|
|
5
|
+
return invokeHostApi<MiniAppUpdateInfo>(
|
|
6
|
+
'getMiniAppUpdateInfo',
|
|
7
|
+
{},
|
|
8
|
+
'1.0',
|
|
9
|
+
15000,
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function applyMiniAppUpdate(): Promise<MiniAppUpdateInfo> {
|
|
14
|
+
return invokeHostApi<MiniAppUpdateInfo>(
|
|
15
|
+
'applyMiniAppUpdate',
|
|
16
|
+
{},
|
|
17
|
+
'1.0',
|
|
18
|
+
120000,
|
|
19
|
+
);
|
|
20
|
+
}
|
package/src/network.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { invokeHostApi, subscribeToHostEvent } from './runtime/host';
|
|
2
|
+
|
|
3
|
+
export interface GetNetworkTypeResult {
|
|
4
|
+
networkType: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface NetworkStatusChangeResult {
|
|
8
|
+
isConnected: boolean;
|
|
9
|
+
networkType: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const getNetworkType = async () => {
|
|
13
|
+
const result = await invokeHostApi<GetNetworkTypeResult>('getNetworkType');
|
|
14
|
+
return result.networkType;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const onNetworkStatusChange = (
|
|
18
|
+
callback: (res: NetworkStatusChangeResult) => void,
|
|
19
|
+
) => {
|
|
20
|
+
let unsubscribePromise: Promise<void> | null = null;
|
|
21
|
+
|
|
22
|
+
const handle = subscribeToHostEvent<NetworkStatusChangeResult>(
|
|
23
|
+
'networkStatusChange',
|
|
24
|
+
{},
|
|
25
|
+
callback,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return () => {
|
|
29
|
+
if (!unsubscribePromise) {
|
|
30
|
+
unsubscribePromise = handle.then(subscription =>
|
|
31
|
+
subscription.unsubscribe(),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return unsubscribePromise;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { subscribeToHostEvent } from '../runtime/host';
|
|
2
|
+
|
|
3
|
+
export const onUserCaptureScreen = (callback: () => void) => {
|
|
4
|
+
let unsubscribePromise: Promise<void> | null = null;
|
|
5
|
+
const handle = subscribeToHostEvent<null>('userCaptureScreen', {}, () =>
|
|
6
|
+
callback(),
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
return () => {
|
|
10
|
+
if (!unsubscribePromise) {
|
|
11
|
+
unsubscribePromise = handle.then(subscription =>
|
|
12
|
+
subscription.unsubscribe(),
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return unsubscribePromise;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { invokeHostApi } from '../runtime/host';
|
|
2
|
+
|
|
3
|
+
export interface PreviewImageOptions {
|
|
4
|
+
urls: string[];
|
|
5
|
+
current?: string;
|
|
6
|
+
showMenu?: boolean;
|
|
7
|
+
saveMediaText?: string;
|
|
8
|
+
cancelText?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function previewImages(options: PreviewImageOptions): Promise<void> {
|
|
12
|
+
return invokeHostApi<void>('previewImage', options, '1.0', 120000);
|
|
13
|
+
}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import { Miniapp } from '@nebula-rn/sdk';
|
|
2
|
+
import type { NebulaApiInvokeResult } from '@nebula-rn/sdk';
|
|
3
|
+
|
|
4
|
+
export type HostApiEventMessage<TPayload = unknown> = {
|
|
5
|
+
__nebulaApiEvent: 'v1';
|
|
6
|
+
apiName: string;
|
|
7
|
+
channel: string;
|
|
8
|
+
subscriptionId?: string;
|
|
9
|
+
taskId?: string;
|
|
10
|
+
payload?: TPayload;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type HostEventListener<TPayload> = (payload: TPayload) => void;
|
|
14
|
+
|
|
15
|
+
type HostTaskProgressListener<TProgress> = (payload: TProgress) => void;
|
|
16
|
+
type HostTaskHeadersListener<THeaders> = (payload: THeaders) => void;
|
|
17
|
+
|
|
18
|
+
export type HostTask<TData, TProgress, THeaders> = {
|
|
19
|
+
abort(): Promise<void>;
|
|
20
|
+
onProgressUpdate(listener: HostTaskProgressListener<TProgress>): void;
|
|
21
|
+
offProgressUpdate(listener: HostTaskProgressListener<TProgress>): void;
|
|
22
|
+
onHeadersReceived(listener: HostTaskHeadersListener<THeaders>): void;
|
|
23
|
+
offHeadersReceived(listener: HostTaskHeadersListener<THeaders>): void;
|
|
24
|
+
then<TResult1 = TData, TResult2 = never>(
|
|
25
|
+
onfulfilled?:
|
|
26
|
+
((value: TData) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
|
27
|
+
onrejected?:
|
|
28
|
+
| ((reason: unknown) => TResult2 | PromiseLike<TResult2>)
|
|
29
|
+
| undefined
|
|
30
|
+
| null,
|
|
31
|
+
): Promise<TResult1 | TResult2>;
|
|
32
|
+
catch<TResult = never>(
|
|
33
|
+
onrejected?:
|
|
34
|
+
((reason: unknown) => TResult | PromiseLike<TResult>) | undefined | null,
|
|
35
|
+
): Promise<TData | TResult>;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type HostSubscriptionHandle = {
|
|
39
|
+
subscriptionId: string;
|
|
40
|
+
unsubscribe: () => Promise<void>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type HostApiError = {
|
|
44
|
+
code?: unknown;
|
|
45
|
+
message?: unknown;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
49
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isHostApiEventMessage(
|
|
53
|
+
value: Record<string, unknown>,
|
|
54
|
+
): value is HostApiEventMessage {
|
|
55
|
+
return (
|
|
56
|
+
value.__nebulaApiEvent === 'v1' &&
|
|
57
|
+
typeof value.apiName === 'string' &&
|
|
58
|
+
typeof value.channel === 'string'
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function createHostApiError(
|
|
63
|
+
apiName: string,
|
|
64
|
+
error: unknown,
|
|
65
|
+
fallbackCode = 'HOST_API_FAILED',
|
|
66
|
+
): Error & { code: string } {
|
|
67
|
+
const details = isRecord(error) ? (error as HostApiError) : undefined;
|
|
68
|
+
const code = typeof details?.code === 'string' ? details.code : fallbackCode;
|
|
69
|
+
const message =
|
|
70
|
+
typeof details?.message === 'string'
|
|
71
|
+
? details.message
|
|
72
|
+
: error instanceof Error
|
|
73
|
+
? error.message
|
|
74
|
+
: `${apiName}:fail host request failed`;
|
|
75
|
+
|
|
76
|
+
const hostError = new Error(message) as Error & { code: string };
|
|
77
|
+
hostError.code = code;
|
|
78
|
+
return hostError;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function invokeHostApi<TData = unknown>(
|
|
82
|
+
apiName: string,
|
|
83
|
+
payload: object = {},
|
|
84
|
+
version = '1.0',
|
|
85
|
+
timeoutMs = 15000,
|
|
86
|
+
): Promise<TData> {
|
|
87
|
+
const result = await Miniapp.invokeHostApi<TData>(
|
|
88
|
+
apiName,
|
|
89
|
+
payload as Record<string, unknown>,
|
|
90
|
+
version,
|
|
91
|
+
timeoutMs,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (!result.ok) {
|
|
95
|
+
throw createHostApiError(apiName, result.error);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return result.data;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function invokeHostApiResult<TData = unknown>(
|
|
102
|
+
apiName: string,
|
|
103
|
+
payload: object = {},
|
|
104
|
+
version = '1.0',
|
|
105
|
+
timeoutMs = 15000,
|
|
106
|
+
): Promise<NebulaApiInvokeResult<TData>> {
|
|
107
|
+
return Miniapp.invokeHostApi<TData>(
|
|
108
|
+
apiName,
|
|
109
|
+
payload as Record<string, unknown>,
|
|
110
|
+
version,
|
|
111
|
+
timeoutMs,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function addHostApiEventListener<TPayload = unknown>(
|
|
116
|
+
apiName: string,
|
|
117
|
+
channel: string,
|
|
118
|
+
listener: HostEventListener<TPayload>,
|
|
119
|
+
matcher?: (message: HostApiEventMessage<TPayload>) => boolean,
|
|
120
|
+
): () => void {
|
|
121
|
+
return Miniapp.onHostMessage(event => {
|
|
122
|
+
const { message } = event;
|
|
123
|
+
if (!isRecord(message) || !isHostApiEventMessage(message)) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (message.apiName !== apiName || message.channel !== channel) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const typedMessage = message as HostApiEventMessage<TPayload>;
|
|
132
|
+
|
|
133
|
+
if (matcher && !matcher(typedMessage)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
listener((typedMessage.payload ?? null) as TPayload);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function subscribeToHostEvent<TPayload = unknown>(
|
|
142
|
+
apiName: string,
|
|
143
|
+
payload: object,
|
|
144
|
+
onEvent: HostEventListener<TPayload>,
|
|
145
|
+
options?: {
|
|
146
|
+
version?: string;
|
|
147
|
+
timeoutMs?: number;
|
|
148
|
+
unsubscribePayload?: object;
|
|
149
|
+
},
|
|
150
|
+
): Promise<HostSubscriptionHandle> {
|
|
151
|
+
const version = options?.version ?? '1.0';
|
|
152
|
+
const timeoutMs = options?.timeoutMs ?? 15000;
|
|
153
|
+
const result = await invokeHostApi<{
|
|
154
|
+
subscriptionId: string;
|
|
155
|
+
}>(`${apiName}.subscribe`, payload, version, timeoutMs);
|
|
156
|
+
|
|
157
|
+
const stopListening = addHostApiEventListener<TPayload>(
|
|
158
|
+
apiName,
|
|
159
|
+
'subscription',
|
|
160
|
+
onEvent,
|
|
161
|
+
message => message.subscriptionId === result.subscriptionId,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
subscriptionId: result.subscriptionId,
|
|
166
|
+
unsubscribe: async () => {
|
|
167
|
+
stopListening();
|
|
168
|
+
await invokeHostApi(
|
|
169
|
+
`${apiName}.unsubscribe`,
|
|
170
|
+
{
|
|
171
|
+
subscriptionId: result.subscriptionId,
|
|
172
|
+
...(options?.unsubscribePayload ?? {}),
|
|
173
|
+
},
|
|
174
|
+
version,
|
|
175
|
+
timeoutMs,
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
class HostTaskImpl<TData, TProgress, THeaders> implements HostTask<
|
|
182
|
+
TData,
|
|
183
|
+
TProgress,
|
|
184
|
+
THeaders
|
|
185
|
+
> {
|
|
186
|
+
private readonly promise: Promise<TData>;
|
|
187
|
+
private readonly aborter: () => Promise<void>;
|
|
188
|
+
private readonly progressListeners = new Set<
|
|
189
|
+
HostTaskProgressListener<TProgress>
|
|
190
|
+
>();
|
|
191
|
+
private readonly headersListeners = new Set<
|
|
192
|
+
HostTaskHeadersListener<THeaders>
|
|
193
|
+
>();
|
|
194
|
+
private readonly cleanup: () => void;
|
|
195
|
+
|
|
196
|
+
constructor(
|
|
197
|
+
promise: Promise<TData>,
|
|
198
|
+
aborter: () => Promise<void>,
|
|
199
|
+
cleanup: () => void,
|
|
200
|
+
) {
|
|
201
|
+
this.promise = promise;
|
|
202
|
+
this.aborter = aborter;
|
|
203
|
+
this.cleanup = cleanup;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
abort(): Promise<void> {
|
|
207
|
+
this.cleanup();
|
|
208
|
+
return this.aborter();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
onProgressUpdate(listener: HostTaskProgressListener<TProgress>): void {
|
|
212
|
+
this.progressListeners.add(listener);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
offProgressUpdate(listener: HostTaskProgressListener<TProgress>): void {
|
|
216
|
+
this.progressListeners.delete(listener);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
onHeadersReceived(listener: HostTaskHeadersListener<THeaders>): void {
|
|
220
|
+
this.headersListeners.add(listener);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
offHeadersReceived(listener: HostTaskHeadersListener<THeaders>): void {
|
|
224
|
+
this.headersListeners.delete(listener);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
emitProgress(payload: TProgress): void {
|
|
228
|
+
this.progressListeners.forEach(listener => listener(payload));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
emitHeaders(payload: THeaders): void {
|
|
232
|
+
this.headersListeners.forEach(listener => listener(payload));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
then<TResult1 = TData, TResult2 = never>(
|
|
236
|
+
onfulfilled?:
|
|
237
|
+
((value: TData) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
|
238
|
+
onrejected?:
|
|
239
|
+
| ((reason: unknown) => TResult2 | PromiseLike<TResult2>)
|
|
240
|
+
| undefined
|
|
241
|
+
| null,
|
|
242
|
+
): Promise<TResult1 | TResult2> {
|
|
243
|
+
return this.promise.then(onfulfilled, onrejected);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
catch<TResult = never>(
|
|
247
|
+
onrejected?:
|
|
248
|
+
((reason: unknown) => TResult | PromiseLike<TResult>) | undefined | null,
|
|
249
|
+
): Promise<TData | TResult> {
|
|
250
|
+
return this.promise.catch(onrejected);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function createHostTask<TData, TProgress, THeaders>(
|
|
255
|
+
apiName: string,
|
|
256
|
+
payload: object,
|
|
257
|
+
options?: {
|
|
258
|
+
version?: string;
|
|
259
|
+
timeoutMs?: number;
|
|
260
|
+
},
|
|
261
|
+
): HostTask<TData, TProgress, THeaders> {
|
|
262
|
+
const version = options?.version ?? '1.0';
|
|
263
|
+
const timeoutMs = options?.timeoutMs ?? 15000;
|
|
264
|
+
let stopResultListener = () => {};
|
|
265
|
+
let stopProgressListener = () => {};
|
|
266
|
+
let stopHeadersListener = () => {};
|
|
267
|
+
let startedTaskId: string | null = null;
|
|
268
|
+
|
|
269
|
+
function cleanup() {
|
|
270
|
+
stopResultListener();
|
|
271
|
+
stopProgressListener();
|
|
272
|
+
stopHeadersListener();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const startTask = invokeHostApi<{ taskId: string }>(
|
|
276
|
+
`${apiName}.start`,
|
|
277
|
+
payload,
|
|
278
|
+
version,
|
|
279
|
+
timeoutMs,
|
|
280
|
+
);
|
|
281
|
+
const promise = startTask.then(
|
|
282
|
+
({ taskId }) =>
|
|
283
|
+
new Promise<TData>((resolve, reject) => {
|
|
284
|
+
startedTaskId = taskId;
|
|
285
|
+
|
|
286
|
+
stopResultListener = addHostApiEventListener<
|
|
287
|
+
NebulaApiInvokeResult<TData> | TData
|
|
288
|
+
>(
|
|
289
|
+
apiName,
|
|
290
|
+
'task.result',
|
|
291
|
+
resultPayload => {
|
|
292
|
+
cleanup();
|
|
293
|
+
if (
|
|
294
|
+
isRecord(resultPayload) &&
|
|
295
|
+
typeof resultPayload.ok === 'boolean'
|
|
296
|
+
) {
|
|
297
|
+
const result = resultPayload as NebulaApiInvokeResult<TData>;
|
|
298
|
+
if (result.ok) {
|
|
299
|
+
resolve(result.data);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
reject(createHostApiError(apiName, result.error));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
resolve(resultPayload as TData);
|
|
306
|
+
},
|
|
307
|
+
message => message.taskId === taskId,
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
stopProgressListener = addHostApiEventListener<TProgress>(
|
|
311
|
+
apiName,
|
|
312
|
+
'task.progress',
|
|
313
|
+
progressPayload => {
|
|
314
|
+
task.emitProgress(progressPayload);
|
|
315
|
+
},
|
|
316
|
+
message => message.taskId === taskId,
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
stopHeadersListener = addHostApiEventListener<THeaders>(
|
|
320
|
+
apiName,
|
|
321
|
+
'task.headers',
|
|
322
|
+
headersPayload => {
|
|
323
|
+
task.emitHeaders(headersPayload);
|
|
324
|
+
},
|
|
325
|
+
message => message.taskId === taskId,
|
|
326
|
+
);
|
|
327
|
+
}),
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
const task = new HostTaskImpl<TData, TProgress, THeaders>(
|
|
331
|
+
promise,
|
|
332
|
+
async () => {
|
|
333
|
+
cleanup();
|
|
334
|
+
const taskId =
|
|
335
|
+
startedTaskId ??
|
|
336
|
+
(await startTask.then(
|
|
337
|
+
result => result.taskId,
|
|
338
|
+
() => null,
|
|
339
|
+
));
|
|
340
|
+
if (!taskId) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
await invokeHostApi(
|
|
344
|
+
`${apiName}.abort`,
|
|
345
|
+
{
|
|
346
|
+
taskId,
|
|
347
|
+
},
|
|
348
|
+
version,
|
|
349
|
+
timeoutMs,
|
|
350
|
+
);
|
|
351
|
+
},
|
|
352
|
+
cleanup,
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
return task;
|
|
356
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ScanCodeError } from './types';
|
|
2
|
+
import type {
|
|
3
|
+
ScanCodeCapabilityName,
|
|
4
|
+
ScanCodeCapabilityVersion,
|
|
5
|
+
ScanCodeErrorCode,
|
|
6
|
+
} from './types';
|
|
7
|
+
|
|
8
|
+
export const SCAN_CODE_CAPABILITY_NAME: ScanCodeCapabilityName = 'scanCode';
|
|
9
|
+
export const SCAN_CODE_CAPABILITY_VERSION: ScanCodeCapabilityVersion = '1.0';
|
|
10
|
+
|
|
11
|
+
export const SCAN_CODE_DEFAULT_TYPES = ['qr', 'ean-13', 'code-128'] as const;
|
|
12
|
+
|
|
13
|
+
export const SCAN_CODE_MINIMUM_HOST_BRIDGE_VERSION = '1.0';
|
|
14
|
+
|
|
15
|
+
export function createScanCodeError(
|
|
16
|
+
code: ScanCodeErrorCode,
|
|
17
|
+
message: string,
|
|
18
|
+
): ScanCodeError {
|
|
19
|
+
return new ScanCodeError(code, message);
|
|
20
|
+
}
|
|
Binary file
|
|
Binary file
|