@zimi/remote 0.2.0 → 0.2.1-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/adaptors/http.js +1 -0
- package/dist/adaptors/http.js.map +1 -1
- package/dist/adaptors/iframe.js +1 -0
- package/dist/adaptors/iframe.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/remoteValue/exposeToRemote.d.ts +15 -0
- package/dist/remoteValue/exposeToRemote.js +47 -0
- package/dist/remoteValue/exposeToRemote.js.map +1 -0
- package/dist/remoteValue/remoteValue.d.ts +26 -0
- package/dist/remoteValue/remoteValue.js +65 -0
- package/dist/remoteValue/remoteValue.js.map +1 -0
- package/package.json +1 -1
- package/src/adaptor.d.ts +1 -0
- package/src/adaptors/http.ts +1 -0
- package/src/adaptors/iframe.ts +1 -0
- package/src/index.ts +2 -0
- package/src/remoteValue/exposeToRemote.ts +64 -0
- package/src/remoteValue/remoteValue.ts +81 -0
- package/src/remoteValue/type.d.ts +115 -0
package/README.md
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
- 本地可以是浏览器、服务器,甚至一些受限的 `js` 子集
|
|
4
4
|
- 远端可以是任何终端,如 `iframe` / `Java` 服务器 等
|
|
5
5
|
- 对远端响应的数据格式也不严格限制(可以集中解析)
|
|
6
|
+
- 已在公司游戏前后端通信中应用,极大地降低了通信成本(简化调用)
|
|
7
|
+
- ts 类型严格
|
|
6
8
|
|
|
7
9
|
## install
|
|
8
10
|
```
|
|
@@ -11,7 +13,7 @@ pnpm i @zimi/remote
|
|
|
11
13
|
|
|
12
14
|
## examples
|
|
13
15
|
|
|
14
|
-
###
|
|
16
|
+
### 调用示意
|
|
15
17
|
|
|
16
18
|
```ts
|
|
17
19
|
|
package/dist/adaptors/http.js
CHANGED
|
@@ -17,6 +17,7 @@ export const remoteEventManager = new RemoteEventManager();
|
|
|
17
17
|
export function createHttpAdaptor({ onEmit, }) {
|
|
18
18
|
const adaptor = {
|
|
19
19
|
every: remoteEventManager.onEvery.bind(remoteEventManager),
|
|
20
|
+
on: remoteEventManager.on.bind(remoteEventManager),
|
|
20
21
|
once: remoteEventManager.once.bind(remoteEventManager),
|
|
21
22
|
off: remoteEventManager.off.bind(remoteEventManager),
|
|
22
23
|
emit: onEmit,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/adaptors/http.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;AAIxC,MAAM,kBAAmB,SAAQ,YAE/B;IAFF;;QAGE;;;;mBAAmB,kBAAkB;WAAA;IAKvC,CAAC;IAHC,OAAO,CAAC,EAAsC;QAC5C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;IACpC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,EAAE,CAAA;AAE1D,MAAM,UAAU,iBAAiB,CAAC,EAChC,MAAM,GAGP;IACC,MAAM,OAAO,GAAY;QACvB,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC1D,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACtD,GAAG,EAAE,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACpD,IAAI,EAAE,MAAM;KACb,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/adaptors/http.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;AAIxC,MAAM,kBAAmB,SAAQ,YAE/B;IAFF;;QAGE;;;;mBAAmB,kBAAkB;WAAA;IAKvC,CAAC;IAHC,OAAO,CAAC,EAAsC;QAC5C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;IACpC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,EAAE,CAAA;AAE1D,MAAM,UAAU,iBAAiB,CAAC,EAChC,MAAM,GAGP;IACC,MAAM,OAAO,GAAY;QACvB,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC1D,EAAE,EAAE,kBAAkB,CAAC,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAClD,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACtD,GAAG,EAAE,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACpD,IAAI,EAAE,MAAM;KACb,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
package/dist/adaptors/iframe.js
CHANGED
|
@@ -29,6 +29,7 @@ export function createIframeAdaptor({ onEmit, }) {
|
|
|
29
29
|
const remoteEventManager = new RemoteEventManager();
|
|
30
30
|
const adaptor = {
|
|
31
31
|
every: remoteEventManager.onEvery.bind(remoteEventManager),
|
|
32
|
+
on: remoteEventManager.on.bind(remoteEventManager),
|
|
32
33
|
once: remoteEventManager.once.bind(remoteEventManager),
|
|
33
34
|
off: remoteEventManager.off.bind(remoteEventManager),
|
|
34
35
|
emit: onEmit,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iframe.js","sourceRoot":"","sources":["../../src/adaptors/iframe.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAI/C,MAAM,kBAAmB,SAAQ,YAE/B;IAGA;QACE,KAAK,EAAE,CAAA;QAHT;;;;mBAAmB,kBAAkB;WAAA;QAInC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAM;QACR,CAAC;QACD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YAC3C,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;YACtB,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;gBAC1B,oCAAoC;gBACpC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAA;YACxC,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,CAAC,EAAsC;QAC5C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;IACpC,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAC,EAClC,MAAM,GAGP;IACC,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,EAAE,CAAA;IAEnD,MAAM,OAAO,GAAY;QACvB,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC1D,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACtD,GAAG,EAAE,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACpD,IAAI,EAAE,MAAM;KACb,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
1
|
+
{"version":3,"file":"iframe.js","sourceRoot":"","sources":["../../src/adaptors/iframe.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAI/C,MAAM,kBAAmB,SAAQ,YAE/B;IAGA;QACE,KAAK,EAAE,CAAA;QAHT;;;;mBAAmB,kBAAkB;WAAA;QAInC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAM;QACR,CAAC;QACD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YAC3C,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;YACtB,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;gBAC1B,oCAAoC;gBACpC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAA;YACxC,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,CAAC,EAAsC;QAC5C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;IACpC,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAC,EAClC,MAAM,GAGP;IACC,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,EAAE,CAAA;IAEnD,MAAM,OAAO,GAAY;QACvB,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC1D,EAAE,EAAE,kBAAkB,CAAC,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAClD,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACtD,GAAG,EAAE,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACpD,IAAI,EAAE,MAAM;KACb,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,3 +3,5 @@ export type { AdaptorPackageData, Adaptor } from './adaptor';
|
|
|
3
3
|
export { RemoteError, RemoteNotFoundError, RemoteTimeoutError, response, } from './response';
|
|
4
4
|
export { createIframeAdaptor } from './adaptors/iframe';
|
|
5
5
|
export { createHttpAdaptor, remoteEventManager } from './adaptors/http';
|
|
6
|
+
export { remoteValue } from './remoteValue/remoteValue';
|
|
7
|
+
export { exposeToRemote } from './remoteValue/exposeToRemote';
|
package/dist/index.js
CHANGED
|
@@ -2,4 +2,6 @@ export { Remote, isRemoteAdaptorData } from './remote';
|
|
|
2
2
|
export { RemoteError, RemoteNotFoundError, RemoteTimeoutError, response, } from './response';
|
|
3
3
|
export { createIframeAdaptor } from './adaptors/iframe';
|
|
4
4
|
export { createHttpAdaptor, remoteEventManager } from './adaptors/http';
|
|
5
|
+
export { remoteValue } from './remoteValue/remoteValue';
|
|
6
|
+
export { exposeToRemote } from './remoteValue/exposeToRemote';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEtD,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,GACT,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEtD,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,GACT,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Adaptor, AdaptorPackageData } from '../adaptor';
|
|
2
|
+
interface ExposeProps {
|
|
3
|
+
globalName: string;
|
|
4
|
+
adaptor: Adaptor;
|
|
5
|
+
/**
|
|
6
|
+
* ['*'] or ['device_id_1', 'device_id_2']
|
|
7
|
+
*/
|
|
8
|
+
exposeTo: string[];
|
|
9
|
+
/**
|
|
10
|
+
* 你可以在该回调中抛错,以阻止远程调用
|
|
11
|
+
*/
|
|
12
|
+
onRequest?: (e: AdaptorPackageData) => void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare function exposeToRemote<T extends object>(obj: T, options: ExposeProps): () => void;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { RemoteError, response } from '../response';
|
|
2
|
+
function defaultOnRequest(e) {
|
|
3
|
+
return e;
|
|
4
|
+
}
|
|
5
|
+
export function exposeToRemote(obj, options) {
|
|
6
|
+
const { globalName, adaptor, exposeTo, onRequest = defaultOnRequest, } = options;
|
|
7
|
+
const callback = async (e) => {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
try {
|
|
10
|
+
await onRequest(e);
|
|
11
|
+
if (!exposeTo.includes(e.deviceId) && !exposeTo.includes('*')) {
|
|
12
|
+
throw new RemoteError('permission denied');
|
|
13
|
+
}
|
|
14
|
+
const { paths, args } = e.data;
|
|
15
|
+
let target = obj;
|
|
16
|
+
for (let i = 0; i < paths.length; i += 1) {
|
|
17
|
+
target = target[paths[i]];
|
|
18
|
+
}
|
|
19
|
+
let res;
|
|
20
|
+
if (target instanceof Function) {
|
|
21
|
+
res = await target(...args);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
res = target;
|
|
25
|
+
}
|
|
26
|
+
adaptor.emit({
|
|
27
|
+
name: (_a = e.callbackName) !== null && _a !== void 0 ? _a : 'IMPOSSIBLE_NO_CALLBACK_NAME',
|
|
28
|
+
deviceId: e.targetDeviceId,
|
|
29
|
+
targetDeviceId: e.deviceId,
|
|
30
|
+
data: response.success(res),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
adaptor.emit({
|
|
35
|
+
name: (_b = e.callbackName) !== null && _b !== void 0 ? _b : 'IMPOSSIBLE_NO_CALLBACK_NAME',
|
|
36
|
+
deviceId: e.targetDeviceId,
|
|
37
|
+
targetDeviceId: e.deviceId,
|
|
38
|
+
data: response.error(RemoteError.fromError(error)),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
adaptor.on(`__REMOTE_VALUE_REQ__${globalName}`, callback);
|
|
43
|
+
return () => {
|
|
44
|
+
adaptor.off(`__REMOTE_VALUE_REQ__${globalName}`, callback);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=exposeToRemote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exposeToRemote.js","sourceRoot":"","sources":["../../src/remoteValue/exposeToRemote.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAenD,SAAS,gBAAgB,CAAC,CAAqB;IAC7C,OAAO,CAAC,CAAA;AACV,CAAC;AAED,MAAM,UAAU,cAAc,CAAmB,GAAM,EAAE,OAAoB;IAC3E,MAAM,EACJ,UAAU,EACV,OAAO,EACP,QAAQ,EACR,SAAS,GAAG,gBAAgB,GAC7B,GAAG,OAAO,CAAA;IACX,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAqB,EAAE,EAAE;;QAC/C,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,CAAC,CAAC,CAAA;YAClB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9D,MAAM,IAAI,WAAW,CAAC,mBAAmB,CAAC,CAAA;YAC5C,CAAC;YACD,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAA4C,CAAA;YACtE,IAAI,MAAM,GAAG,GAAG,CAAA;YAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAwB,CAAkB,CAAA;YACnE,CAAC;YACD,IAAI,GAAY,CAAA;YAChB,IAAI,MAAM,YAAY,QAAQ,EAAE,CAAC;gBAC/B,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;YAC7B,CAAC;iBAAM,CAAC;gBACN,GAAG,GAAG,MAAM,CAAA;YACd,CAAC;YACD,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAA,CAAC,CAAC,YAAY,mCAAI,6BAA6B;gBACrD,QAAQ,EAAE,CAAC,CAAC,cAAc;gBAC1B,cAAc,EAAE,CAAC,CAAC,QAAQ;gBAC1B,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC;aAC5B,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAA,CAAC,CAAC,YAAY,mCAAI,6BAA6B;gBACrD,QAAQ,EAAE,CAAC,CAAC,cAAc;gBAC1B,cAAc,EAAE,CAAC,CAAC,QAAQ;gBAC1B,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;aACnD,CAAC,CAAA;QACJ,CAAC;IACH,CAAC,CAAA;IACD,OAAO,CAAC,EAAE,CAAC,uBAAuB,UAAU,EAAE,EAAE,QAAQ,CAAC,CAAA;IACzD,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,GAAG,CAAC,uBAAuB,UAAU,EAAE,EAAE,QAAQ,CAAC,CAAA;IAC5D,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Adaptor, AdaptorPackageData } from '../adaptor';
|
|
2
|
+
import type { ToFunc } from './type';
|
|
3
|
+
type RemoteValueProps = Pick<AdaptorPackageData, 'deviceId' | 'targetDeviceId'> & {
|
|
4
|
+
globalName: string;
|
|
5
|
+
adaptor: Adaptor;
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* @example
|
|
10
|
+
* ```
|
|
11
|
+
* const obj = remoteValue<{
|
|
12
|
+
* a: number;
|
|
13
|
+
* b: {
|
|
14
|
+
* c: string;
|
|
15
|
+
* };
|
|
16
|
+
* funcD: () => number
|
|
17
|
+
* }>()
|
|
18
|
+
*
|
|
19
|
+
* const val_1 = await obj.a() // number
|
|
20
|
+
* const val_2 = await obj.b() // { c: string }
|
|
21
|
+
* const val_3 = await obj.b.c() // string
|
|
22
|
+
* const val_4 = await obj.funcD() // number
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function remoteValue<T extends object>(props: RemoteValueProps): ToFunc<T>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { RemoteError, RemoteTimeoutError } from '../response';
|
|
2
|
+
function noop() {
|
|
3
|
+
// pass
|
|
4
|
+
}
|
|
5
|
+
function geneProxy(paths, props) {
|
|
6
|
+
return new Proxy(noop, {
|
|
7
|
+
apply(target, thisArg, argArray) {
|
|
8
|
+
const { adaptor, globalName, timeoutMs = 30000, ...restProps } = props;
|
|
9
|
+
const randomStr = Math.random().toString(36).slice(2);
|
|
10
|
+
const name = `__REMOTE_VALUE_REQ__${globalName}`;
|
|
11
|
+
const responseName = `__REMOTE_VALUE_RES__${[globalName, ...paths].join('.')}-${randomStr}`;
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
let timer;
|
|
14
|
+
const callback = (e) => {
|
|
15
|
+
var _a;
|
|
16
|
+
clearTimeout(timer);
|
|
17
|
+
if (RemoteError.isRemoteError(e.data)) {
|
|
18
|
+
reject(RemoteError.fromError(e.data));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
resolve((_a = e.data) === null || _a === void 0 ? void 0 : _a.data);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
adaptor.once(responseName, callback);
|
|
25
|
+
timer = setTimeout(() => {
|
|
26
|
+
adaptor.off(responseName, callback);
|
|
27
|
+
reject(new RemoteTimeoutError(`timeout: ${[globalName, ...paths].join('.')}`));
|
|
28
|
+
}, timeoutMs);
|
|
29
|
+
adaptor.emit({
|
|
30
|
+
name,
|
|
31
|
+
callbackName: responseName,
|
|
32
|
+
...restProps,
|
|
33
|
+
data: {
|
|
34
|
+
paths,
|
|
35
|
+
args: argArray,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
get(target, prop) {
|
|
41
|
+
return geneProxy([...paths, prop], props);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* @example
|
|
47
|
+
* ```
|
|
48
|
+
* const obj = remoteValue<{
|
|
49
|
+
* a: number;
|
|
50
|
+
* b: {
|
|
51
|
+
* c: string;
|
|
52
|
+
* };
|
|
53
|
+
* funcD: () => number
|
|
54
|
+
* }>()
|
|
55
|
+
*
|
|
56
|
+
* const val_1 = await obj.a() // number
|
|
57
|
+
* const val_2 = await obj.b() // { c: string }
|
|
58
|
+
* const val_3 = await obj.b.c() // string
|
|
59
|
+
* const val_4 = await obj.funcD() // number
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function remoteValue(props) {
|
|
63
|
+
return geneProxy([], props);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=remoteValue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remoteValue.js","sourceRoot":"","sources":["../../src/remoteValue/remoteValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAY,MAAM,aAAa,CAAA;AAIvE,SAAS,IAAI;IACX,OAAO;AACT,CAAC;AAWD,SAAS,SAAS,CAAmB,KAAe,EAAE,KAAuB;IAC3E,OAAO,IAAI,KAAK,CAAY,IAA4B,EAAE;QACxD,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ;YAC7B,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,SAAS,EAAE,GAAG,KAAK,CAAA;YACtE,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACrD,MAAM,IAAI,GAAG,uBAAuB,UAAU,EAAE,CAAA;YAChD,MAAM,YAAY,GAAG,uBAAuB,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,EAAE,CAAA;YAE3F,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,IAAI,KAAiC,CAAA;gBACrC,MAAM,QAAQ,GAAoB,CAAC,CAAC,EAAE,EAAE;;oBACtC,YAAY,CAAC,KAAK,CAAC,CAAA;oBACnB,IAAI,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;wBACtC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;oBACvC,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,MAAC,CAAC,CAAC,IAA4C,0CAAE,IAAI,CAAC,CAAA;oBAChE,CAAC;gBACH,CAAC,CAAA;gBACD,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;gBACpC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBACtB,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;oBACnC,MAAM,CACJ,IAAI,kBAAkB,CACpB,YAAY,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAC/C,CACF,CAAA;gBACH,CAAC,EAAE,SAAS,CAAC,CAAA;gBACb,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI;oBACJ,YAAY,EAAE,YAAY;oBAC1B,GAAG,SAAS;oBACZ,IAAI,EAAE;wBACJ,KAAK;wBACL,IAAI,EAAE,QAAQ;qBACf;iBACF,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC;QACD,GAAG,CAAC,MAAM,EAAE,IAAI;YACd,OAAO,SAAS,CAAC,CAAC,GAAG,KAAK,EAAE,IAAc,CAAC,EAAE,KAAK,CAAC,CAAA;QACrD,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,WAAW,CAAmB,KAAuB;IACnE,OAAO,SAAS,CAAI,EAAE,EAAE,KAAK,CAAC,CAAA;AAChC,CAAC"}
|
package/package.json
CHANGED
package/src/adaptor.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface Adaptor {
|
|
|
28
28
|
* off 用于移除 once 注册的事件,当事件超时后,需要主动 off
|
|
29
29
|
*/
|
|
30
30
|
off: (name: string, callback: AdaptorCallback) => void
|
|
31
|
+
on: (name: string, callback: AdaptorCallback) => void
|
|
31
32
|
once: (name: string, callback: AdaptorCallback) => void
|
|
32
33
|
emit: (data: AdaptorPackageData) => void
|
|
33
34
|
}
|
package/src/adaptors/http.ts
CHANGED
|
@@ -21,6 +21,7 @@ export function createHttpAdaptor({
|
|
|
21
21
|
}) {
|
|
22
22
|
const adaptor: Adaptor = {
|
|
23
23
|
every: remoteEventManager.onEvery.bind(remoteEventManager),
|
|
24
|
+
on: remoteEventManager.on.bind(remoteEventManager),
|
|
24
25
|
once: remoteEventManager.once.bind(remoteEventManager),
|
|
25
26
|
off: remoteEventManager.off.bind(remoteEventManager),
|
|
26
27
|
emit: onEmit,
|
package/src/adaptors/iframe.ts
CHANGED
|
@@ -37,6 +37,7 @@ export function createIframeAdaptor({
|
|
|
37
37
|
|
|
38
38
|
const adaptor: Adaptor = {
|
|
39
39
|
every: remoteEventManager.onEvery.bind(remoteEventManager),
|
|
40
|
+
on: remoteEventManager.on.bind(remoteEventManager),
|
|
40
41
|
once: remoteEventManager.once.bind(remoteEventManager),
|
|
41
42
|
off: remoteEventManager.off.bind(remoteEventManager),
|
|
42
43
|
emit: onEmit,
|
package/src/index.ts
CHANGED
|
@@ -8,3 +8,5 @@ export {
|
|
|
8
8
|
} from './response'
|
|
9
9
|
export { createIframeAdaptor } from './adaptors/iframe'
|
|
10
10
|
export { createHttpAdaptor, remoteEventManager } from './adaptors/http'
|
|
11
|
+
export { remoteValue } from './remoteValue/remoteValue'
|
|
12
|
+
export { exposeToRemote } from './remoteValue/exposeToRemote'
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Adaptor, AdaptorPackageData } from '../adaptor'
|
|
2
|
+
import { RemoteError, response } from '../response'
|
|
3
|
+
|
|
4
|
+
interface ExposeProps {
|
|
5
|
+
globalName: string
|
|
6
|
+
adaptor: Adaptor
|
|
7
|
+
/**
|
|
8
|
+
* ['*'] or ['device_id_1', 'device_id_2']
|
|
9
|
+
*/
|
|
10
|
+
exposeTo: string[]
|
|
11
|
+
/**
|
|
12
|
+
* 你可以在该回调中抛错,以阻止远程调用
|
|
13
|
+
*/
|
|
14
|
+
onRequest?: (e: AdaptorPackageData) => void | Promise<void>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function defaultOnRequest(e: AdaptorPackageData) {
|
|
18
|
+
return e
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function exposeToRemote<T extends object>(obj: T, options: ExposeProps) {
|
|
22
|
+
const {
|
|
23
|
+
globalName,
|
|
24
|
+
adaptor,
|
|
25
|
+
exposeTo,
|
|
26
|
+
onRequest = defaultOnRequest,
|
|
27
|
+
} = options
|
|
28
|
+
const callback = async (e: AdaptorPackageData) => {
|
|
29
|
+
try {
|
|
30
|
+
await onRequest(e)
|
|
31
|
+
if (!exposeTo.includes(e.deviceId) && !exposeTo.includes('*')) {
|
|
32
|
+
throw new RemoteError('permission denied')
|
|
33
|
+
}
|
|
34
|
+
const { paths, args } = e.data as { paths: string[]; args: unknown[] }
|
|
35
|
+
let target = obj
|
|
36
|
+
for (let i = 0; i < paths.length; i += 1) {
|
|
37
|
+
target = target[paths[i] as keyof typeof target] as typeof target
|
|
38
|
+
}
|
|
39
|
+
let res: unknown
|
|
40
|
+
if (target instanceof Function) {
|
|
41
|
+
res = await target(...args)
|
|
42
|
+
} else {
|
|
43
|
+
res = target
|
|
44
|
+
}
|
|
45
|
+
adaptor.emit({
|
|
46
|
+
name: e.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME',
|
|
47
|
+
deviceId: e.targetDeviceId,
|
|
48
|
+
targetDeviceId: e.deviceId,
|
|
49
|
+
data: response.success(res),
|
|
50
|
+
})
|
|
51
|
+
} catch (error) {
|
|
52
|
+
adaptor.emit({
|
|
53
|
+
name: e.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME',
|
|
54
|
+
deviceId: e.targetDeviceId,
|
|
55
|
+
targetDeviceId: e.deviceId,
|
|
56
|
+
data: response.error(RemoteError.fromError(error)),
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
adaptor.on(`__REMOTE_VALUE_REQ__${globalName}`, callback)
|
|
61
|
+
return () => {
|
|
62
|
+
adaptor.off(`__REMOTE_VALUE_REQ__${globalName}`, callback)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { RemoteError, RemoteTimeoutError, response } from '../response'
|
|
2
|
+
import { Adaptor, AdaptorCallback, AdaptorPackageData } from '../adaptor'
|
|
3
|
+
import type { ToFunc } from './type'
|
|
4
|
+
|
|
5
|
+
function noop() {
|
|
6
|
+
// pass
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type RemoteValueProps = Pick<
|
|
10
|
+
AdaptorPackageData,
|
|
11
|
+
'deviceId' | 'targetDeviceId'
|
|
12
|
+
> & {
|
|
13
|
+
globalName: string
|
|
14
|
+
adaptor: Adaptor
|
|
15
|
+
timeoutMs?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function geneProxy<T extends object>(paths: string[], props: RemoteValueProps) {
|
|
19
|
+
return new Proxy<ToFunc<T>>(noop as unknown as ToFunc<T>, {
|
|
20
|
+
apply(target, thisArg, argArray) {
|
|
21
|
+
const { adaptor, globalName, timeoutMs = 30000, ...restProps } = props
|
|
22
|
+
const randomStr = Math.random().toString(36).slice(2)
|
|
23
|
+
const name = `__REMOTE_VALUE_REQ__${globalName}`
|
|
24
|
+
const responseName = `__REMOTE_VALUE_RES__${[globalName, ...paths].join('.')}-${randomStr}`
|
|
25
|
+
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
let timer: NodeJS.Timeout | undefined
|
|
28
|
+
const callback: AdaptorCallback = (e) => {
|
|
29
|
+
clearTimeout(timer)
|
|
30
|
+
if (RemoteError.isRemoteError(e.data)) {
|
|
31
|
+
reject(RemoteError.fromError(e.data))
|
|
32
|
+
} else {
|
|
33
|
+
resolve((e.data as ReturnType<typeof response.success>)?.data)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
adaptor.once(responseName, callback)
|
|
37
|
+
timer = setTimeout(() => {
|
|
38
|
+
adaptor.off(responseName, callback)
|
|
39
|
+
reject(
|
|
40
|
+
new RemoteTimeoutError(
|
|
41
|
+
`timeout: ${[globalName, ...paths].join('.')}`
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
}, timeoutMs)
|
|
45
|
+
adaptor.emit({
|
|
46
|
+
name,
|
|
47
|
+
callbackName: responseName,
|
|
48
|
+
...restProps,
|
|
49
|
+
data: {
|
|
50
|
+
paths,
|
|
51
|
+
args: argArray,
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
},
|
|
56
|
+
get(target, prop) {
|
|
57
|
+
return geneProxy([...paths, prop as string], props)
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @example
|
|
64
|
+
* ```
|
|
65
|
+
* const obj = remoteValue<{
|
|
66
|
+
* a: number;
|
|
67
|
+
* b: {
|
|
68
|
+
* c: string;
|
|
69
|
+
* };
|
|
70
|
+
* funcD: () => number
|
|
71
|
+
* }>()
|
|
72
|
+
*
|
|
73
|
+
* const val_1 = await obj.a() // number
|
|
74
|
+
* const val_2 = await obj.b() // { c: string }
|
|
75
|
+
* const val_3 = await obj.b.c() // string
|
|
76
|
+
* const val_4 = await obj.funcD() // number
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export function remoteValue<T extends object>(props: RemoteValueProps) {
|
|
80
|
+
return geneProxy<T>([], props)
|
|
81
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
type HasFunc<T> = T extends (...args: unknown[]) => unknown
|
|
2
|
+
? true
|
|
3
|
+
: T extends unknown[]
|
|
4
|
+
? { [K in keyof T]: HasFunc<T[K]> }[number] extends false
|
|
5
|
+
? false
|
|
6
|
+
: true
|
|
7
|
+
: T extends object
|
|
8
|
+
? { [K in keyof T]: HasFunc<T[K]> }[keyof T] extends false
|
|
9
|
+
? false
|
|
10
|
+
: true
|
|
11
|
+
: false
|
|
12
|
+
|
|
13
|
+
export type ToFunc<T extends object> = {
|
|
14
|
+
[K in keyof T]: T[K] extends (...args: infer Args) => infer Ret
|
|
15
|
+
? (...args: Args) => Promise<Awaited<Ret>>
|
|
16
|
+
: HasFunc<T[K]> extends false
|
|
17
|
+
? () => Promise<T[K]>
|
|
18
|
+
: T[K] extends object
|
|
19
|
+
? ToFunc<T[K]>
|
|
20
|
+
: never
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 下面的都是测试代码,用于测试 ToFunc
|
|
24
|
+
|
|
25
|
+
type Assert<T extends true> = T
|
|
26
|
+
|
|
27
|
+
interface TestObj {
|
|
28
|
+
a1: number
|
|
29
|
+
a2: number[]
|
|
30
|
+
a3: [number, string]
|
|
31
|
+
a4: {
|
|
32
|
+
b: number
|
|
33
|
+
c: [string]
|
|
34
|
+
}
|
|
35
|
+
a5: () => Promise<number>
|
|
36
|
+
a6: () => Promise<number[]>
|
|
37
|
+
a7: () => Promise<[number, string]>
|
|
38
|
+
b: {
|
|
39
|
+
b1: number
|
|
40
|
+
b2: number[]
|
|
41
|
+
b3: [number, string]
|
|
42
|
+
b4: () => {
|
|
43
|
+
b: number
|
|
44
|
+
c: [string]
|
|
45
|
+
}
|
|
46
|
+
b5: () => Promise<number>
|
|
47
|
+
b6: () => Promise<number[]>
|
|
48
|
+
b7: () => Promise<[number, string]>
|
|
49
|
+
}
|
|
50
|
+
f: {
|
|
51
|
+
b: number
|
|
52
|
+
c: {
|
|
53
|
+
d: () => number
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type TestA1 = Assert<
|
|
59
|
+
ToFunc<TestObj>['a1'] extends () => Promise<number> ? true : false
|
|
60
|
+
>
|
|
61
|
+
export type TestA2 = Assert<
|
|
62
|
+
ToFunc<TestObj>['a2'] extends () => Promise<number[]> ? true : false
|
|
63
|
+
>
|
|
64
|
+
export type TestA3 = Assert<
|
|
65
|
+
ToFunc<TestObj>['a3'] extends () => Promise<[number, string]> ? true : false
|
|
66
|
+
>
|
|
67
|
+
export type TestA4 = Assert<
|
|
68
|
+
ToFunc<TestObj>['a4'] extends () => Promise<{
|
|
69
|
+
b: number
|
|
70
|
+
c: [string]
|
|
71
|
+
}>
|
|
72
|
+
? true
|
|
73
|
+
: false
|
|
74
|
+
>
|
|
75
|
+
export type TestA5 = Assert<
|
|
76
|
+
ToFunc<TestObj>['a5'] extends () => Promise<number> ? true : false
|
|
77
|
+
>
|
|
78
|
+
export type TestA6 = Assert<
|
|
79
|
+
ToFunc<TestObj>['a6'] extends () => Promise<number[]> ? true : false
|
|
80
|
+
>
|
|
81
|
+
export type TestA7 = Assert<
|
|
82
|
+
ToFunc<TestObj>['a7'] extends () => Promise<[number, string]> ? true : false
|
|
83
|
+
>
|
|
84
|
+
export type TestB1 = Assert<
|
|
85
|
+
ToFunc<TestObj>['b']['b1'] extends () => Promise<number> ? true : false
|
|
86
|
+
>
|
|
87
|
+
export type TestB2 = Assert<
|
|
88
|
+
ToFunc<TestObj>['b']['b2'] extends () => Promise<number[]> ? true : false
|
|
89
|
+
>
|
|
90
|
+
export type TestB3 = Assert<
|
|
91
|
+
ToFunc<TestObj>['b']['b3'] extends () => Promise<[number, string]> ? true : false
|
|
92
|
+
>
|
|
93
|
+
export type TestB4 = Assert<
|
|
94
|
+
ToFunc<TestObj>['b']['b4'] extends () => Promise<{
|
|
95
|
+
b: number
|
|
96
|
+
c: [string]
|
|
97
|
+
}>
|
|
98
|
+
? true
|
|
99
|
+
: false
|
|
100
|
+
>
|
|
101
|
+
export type TestB5 = Assert<
|
|
102
|
+
ToFunc<TestObj>['b']['b5'] extends () => Promise<number> ? true : false
|
|
103
|
+
>
|
|
104
|
+
export type TestB6 = Assert<
|
|
105
|
+
ToFunc<TestObj>['b']['b6'] extends () => Promise<number[]> ? true : false
|
|
106
|
+
>
|
|
107
|
+
export type TestB7 = Assert<
|
|
108
|
+
ToFunc<TestObj>['b']['b7'] extends () => Promise<[number, string]> ? true : false
|
|
109
|
+
>
|
|
110
|
+
export type TestF = Assert<
|
|
111
|
+
ToFunc<TestObj>['f']['b'] extends () => Promise<number> ? true : false
|
|
112
|
+
>
|
|
113
|
+
export type TestF2 = Assert<
|
|
114
|
+
ToFunc<TestObj>['f']['c']['d'] extends () => Promise<number> ? true : false
|
|
115
|
+
>
|