@zimi/remote 0.1.0 → 0.1.1-alpha.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/README.md +35 -7
- package/dist/adaptors/http.d.ts +13 -13
- package/dist/adaptors/http.js +26 -25
- package/dist/adaptors/http.js.map +1 -1
- package/dist/adaptors/iframe.d.ts +4 -4
- package/dist/adaptors/iframe.js +38 -37
- package/dist/adaptors/iframe.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/remote.d.ts +79 -79
- package/dist/remote.js +191 -191
- package/dist/remote.js.map +1 -1
- package/dist/remoteValue/index.d.ts +35 -0
- package/dist/remoteValue/index.js +106 -0
- package/dist/remoteValue/index.js.map +1 -0
- package/dist/response.d.ts +104 -104
- package/dist/response.js +154 -154
- package/dist/response.js.map +1 -1
- package/package.json +5 -5
- 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 +1 -0
- package/src/remoteValue/index.ts +129 -0
- package/src/remoteValue/type.d.ts +113 -0
|
@@ -0,0 +1,129 @@
|
|
|
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
|
+
}
|
|
82
|
+
|
|
83
|
+
interface ExposeProps {
|
|
84
|
+
globalName: string
|
|
85
|
+
adaptor: Adaptor
|
|
86
|
+
/**
|
|
87
|
+
* ['*'] or ['device_id_1', 'device_id_2']
|
|
88
|
+
*/
|
|
89
|
+
exposeTo: string[]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function exposeToRemote<T extends object>(obj: T, options: ExposeProps) {
|
|
93
|
+
const { globalName, adaptor, exposeTo } = options
|
|
94
|
+
const callback = async (e: AdaptorPackageData) => {
|
|
95
|
+
try {
|
|
96
|
+
if (!exposeTo.includes(e.deviceId) && !exposeTo.includes('*')) {
|
|
97
|
+
throw new RemoteError('permission denied')
|
|
98
|
+
}
|
|
99
|
+
const { paths, args } = e.data as { paths: string[]; args: unknown[] }
|
|
100
|
+
let target = obj
|
|
101
|
+
for (let i = 0; i < paths.length - 1; i += 1) {
|
|
102
|
+
target = target[paths[i] as keyof typeof target] as typeof target
|
|
103
|
+
}
|
|
104
|
+
let res: unknown
|
|
105
|
+
if (target instanceof Function) {
|
|
106
|
+
res = await target(...args)
|
|
107
|
+
} else {
|
|
108
|
+
res = target
|
|
109
|
+
}
|
|
110
|
+
adaptor.emit({
|
|
111
|
+
name: e.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME',
|
|
112
|
+
deviceId: e.targetDeviceId,
|
|
113
|
+
targetDeviceId: e.deviceId,
|
|
114
|
+
data: response.success(res),
|
|
115
|
+
})
|
|
116
|
+
} catch (error) {
|
|
117
|
+
adaptor.emit({
|
|
118
|
+
name: e.callbackName ?? 'IMPOSSIBLE_NO_CALLBACK_NAME',
|
|
119
|
+
deviceId: e.targetDeviceId,
|
|
120
|
+
targetDeviceId: e.deviceId,
|
|
121
|
+
data: response.error(RemoteError.fromError(error)),
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
adaptor.on(`__REMOTE_VALUE_REQ__${globalName}`, callback)
|
|
126
|
+
return () => {
|
|
127
|
+
adaptor.off(`__REMOTE_VALUE_REQ__${globalName}`, callback)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
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
|
+
type Assert<T extends true> = T
|
|
24
|
+
|
|
25
|
+
interface TestObj {
|
|
26
|
+
a1: number
|
|
27
|
+
a2: number[]
|
|
28
|
+
a3: [number, string]
|
|
29
|
+
a4: {
|
|
30
|
+
b: number
|
|
31
|
+
c: [string]
|
|
32
|
+
}
|
|
33
|
+
a5: () => Promise<number>
|
|
34
|
+
a6: () => Promise<number[]>
|
|
35
|
+
a7: () => Promise<[number, string]>
|
|
36
|
+
b: {
|
|
37
|
+
b1: number
|
|
38
|
+
b2: number[]
|
|
39
|
+
b3: [number, string]
|
|
40
|
+
b4: () => {
|
|
41
|
+
b: number
|
|
42
|
+
c: [string]
|
|
43
|
+
}
|
|
44
|
+
b5: () => Promise<number>
|
|
45
|
+
b6: () => Promise<number[]>
|
|
46
|
+
b7: () => Promise<[number, string]>
|
|
47
|
+
}
|
|
48
|
+
f: {
|
|
49
|
+
b: number
|
|
50
|
+
c: {
|
|
51
|
+
d: () => number
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type TestA1 = Assert<
|
|
57
|
+
ToFunc<TestObj>['a1'] extends () => Promise<number> ? true : false
|
|
58
|
+
>
|
|
59
|
+
export type TestA2 = Assert<
|
|
60
|
+
ToFunc<TestObj>['a2'] extends () => Promise<number[]> ? true : false
|
|
61
|
+
>
|
|
62
|
+
export type TestA3 = Assert<
|
|
63
|
+
ToFunc<TestObj>['a3'] extends () => Promise<[number, string]> ? true : false
|
|
64
|
+
>
|
|
65
|
+
export type TestA4 = Assert<
|
|
66
|
+
ToFunc<TestObj>['a4'] extends () => Promise<{
|
|
67
|
+
b: number
|
|
68
|
+
c: [string]
|
|
69
|
+
}>
|
|
70
|
+
? true
|
|
71
|
+
: false
|
|
72
|
+
>
|
|
73
|
+
export type TestA5 = Assert<
|
|
74
|
+
ToFunc<TestObj>['a5'] extends () => Promise<number> ? true : false
|
|
75
|
+
>
|
|
76
|
+
export type TestA6 = Assert<
|
|
77
|
+
ToFunc<TestObj>['a6'] extends () => Promise<number[]> ? true : false
|
|
78
|
+
>
|
|
79
|
+
export type TestA7 = Assert<
|
|
80
|
+
ToFunc<TestObj>['a7'] extends () => Promise<[number, string]> ? true : false
|
|
81
|
+
>
|
|
82
|
+
export type TestB1 = Assert<
|
|
83
|
+
ToFunc<TestObj>['b']['b1'] extends () => Promise<number> ? true : false
|
|
84
|
+
>
|
|
85
|
+
export type TestB2 = Assert<
|
|
86
|
+
ToFunc<TestObj>['b']['b2'] extends () => Promise<number[]> ? true : false
|
|
87
|
+
>
|
|
88
|
+
export type TestB3 = Assert<
|
|
89
|
+
ToFunc<TestObj>['b']['b3'] extends () => Promise<[number, string]> ? true : false
|
|
90
|
+
>
|
|
91
|
+
export type TestB4 = Assert<
|
|
92
|
+
ToFunc<TestObj>['b']['b4'] extends () => Promise<{
|
|
93
|
+
b: number
|
|
94
|
+
c: [string]
|
|
95
|
+
}>
|
|
96
|
+
? true
|
|
97
|
+
: false
|
|
98
|
+
>
|
|
99
|
+
export type TestB5 = Assert<
|
|
100
|
+
ToFunc<TestObj>['b']['b5'] extends () => Promise<number> ? true : false
|
|
101
|
+
>
|
|
102
|
+
export type TestB6 = Assert<
|
|
103
|
+
ToFunc<TestObj>['b']['b6'] extends () => Promise<number[]> ? true : false
|
|
104
|
+
>
|
|
105
|
+
export type TestB7 = Assert<
|
|
106
|
+
ToFunc<TestObj>['b']['b7'] extends () => Promise<[number, string]> ? true : false
|
|
107
|
+
>
|
|
108
|
+
export type TestF = Assert<
|
|
109
|
+
ToFunc<TestObj>['f']['b'] extends () => Promise<number> ? true : false
|
|
110
|
+
>
|
|
111
|
+
export type TestF2 = Assert<
|
|
112
|
+
ToFunc<TestObj>['f']['c']['d'] extends () => Promise<number> ? true : false
|
|
113
|
+
>
|