@zimi/remote 0.2.1 → 0.2.4

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.
Files changed (115) hide show
  1. package/LICENSE.md +21 -21
  2. package/README.md +289 -285
  3. package/dist/adaptor.d.mts +33 -0
  4. package/dist/adaptor.d.ts +5 -4
  5. package/dist/adaptor.js +1 -1
  6. package/dist/adaptor.js.map +1 -1
  7. package/dist/adaptor.mjs +1 -0
  8. package/dist/adaptor.mjs.map +1 -0
  9. package/dist/adaptors/dao3/client.d.mts +39 -0
  10. package/dist/adaptors/dao3/client.d.ts +5 -3
  11. package/dist/adaptors/dao3/client.js +1 -44
  12. package/dist/adaptors/dao3/client.js.map +1 -1
  13. package/dist/adaptors/dao3/client.mjs +2 -0
  14. package/dist/adaptors/dao3/client.mjs.map +1 -0
  15. package/dist/adaptors/dao3/server.d.mts +82 -0
  16. package/dist/adaptors/dao3/server.d.ts +5 -3
  17. package/dist/adaptors/dao3/server.js +1 -104
  18. package/dist/adaptors/dao3/server.js.map +1 -1
  19. package/dist/adaptors/dao3/server.mjs +2 -0
  20. package/dist/adaptors/dao3/server.mjs.map +1 -0
  21. package/dist/adaptors/electron/constants.d.mts +5 -0
  22. package/dist/adaptors/electron/constants.d.ts +5 -0
  23. package/dist/adaptors/electron/constants.js +2 -0
  24. package/dist/adaptors/electron/constants.js.map +1 -0
  25. package/dist/adaptors/electron/constants.mjs +2 -0
  26. package/dist/adaptors/electron/constants.mjs.map +1 -0
  27. package/dist/adaptors/electron/main.d.mts +10 -0
  28. package/dist/adaptors/electron/main.d.ts +10 -0
  29. package/dist/adaptors/electron/main.js +2 -0
  30. package/dist/adaptors/electron/main.js.map +1 -0
  31. package/dist/adaptors/electron/main.mjs +2 -0
  32. package/dist/adaptors/electron/main.mjs.map +1 -0
  33. package/dist/adaptors/electron/messenger.d.mts +8 -0
  34. package/dist/adaptors/electron/messenger.d.ts +8 -0
  35. package/dist/adaptors/electron/messenger.js +2 -0
  36. package/dist/adaptors/electron/messenger.js.map +1 -0
  37. package/dist/adaptors/electron/messenger.mjs +2 -0
  38. package/dist/adaptors/electron/messenger.mjs.map +1 -0
  39. package/dist/adaptors/electron/preload.d.mts +6 -0
  40. package/dist/adaptors/electron/preload.d.ts +6 -0
  41. package/dist/adaptors/electron/preload.js +2 -0
  42. package/dist/adaptors/electron/preload.js.map +1 -0
  43. package/dist/adaptors/electron/preload.mjs +2 -0
  44. package/dist/adaptors/electron/preload.mjs.map +1 -0
  45. package/dist/adaptors/electron/renderer.d.mts +9 -0
  46. package/dist/adaptors/electron/renderer.d.ts +9 -0
  47. package/dist/adaptors/electron/renderer.js +2 -0
  48. package/dist/adaptors/electron/renderer.js.map +1 -0
  49. package/dist/adaptors/electron/renderer.mjs +2 -0
  50. package/dist/adaptors/electron/renderer.mjs.map +1 -0
  51. package/dist/adaptors/http.d.mts +15 -0
  52. package/dist/adaptors/http.d.ts +6 -4
  53. package/dist/adaptors/http.js +1 -26
  54. package/dist/adaptors/http.js.map +1 -1
  55. package/dist/adaptors/http.mjs +2 -0
  56. package/dist/adaptors/http.mjs.map +1 -0
  57. package/dist/adaptors/iframe.d.mts +7 -0
  58. package/dist/adaptors/iframe.d.ts +5 -2
  59. package/dist/adaptors/iframe.js +1 -38
  60. package/dist/adaptors/iframe.js.map +1 -1
  61. package/dist/adaptors/iframe.mjs +2 -0
  62. package/dist/adaptors/iframe.mjs.map +1 -0
  63. package/dist/index.d.mts +16 -0
  64. package/dist/index.d.ts +16 -10
  65. package/dist/index.js +1 -9
  66. package/dist/index.js.map +1 -1
  67. package/dist/index.mjs +2 -0
  68. package/dist/index.mjs.map +1 -0
  69. package/dist/remote.d.mts +81 -0
  70. package/dist/remote.d.ts +6 -4
  71. package/dist/remote.js +1 -196
  72. package/dist/remote.js.map +1 -1
  73. package/dist/remote.mjs +2 -0
  74. package/dist/remote.mjs.map +1 -0
  75. package/dist/remoteValue/exposeToRemote.d.mts +43 -0
  76. package/dist/remoteValue/exposeToRemote.d.ts +7 -5
  77. package/dist/remoteValue/exposeToRemote.js +1 -52
  78. package/dist/remoteValue/exposeToRemote.js.map +1 -1
  79. package/dist/remoteValue/exposeToRemote.mjs +2 -0
  80. package/dist/remoteValue/exposeToRemote.mjs.map +1 -0
  81. package/dist/remoteValue/remoteValue.d.mts +29 -0
  82. package/dist/remoteValue/remoteValue.d.ts +6 -4
  83. package/dist/remoteValue/remoteValue.js +1 -67
  84. package/dist/remoteValue/remoteValue.js.map +1 -1
  85. package/dist/remoteValue/remoteValue.mjs +2 -0
  86. package/dist/remoteValue/remoteValue.mjs.map +1 -0
  87. package/dist/remoteValue/type.d.mts +67 -0
  88. package/dist/remoteValue/type.d.ts +20 -19
  89. package/dist/remoteValue/type.js +1 -1
  90. package/dist/remoteValue/type.js.map +1 -1
  91. package/dist/remoteValue/type.mjs +1 -0
  92. package/dist/remoteValue/type.mjs.map +1 -0
  93. package/dist/response.d.mts +105 -0
  94. package/dist/response.d.ts +6 -5
  95. package/dist/response.js +1 -154
  96. package/dist/response.js.map +1 -1
  97. package/dist/response.mjs +2 -0
  98. package/dist/response.mjs.map +1 -0
  99. package/package.json +31 -24
  100. package/src/adaptor.ts +34 -34
  101. package/src/adaptors/dao3/client.ts +53 -53
  102. package/src/adaptors/dao3/server.ts +136 -136
  103. package/src/adaptors/electron/constants.ts +3 -0
  104. package/src/adaptors/electron/main.ts +59 -0
  105. package/src/adaptors/electron/messenger.ts +13 -0
  106. package/src/adaptors/electron/preload.ts +21 -0
  107. package/src/adaptors/electron/renderer.ts +52 -0
  108. package/src/adaptors/http.ts +31 -31
  109. package/src/adaptors/iframe.ts +47 -47
  110. package/src/index.ts +17 -12
  111. package/src/remote.ts +263 -260
  112. package/src/remoteValue/exposeToRemote.ts +102 -102
  113. package/src/remoteValue/remoteValue.ts +94 -94
  114. package/src/remoteValue/type.ts +124 -124
  115. package/src/response.ts +170 -170
package/src/remote.ts CHANGED
@@ -1,260 +1,263 @@
1
- import {
2
- RemoteError,
3
- RemoteNotFoundError,
4
- RemoteTimeoutError,
5
- response,
6
- } from './response'
7
-
8
- import type { Adaptor, AdaptorCallback, AdaptorPackageData } from './adaptor'
9
-
10
- const RESPONSE_PREFIX = '_response_'
11
-
12
- type LogFunc = (...data: unknown[]) => void
13
-
14
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
- type RemoteCallableFunc = (data: any) => Promise<any>
16
-
17
- interface RemoteFuncRecords {
18
- [key: string]: RemoteCallableFunc
19
- }
20
-
21
- type FuncMapWithConfig<T extends RemoteFuncRecords> = {
22
- [K in keyof T]: T[K] extends (data: infer Arg) => Promise<infer Ret>
23
- ? (
24
- data: Arg,
25
- config?: {
26
- timeoutMs?: number
27
- targetDeviceId?: string
28
- }
29
- ) => Promise<Ret>
30
- : never
31
- }
32
-
33
- type RegisteredFunc<T extends RemoteCallableFunc> = T extends (
34
- data: infer Arg
35
- ) => infer Ret
36
- ? (
37
- data: Arg,
38
- ctx: {
39
- /**
40
- * 对方的设备 id
41
- */
42
- deviceId: string
43
- }
44
- ) => Ret
45
- : never
46
-
47
- function defaultLog(
48
- this: Remote<
49
- {
50
- [key: string]: RemoteCallableFunc
51
- },
52
- {
53
- [key: string]: RemoteCallableFunc
54
- }
55
- >,
56
- ...data: unknown[]
57
- ) {
58
- if (!this.debug) {
59
- return
60
- }
61
- console.log(`[remote of ${this.deviceId}]`, ...data)
62
- }
63
-
64
- export class Remote<
65
- /**
66
- * MF means my functions
67
- */
68
- MF extends RemoteFuncRecords,
69
- /**
70
- * OF means others functions
71
- */
72
- OF extends RemoteFuncRecords,
73
- > {
74
- debug = false
75
-
76
- private log: LogFunc
77
-
78
- /**
79
- * (调用对方函数时的)默认超时时间,单位 ms
80
- * @default 30000
81
- */
82
- private defaultTimeoutMs = 30000
83
-
84
- private map: {
85
- [key: string]: {
86
- callback: RegisteredFunc<RemoteCallableFunc>
87
- }
88
- } = {}
89
-
90
- private deviceIdValue = ''
91
-
92
- /**
93
- * 设备 id 应该唯一,用于区分不同设备。
94
- * 你可以在任何时候修改(更新)它。
95
- * @default ''
96
- */
97
- get deviceId() {
98
- return this.deviceIdValue
99
- }
100
-
101
- set deviceId(deviceId: string) {
102
- this.log(`deviceId set: from "${this.deviceIdValue}" to "${deviceId}"`)
103
- this.deviceIdValue = deviceId
104
- }
105
-
106
- constructor(
107
- private adaptor: Adaptor,
108
- config?: {
109
- /**
110
- * 设备 id 应该唯一,用于区分不同设备。
111
- * 你可以在任何时候修改(更新)它。
112
- * @default ''
113
- */
114
- deviceId?: string
115
- /**
116
- * (调用对方函数时的)默认超时时间,单位 ms
117
- * @default 30000
118
- */
119
- defaultTimeoutMs?: number
120
- debug?: boolean
121
- /**
122
- * 格式化 AdaptorPackageData 的函数,
123
- * 用于调试时输出日志。
124
- * @default JSON.stringify
125
- */
126
- log?: LogFunc
127
- }
128
- ) {
129
- this.debug = config?.debug ?? this.debug
130
- this.defaultTimeoutMs = config?.defaultTimeoutMs ?? this.defaultTimeoutMs
131
- this.log = config?.log ?? defaultLog.bind(this)
132
- this.deviceId = config?.deviceId ?? this.deviceId
133
-
134
- adaptor.every(async (e) => {
135
- const { deviceId: selfDeviceId } = this
136
- const { name, data, deviceId: targetDeviceId, callbackName } = e
137
- const callback = this.map[name]?.callback
138
- if (!callback) {
139
- if (name.startsWith(RESPONSE_PREFIX)) {
140
- // 这是响应,会在 callAsync once 中处理,这儿不用处理
141
- this.log('[every] response received: ', e)
142
- return
143
- }
144
- this.log('callback not found: ', name)
145
- if (callbackName) {
146
- adaptor.emit({
147
- deviceId: selfDeviceId,
148
- targetDeviceId,
149
- name: callbackName,
150
- data: response.error(
151
- new RemoteNotFoundError(`callback not found: ${name}`)
152
- ),
153
- })
154
- }
155
- return
156
- }
157
- if (!callbackName) {
158
- this.log('should not respond: ', e)
159
- void callback(data, { deviceId: targetDeviceId })
160
- return
161
- }
162
- this.log(`callback: ${name}; respondName: ${callbackName}; data: `, data)
163
- try {
164
- const ret = await callback(data, { deviceId: targetDeviceId })
165
- this.log('callback return: ', ret)
166
- adaptor.emit({
167
- deviceId: selfDeviceId,
168
- targetDeviceId,
169
- name: callbackName,
170
- data: response.success(ret),
171
- })
172
- } catch (error) {
173
- this.log('callback error: ', error)
174
- adaptor.emit({
175
- deviceId: selfDeviceId,
176
- targetDeviceId,
177
- name: callbackName,
178
- data: response.error(RemoteError.fromError(error)),
179
- })
180
- }
181
- })
182
- }
183
-
184
- /**
185
- * 调用其他端的方法;会等待对方响应。
186
- * 不能直接使用该方法,应该使用 proxy。
187
- * @WARNING 不能用于响应其他端。
188
- */
189
- private callAsync(
190
- name: string,
191
- data: unknown,
192
- config?: {
193
- timeoutMs?: number
194
- targetDeviceId?: string
195
- }
196
- ) {
197
- const timeoutMs = config?.timeoutMs ?? this.defaultTimeoutMs
198
- const { deviceId } = this
199
- const randomStr = Math.random().toString(36).slice(2)
200
- // 本条消息的响应名
201
- const responseName = `${RESPONSE_PREFIX}-${name}-${deviceId}-${randomStr}`
202
- return new Promise((resolve, reject) => {
203
- let timer: NodeJS.Timeout | undefined
204
- this.log(`callAsync ${name}: waiting for response: ${responseName}`)
205
- const callback: AdaptorCallback = (e) => {
206
- clearTimeout(timer)
207
- this.log(`response received: ${responseName}`, e)
208
- if (RemoteError.isRemoteError(e.data)) {
209
- reject(RemoteError.fromError(e.data))
210
- } else {
211
- resolve((e.data as ReturnType<typeof response.success>)?.data)
212
- }
213
- }
214
- this.adaptor.once(responseName, callback)
215
- timer = setTimeout(() => {
216
- this.log(`timeout: ${responseName}`)
217
- this.adaptor.off(responseName, callback)
218
- reject(new RemoteTimeoutError(`timeout: ${name}`))
219
- }, timeoutMs)
220
- this.adaptor.emit({
221
- deviceId,
222
- targetDeviceId: config?.targetDeviceId ?? '',
223
- name,
224
- data,
225
- callbackName: responseName,
226
- })
227
- })
228
- }
229
-
230
- /**
231
- * 注册方法,供对方调用;
232
- */
233
- register<K extends keyof MF>(name: K, callback: RegisteredFunc<MF[K]>): void {
234
- this.map[name as string] = { callback }
235
- }
236
-
237
- _ = new Proxy<FuncMapWithConfig<OF>>({} as FuncMapWithConfig<OF>, {
238
- get: (_, k) => this.callAsync.bind(this, k as string),
239
- })
240
-
241
- self = new Proxy<MF>({} as MF, {
242
- get: (_, k) => (data: unknown) =>
243
- this.map[k as string]?.callback(data, {
244
- deviceId: this.deviceId,
245
- }),
246
- })
247
- }
248
-
249
- export function isRemoteAdaptorData(data: unknown): data is AdaptorPackageData {
250
- return (
251
- !!data &&
252
- typeof data === 'object' &&
253
- 'deviceId' in data &&
254
- 'name' in data &&
255
- typeof data.deviceId === 'string' &&
256
- typeof data.name === 'string' &&
257
- !!data.deviceId &&
258
- !!data.name
259
- )
260
- }
1
+ import {
2
+ RemoteError,
3
+ RemoteNotFoundError,
4
+ RemoteTimeoutError,
5
+ response,
6
+ } from './response'
7
+
8
+ import type { Adaptor, AdaptorCallback, AdaptorPackageData } from './adaptor'
9
+
10
+ const RESPONSE_PREFIX = '_response_'
11
+
12
+ type LogFunc = (...data: unknown[]) => void
13
+
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ type RemoteCallableFunc = (data: any) => Promise<any>
16
+
17
+ interface RemoteFuncRecords {
18
+ [key: string]: RemoteCallableFunc
19
+ }
20
+
21
+ type FuncMapWithConfig<T extends RemoteFuncRecords> = {
22
+ [K in keyof T]: T[K] extends (data: infer Arg) => Promise<infer Ret>
23
+ ? (
24
+ data: Arg,
25
+ config?: {
26
+ timeoutMs?: number
27
+ targetDeviceId?: string
28
+ }
29
+ ) => Promise<Ret>
30
+ : never
31
+ }
32
+
33
+ type RegisteredFunc<T extends RemoteCallableFunc> = T extends (
34
+ data: infer Arg
35
+ ) => infer Ret
36
+ ? (
37
+ data: Arg,
38
+ ctx: {
39
+ /**
40
+ * 对方的设备 id
41
+ */
42
+ deviceId: string
43
+ }
44
+ ) => Ret
45
+ : never
46
+
47
+ function defaultLog(
48
+ this: Remote<
49
+ {
50
+ [key: string]: RemoteCallableFunc
51
+ },
52
+ {
53
+ [key: string]: RemoteCallableFunc
54
+ }
55
+ >,
56
+ ...data: unknown[]
57
+ ) {
58
+ if (!this.debug) {
59
+ return
60
+ }
61
+ console.log(`[remote of ${this.deviceId}]`, ...data)
62
+ }
63
+
64
+ export class Remote<
65
+ /**
66
+ * MF means my functions
67
+ */
68
+ MF extends RemoteFuncRecords,
69
+ /**
70
+ * OF means others functions
71
+ */
72
+ OF extends RemoteFuncRecords,
73
+ > {
74
+ debug = false
75
+
76
+ private log: LogFunc
77
+
78
+ /**
79
+ * (调用对方函数时的)默认超时时间,单位 ms
80
+ * @default 30000
81
+ */
82
+ private defaultTimeoutMs = 30000
83
+
84
+ private map: {
85
+ [key: string]: {
86
+ callback: RegisteredFunc<RemoteCallableFunc>
87
+ }
88
+ } = {}
89
+
90
+ private deviceIdValue = ''
91
+
92
+ /**
93
+ * 设备 id 应该唯一,用于区分不同设备。
94
+ * 你可以在任何时候修改(更新)它。
95
+ * @default ''
96
+ */
97
+ get deviceId() {
98
+ return this.deviceIdValue
99
+ }
100
+
101
+ set deviceId(deviceId: string) {
102
+ this.log(`deviceId set: from "${this.deviceIdValue}" to "${deviceId}"`)
103
+ this.deviceIdValue = deviceId
104
+ }
105
+
106
+ constructor(
107
+ private adaptor: Adaptor,
108
+ config?: {
109
+ /**
110
+ * 设备 id 应该唯一,用于区分不同设备。
111
+ * 你可以在任何时候修改(更新)它。
112
+ * @default ''
113
+ */
114
+ deviceId?: string
115
+ /**
116
+ * (调用对方函数时的)默认超时时间,单位 ms
117
+ * @default 30000
118
+ */
119
+ defaultTimeoutMs?: number
120
+ debug?: boolean
121
+ /**
122
+ * 格式化 AdaptorPackageData 的函数,
123
+ * 用于调试时输出日志。
124
+ * @default JSON.stringify
125
+ */
126
+ log?: LogFunc
127
+ }
128
+ ) {
129
+ this.debug = config?.debug ?? this.debug
130
+ this.defaultTimeoutMs = config?.defaultTimeoutMs ?? this.defaultTimeoutMs
131
+ this.log = config?.log ?? defaultLog.bind(this)
132
+ this.deviceId = config?.deviceId ?? this.deviceId
133
+
134
+ adaptor.every(async (e) => {
135
+ const { deviceId: selfDeviceId } = this
136
+ const { name, data, deviceId: targetDeviceId, callbackName } = e
137
+ const callback = this.map[name]?.callback
138
+ if (!callback) {
139
+ if (name.startsWith(RESPONSE_PREFIX)) {
140
+ // 这是响应,会在 callAsync once 中处理,这儿不用处理
141
+ this.log('[every] response received: ', e)
142
+ return
143
+ }
144
+ this.log('callback not found: ', name)
145
+ if (callbackName) {
146
+ adaptor.emit({
147
+ deviceId: selfDeviceId,
148
+ targetDeviceId,
149
+ name: callbackName,
150
+ data: response.error(
151
+ new RemoteNotFoundError(`callback not found: ${name}`)
152
+ ),
153
+ })
154
+ }
155
+ return
156
+ }
157
+ if (!callbackName) {
158
+ this.log('should not respond: ', e)
159
+ void callback(data, { deviceId: targetDeviceId })
160
+ return
161
+ }
162
+ this.log(`callback: ${name}; respondName: ${callbackName}; data: `, data)
163
+ try {
164
+ const ret = await callback(data, { deviceId: targetDeviceId })
165
+ this.log('callback return: ', ret)
166
+ adaptor.emit({
167
+ deviceId: selfDeviceId,
168
+ targetDeviceId,
169
+ name: callbackName,
170
+ data: response.success(ret),
171
+ })
172
+ } catch (error) {
173
+ this.log('callback error: ', error)
174
+ adaptor.emit({
175
+ deviceId: selfDeviceId,
176
+ targetDeviceId,
177
+ name: callbackName,
178
+ data: response.error(RemoteError.fromError(error)),
179
+ })
180
+ }
181
+ })
182
+ }
183
+
184
+ /**
185
+ * 调用其他端的方法;会等待对方响应。
186
+ * 不能直接使用该方法,应该使用 proxy。
187
+ * @WARNING 不能用于响应其他端。
188
+ */
189
+ private callAsync(
190
+ name: string,
191
+ data: unknown,
192
+ config?: {
193
+ timeoutMs?: number
194
+ targetDeviceId?: string
195
+ }
196
+ ) {
197
+ const timeoutMs = config?.timeoutMs ?? this.defaultTimeoutMs
198
+ const { deviceId } = this
199
+ const randomStr = Math.random().toString(36).slice(2)
200
+ // 本条消息的响应名
201
+ const responseName = `${RESPONSE_PREFIX}-${name}-${deviceId}-${randomStr}`
202
+ return new Promise((resolve, reject) => {
203
+ let timer: NodeJS.Timeout | undefined
204
+ this.log(`callAsync ${name}: waiting for response: ${responseName}`)
205
+ const callback: AdaptorCallback = (e) => {
206
+ clearTimeout(timer)
207
+ this.log(`response received: ${responseName}`, e)
208
+ if (RemoteError.isRemoteError(e.data)) {
209
+ reject(RemoteError.fromError(e.data))
210
+ } else {
211
+ resolve((e.data as ReturnType<typeof response.success>)?.data)
212
+ }
213
+ }
214
+ this.adaptor.once(responseName, callback)
215
+ timer = setTimeout(() => {
216
+ this.log(`timeout: ${responseName}`)
217
+ this.adaptor.off(responseName, callback)
218
+ reject(new RemoteTimeoutError(`timeout: ${name}`))
219
+ }, timeoutMs)
220
+ this.adaptor.emit({
221
+ deviceId,
222
+ targetDeviceId: config?.targetDeviceId ?? '',
223
+ name,
224
+ data,
225
+ callbackName: responseName,
226
+ })
227
+ })
228
+ }
229
+
230
+ /**
231
+ * 注册方法,供对方调用;
232
+ */
233
+ register<K extends keyof MF>(name: K, callback: RegisteredFunc<MF[K]>): void {
234
+ this.map[name as string] = { callback }
235
+ }
236
+
237
+ _ = new Proxy<FuncMapWithConfig<OF>>({} as FuncMapWithConfig<OF>, {
238
+ get: (_, k) => this.callAsync.bind(this, k as string),
239
+ })
240
+
241
+ self = new Proxy<MF>({} as MF, {
242
+ get: (_, k) => (data: unknown) =>
243
+ this.map[k as string]?.callback.apply(null, [
244
+ data,
245
+ {
246
+ deviceId: this.deviceId,
247
+ },
248
+ ]),
249
+ })
250
+ }
251
+
252
+ export function isRemoteAdaptorData(data: unknown): data is AdaptorPackageData {
253
+ return (
254
+ !!data &&
255
+ typeof data === 'object' &&
256
+ 'deviceId' in data &&
257
+ 'name' in data &&
258
+ typeof data.deviceId === 'string' &&
259
+ typeof data.name === 'string' &&
260
+ !!data.deviceId &&
261
+ !!data.name
262
+ )
263
+ }