@nxtedition/deepstream.io-client-js 28.1.23 → 28.1.24
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/.claude/settings.local.json +9 -0
- package/package.json +4 -2
- package/src/client.d.ts +29 -25
- package/src/client.test-d.ts +105 -0
- package/src/record/record-handler.d.ts +48 -46
- package/src/record/record-handler.js +32 -11
- package/src/record/record.d.ts +20 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxtedition/deepstream.io-client-js",
|
|
3
|
-
"version": "28.1.
|
|
3
|
+
"version": "28.1.24",
|
|
4
4
|
"description": "the javascript client for deepstream.io",
|
|
5
5
|
"homepage": "http://deepstream.io",
|
|
6
6
|
"type": "module",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"prepublishOnly": "pinst --disable",
|
|
23
23
|
"postpublish": "pinst --enable",
|
|
24
|
-
"prepare": "husky"
|
|
24
|
+
"prepare": "husky",
|
|
25
|
+
"test:types": "tsd"
|
|
25
26
|
},
|
|
26
27
|
"lint-staged": {
|
|
27
28
|
"*.{js,jsx,md,ts}": [
|
|
@@ -60,6 +61,7 @@
|
|
|
60
61
|
"pinst": "^3.0.0",
|
|
61
62
|
"prettier": "^3.3.3",
|
|
62
63
|
"rxjs": "^7.8.1",
|
|
64
|
+
"tsd": "^0.33.0",
|
|
63
65
|
"type-fest": "^4.33.0",
|
|
64
66
|
"typescript": "^5.6.3",
|
|
65
67
|
"typescript-eslint": "^8.12.2"
|
package/src/client.d.ts
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
3
|
-
import type
|
|
4
|
-
import type
|
|
1
|
+
import type DsRecord from './record/record.js'
|
|
2
|
+
import type { Paths, Get } from './record/record.js'
|
|
3
|
+
import type RecordHandler from './record/record-handler.js'
|
|
4
|
+
import type { RecordStats, ProvideOptions, SyncOptions } from './record/record-handler.js'
|
|
5
|
+
import type EventHandler from './event/event-handler.js'
|
|
6
|
+
import type { EventStats } from './event/event-handler.js'
|
|
7
|
+
import type RpcHandler from './rpc/rpc-handler.js'
|
|
8
|
+
import type { RpcStats, RpcMethodDef } from './rpc/rpc-handler.js'
|
|
5
9
|
|
|
6
|
-
export default function <
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
): DeepstreamClient<Records, Methods>
|
|
10
|
+
export default function <
|
|
11
|
+
Records extends Record<string, unknown> = Record<string, unknown>,
|
|
12
|
+
Methods extends Record<string, RpcMethodDef> = Record<string, RpcMethodDef>,
|
|
13
|
+
>(url: string, options?: unknown): DeepstreamClient<Records, Methods>
|
|
10
14
|
|
|
11
|
-
export type {
|
|
15
|
+
export type {
|
|
16
|
+
DsRecord,
|
|
17
|
+
RecordHandler,
|
|
18
|
+
EventHandler,
|
|
19
|
+
RpcHandler,
|
|
20
|
+
RpcMethodDef,
|
|
21
|
+
ProvideOptions,
|
|
22
|
+
SyncOptions,
|
|
23
|
+
Paths,
|
|
24
|
+
Get,
|
|
25
|
+
}
|
|
12
26
|
|
|
13
27
|
type RecordStateConstants = Readonly<{
|
|
14
28
|
VOID: 0
|
|
@@ -28,8 +42,8 @@ type ConnectionStateConstants = Readonly<{
|
|
|
28
42
|
ERROR: 'ERROR'
|
|
29
43
|
RECONNECTING: 'RECONNECTING'
|
|
30
44
|
}>
|
|
31
|
-
type ConnectionStateKey = keyof
|
|
32
|
-
type ConnectionStateName =
|
|
45
|
+
type ConnectionStateKey = keyof ConnectionStateConstants
|
|
46
|
+
type ConnectionStateName = ConnectionStateConstants[ConnectionStateKey]
|
|
33
47
|
|
|
34
48
|
type EventConstants = Readonly<{
|
|
35
49
|
CONNECTION_ERROR: 'connectionError'
|
|
@@ -61,12 +75,12 @@ type EventConstants = Readonly<{
|
|
|
61
75
|
RECORD_NOT_FOUND: 'RECORD_NOT_FOUND'
|
|
62
76
|
NOT_SUBSCRIBED: 'NOT_SUBSCRIBED'
|
|
63
77
|
}>
|
|
64
|
-
type EventKey = keyof
|
|
65
|
-
type EventName =
|
|
78
|
+
type EventKey = keyof EventConstants
|
|
79
|
+
type EventName = EventConstants[EventKey]
|
|
66
80
|
|
|
67
81
|
export interface DeepstreamClient<
|
|
68
|
-
Records = Record<string, unknown>,
|
|
69
|
-
Methods = Record<string, RpcMethodDef>,
|
|
82
|
+
Records extends Record<string, unknown> = Record<string, unknown>,
|
|
83
|
+
Methods extends Record<string, RpcMethodDef> = Record<string, RpcMethodDef>,
|
|
70
84
|
> {
|
|
71
85
|
nuid: () => string
|
|
72
86
|
event: EventHandler
|
|
@@ -92,13 +106,3 @@ export interface DeepstreamClient<
|
|
|
92
106
|
EVENT: EventConstants
|
|
93
107
|
}
|
|
94
108
|
}
|
|
95
|
-
|
|
96
|
-
export interface ProvideOptions {
|
|
97
|
-
recursive?: boolean
|
|
98
|
-
stringify?: ((input: unknown) => string) | null
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export interface SyncOptions {
|
|
102
|
-
signal?: AbortSignal
|
|
103
|
-
timeout?: number
|
|
104
|
-
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import make from './client.js'
|
|
2
|
+
import { expectAssignable, expectError } from 'tsd'
|
|
3
|
+
|
|
4
|
+
interface Records extends Record<string, unknown> {
|
|
5
|
+
o: {
|
|
6
|
+
o0?: {
|
|
7
|
+
o1?: {
|
|
8
|
+
o2?: {
|
|
9
|
+
o3?: string
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
n: {
|
|
15
|
+
n0: {
|
|
16
|
+
n1: {
|
|
17
|
+
n2: {
|
|
18
|
+
n3: string
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
c: Circular
|
|
24
|
+
m: {
|
|
25
|
+
m1: string
|
|
26
|
+
m2: string
|
|
27
|
+
m3?: string
|
|
28
|
+
}
|
|
29
|
+
p: {
|
|
30
|
+
p1: string
|
|
31
|
+
p2?: string
|
|
32
|
+
p3: { p4: string }
|
|
33
|
+
}
|
|
34
|
+
[x: `${string}:domain`]: {
|
|
35
|
+
d1: string
|
|
36
|
+
d2: {
|
|
37
|
+
d3: string
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface Circular {
|
|
43
|
+
a: {
|
|
44
|
+
b0: Circular
|
|
45
|
+
b1: string
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const ds = make<Records>('')
|
|
50
|
+
|
|
51
|
+
expectAssignable<{ n0?: { n1: { n2: { n3: string } } } } | undefined>(await ds.record.get('n'))
|
|
52
|
+
expectAssignable<{ n1: { n2: { n3: string } } } | undefined>(await ds.record.get('n', 'n0'))
|
|
53
|
+
|
|
54
|
+
// set withouth path
|
|
55
|
+
ds.record.set('n', {}) // empty should always work
|
|
56
|
+
ds.record.set('n', { n0: { n1: { n2: { n3: 'test' } } } })
|
|
57
|
+
expectError(ds.record.set('n', { n0: {} })) // nested props are required
|
|
58
|
+
|
|
59
|
+
// set with path
|
|
60
|
+
ds.record.set('n', 'n0.n1', { n2: { n3: 'test' } })
|
|
61
|
+
ds.record.set('n', 'n0', { n1: { n2: { n3: 'test' } } })
|
|
62
|
+
ds.record.set('n', 'n0.n1', { n2: { n3: 'test' } })
|
|
63
|
+
ds.record.set('n', 'n0.n1.n2', { n3: 'test' })
|
|
64
|
+
ds.record.set('n', 'n0.n1.n2.n3', 'test')
|
|
65
|
+
ds.record.set('o', 'o0.o1.o2.o3', 'test')
|
|
66
|
+
ds.record.set('o', 'o0', {})
|
|
67
|
+
ds.record.set('o', 'o0.o1', {})
|
|
68
|
+
ds.record.set('o', 'o0.o1.o2', {})
|
|
69
|
+
ds.record.set('o', 'o0.o1', { o2: {} })
|
|
70
|
+
ds.record.set('o', 'o0.o1', { o2: { o3: 'test' } })
|
|
71
|
+
ds.record.set('c', 'a.b1', 'test')
|
|
72
|
+
ds.record.set('x:domain', 'd1', 'test')
|
|
73
|
+
const id = 'id'
|
|
74
|
+
ds.record.set(`${id}:domain`, 'd2.d3', 'test')
|
|
75
|
+
|
|
76
|
+
expectAssignable<string>(await ds.record.get(`${id}:domain`, 'd2.d3'))
|
|
77
|
+
|
|
78
|
+
// errors
|
|
79
|
+
expectError(ds.record.set('o', 'o0.o1', { o2: { o3: 0 } }))
|
|
80
|
+
expectError(ds.record.set('o', 'o0.o1', { o3: 0 }))
|
|
81
|
+
expectError(ds.record.set('n', 'x1', {}))
|
|
82
|
+
expectError(ds.record.set('n', 'n0.x2', 22))
|
|
83
|
+
expectError(ds.record.set('n', 'n1.x2', {}))
|
|
84
|
+
expectError(ds.record.set('n', 'n1.n2.n3', { n4: 22 }))
|
|
85
|
+
|
|
86
|
+
expectAssignable<string>(await ds.record.get('p', 'p1'))
|
|
87
|
+
expectAssignable<string | undefined>(await ds.record.get('p', 'p2'))
|
|
88
|
+
expectAssignable<unknown>(await ds.record.get('p', 'x1'))
|
|
89
|
+
|
|
90
|
+
// Circular
|
|
91
|
+
expectAssignable<string | undefined>(await ds.record.get('c', 'a.b1'))
|
|
92
|
+
|
|
93
|
+
// ============
|
|
94
|
+
//
|
|
95
|
+
|
|
96
|
+
// getRecord
|
|
97
|
+
const daRec = ds.record.getRecord('o')
|
|
98
|
+
daRec.set({ o0: {} })
|
|
99
|
+
|
|
100
|
+
daRec.update('o0', (x) => ({ ...x, o1: {} }))
|
|
101
|
+
expectError(daRec.update((x) => 'x'))
|
|
102
|
+
expectError(daRec.update('o0', (x) => ({ ...x, o1: '22' })))
|
|
103
|
+
|
|
104
|
+
ds.record.set('foo', { num: [22, true] })
|
|
105
|
+
ds.record.set('foo', { num: ['22'] })
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Observable } from 'rxjs'
|
|
2
|
-
import type
|
|
2
|
+
import type DsRecord from './record.js'
|
|
3
|
+
import type { EmptyObject, Get, Paths } from './record.js'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export default class RecordHandler<Records> {
|
|
5
|
+
export default class RecordHandler<
|
|
6
|
+
Lookup extends Record<string, unknown> = Record<string, unknown>,
|
|
7
|
+
> {
|
|
8
8
|
VOID: 0
|
|
9
9
|
CLIENT: 1
|
|
10
10
|
SERVER: 2
|
|
@@ -20,13 +20,13 @@ export default class RecordHandler<Records> {
|
|
|
20
20
|
connected: boolean
|
|
21
21
|
stats: RecordStats
|
|
22
22
|
|
|
23
|
-
getRecord
|
|
23
|
+
getRecord<Name extends string, Data = Name extends keyof Lookup ? Lookup[Name] : unknown>(
|
|
24
24
|
name: Name,
|
|
25
|
-
)
|
|
25
|
+
): DsRecord<Data>
|
|
26
26
|
|
|
27
|
-
provide:
|
|
27
|
+
provide: (
|
|
28
28
|
pattern: string,
|
|
29
|
-
callback: (key: string) =>
|
|
29
|
+
callback: (key: string) => unknown,
|
|
30
30
|
optionsOrRecursive?: ProvideOptions | boolean,
|
|
31
31
|
) => void | (() => void)
|
|
32
32
|
|
|
@@ -34,115 +34,107 @@ export default class RecordHandler<Records> {
|
|
|
34
34
|
|
|
35
35
|
set: {
|
|
36
36
|
// without path:
|
|
37
|
-
<Name extends
|
|
37
|
+
<Name extends string>(name: Name, data: Lookup[Name] | EmptyObject): void
|
|
38
38
|
|
|
39
39
|
// with path:
|
|
40
|
-
<Name extends
|
|
40
|
+
<Name extends string, Path extends string | string[]>(
|
|
41
41
|
name: Name,
|
|
42
42
|
path: Path,
|
|
43
|
-
data: Get<
|
|
43
|
+
data: Path extends Paths<Lookup[Name]> ? Get<Lookup[Name], Path> : never,
|
|
44
44
|
): void
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
update: {
|
|
48
48
|
// without path:
|
|
49
|
-
<Name extends
|
|
49
|
+
<Name extends string>(
|
|
50
50
|
name: Name,
|
|
51
|
-
updater: (data:
|
|
51
|
+
updater: (data: Lookup[Name]) => Lookup[Name] | EmptyObject,
|
|
52
52
|
): Promise<void>
|
|
53
53
|
|
|
54
54
|
// with path:
|
|
55
|
-
<Name extends
|
|
55
|
+
<Name extends string, Path extends string | string[]>(
|
|
56
56
|
name: Name,
|
|
57
57
|
path: Path,
|
|
58
|
-
updater: (data:
|
|
58
|
+
updater: (data: Get<Lookup[Name], Path>) => Get<Lookup[Name], Path>,
|
|
59
59
|
): Promise<void>
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
observe: {
|
|
63
63
|
// without path:
|
|
64
|
-
<Name extends
|
|
65
|
-
name: Name,
|
|
66
|
-
): Observable<GettablePossibleEmpty<Data>>
|
|
64
|
+
<Name extends string>(name: Name): Observable<Lookup[Name]>
|
|
67
65
|
|
|
68
66
|
// with path:
|
|
69
|
-
<Name extends
|
|
67
|
+
<Name extends string, Path extends string | string[]>(
|
|
70
68
|
name: Name,
|
|
71
69
|
path: Path,
|
|
72
|
-
): Observable<Get<
|
|
70
|
+
): Observable<Get<Lookup[Name], Path>>
|
|
73
71
|
|
|
74
72
|
// with state:
|
|
75
|
-
<Name extends
|
|
76
|
-
name: Name,
|
|
77
|
-
state: number,
|
|
78
|
-
): Observable<GettablePossibleEmpty<Data>>
|
|
73
|
+
<Name extends string>(name: Name, state: number): Observable<Lookup[Name]>
|
|
79
74
|
|
|
80
75
|
// with path and state:
|
|
81
|
-
<Name extends
|
|
76
|
+
<Name extends string, Path extends string | string[]>(
|
|
82
77
|
name: Name,
|
|
83
78
|
path: Path,
|
|
84
79
|
state: number,
|
|
85
|
-
): Observable<Get<
|
|
80
|
+
): Observable<Get<Lookup[Name], Path>>
|
|
86
81
|
}
|
|
87
82
|
|
|
88
83
|
get: {
|
|
89
84
|
// without path:
|
|
90
|
-
<Name extends
|
|
91
|
-
name: Name,
|
|
92
|
-
state?: number,
|
|
93
|
-
): Promise<GettablePossibleEmpty<Data>>
|
|
85
|
+
<Name extends string>(name: Name, state?: number): Promise<Lookup[Name]>
|
|
94
86
|
|
|
95
87
|
// with path:
|
|
96
|
-
<Name extends
|
|
88
|
+
<Name extends string, Path extends string | string[]>(
|
|
97
89
|
name: Name,
|
|
98
|
-
path
|
|
90
|
+
path: Path,
|
|
99
91
|
state?: number,
|
|
100
|
-
): Promise<Get<
|
|
92
|
+
): Promise<Get<Lookup[Name], Path>>
|
|
101
93
|
}
|
|
102
94
|
|
|
103
95
|
observe2: {
|
|
104
96
|
// without path:
|
|
105
|
-
<Name extends
|
|
97
|
+
<Name extends string>(
|
|
106
98
|
name: Name,
|
|
107
99
|
): Observable<{
|
|
108
|
-
name:
|
|
100
|
+
name: string
|
|
109
101
|
version: string
|
|
110
102
|
state: number
|
|
111
|
-
data:
|
|
103
|
+
data: Lookup[Name]
|
|
112
104
|
}>
|
|
113
105
|
|
|
114
106
|
// with path:
|
|
115
|
-
<Name extends
|
|
107
|
+
<Name extends string, Path extends string | string[]>(
|
|
116
108
|
name: Name,
|
|
117
109
|
path: Path,
|
|
118
110
|
): Observable<{
|
|
119
|
-
name:
|
|
111
|
+
name: string
|
|
120
112
|
version: string
|
|
121
113
|
state: number
|
|
122
|
-
data: Get<
|
|
114
|
+
data: Get<Lookup[Name], Path>
|
|
123
115
|
}>
|
|
124
116
|
|
|
125
117
|
// with state:
|
|
126
|
-
<Name extends
|
|
118
|
+
<Name extends string>(
|
|
127
119
|
name: Name,
|
|
128
120
|
state: number,
|
|
129
121
|
): Observable<{
|
|
130
|
-
name:
|
|
122
|
+
name: string
|
|
131
123
|
version: string
|
|
132
124
|
state: number
|
|
133
|
-
data:
|
|
125
|
+
data: Lookup[Name]
|
|
134
126
|
}>
|
|
135
127
|
|
|
136
128
|
// with path and state:
|
|
137
|
-
<Name extends
|
|
129
|
+
<Name extends string, Path extends string | string[]>(
|
|
138
130
|
name: Name,
|
|
139
131
|
path: Path,
|
|
140
132
|
state: number,
|
|
141
133
|
): Observable<{
|
|
142
|
-
name:
|
|
134
|
+
name: string
|
|
143
135
|
version: string
|
|
144
136
|
state: number
|
|
145
|
-
data: Get<
|
|
137
|
+
data: Get<Lookup[Name], Path>
|
|
146
138
|
}>
|
|
147
139
|
}
|
|
148
140
|
}
|
|
@@ -156,3 +148,13 @@ export interface RecordStats {
|
|
|
156
148
|
patching: number
|
|
157
149
|
subscriptions: number
|
|
158
150
|
}
|
|
151
|
+
|
|
152
|
+
export interface ProvideOptions {
|
|
153
|
+
recursive?: boolean
|
|
154
|
+
stringify?: ((input: unknown) => string) | null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface SyncOptions {
|
|
158
|
+
signal?: AbortSignal
|
|
159
|
+
timeout?: number
|
|
160
|
+
}
|
|
@@ -276,14 +276,15 @@ class RecordHandler {
|
|
|
276
276
|
// TODO (perf): Slow implementation...
|
|
277
277
|
|
|
278
278
|
const signal = opts?.signal
|
|
279
|
-
const timeout = opts?.timeout
|
|
279
|
+
const timeout = opts?.timeout
|
|
280
280
|
|
|
281
|
-
|
|
281
|
+
let disposers
|
|
282
282
|
try {
|
|
283
283
|
const signalPromise = signal
|
|
284
284
|
? new Promise((resolve, reject) => {
|
|
285
285
|
const onAbort = () => reject(signal.reason ?? new utils.AbortError())
|
|
286
286
|
signal.addEventListener('abort', onAbort)
|
|
287
|
+
disposers ??= []
|
|
287
288
|
disposers.push(() => signal.removeEventListener('abort', onAbort))
|
|
288
289
|
})
|
|
289
290
|
: null
|
|
@@ -291,13 +292,14 @@ class RecordHandler {
|
|
|
291
292
|
signalPromise?.catch(noop)
|
|
292
293
|
|
|
293
294
|
if (this._patching.size) {
|
|
294
|
-
|
|
295
|
+
let promises
|
|
295
296
|
|
|
296
297
|
{
|
|
297
298
|
const patchingPromises = []
|
|
298
299
|
for (const callbacks of this._patching.values()) {
|
|
299
300
|
patchingPromises.push(new Promise((resolve) => callbacks.push(resolve)))
|
|
300
301
|
}
|
|
302
|
+
promises ??= []
|
|
301
303
|
promises.push(Promise.all(patchingPromises))
|
|
302
304
|
}
|
|
303
305
|
|
|
@@ -312,30 +314,36 @@ class RecordHandler {
|
|
|
312
314
|
)
|
|
313
315
|
resolve(null)
|
|
314
316
|
}, timeout)
|
|
317
|
+
disposers ??= []
|
|
315
318
|
disposers.push(() => timers.clearTimeout(patchingTimeout))
|
|
316
319
|
}),
|
|
317
320
|
)
|
|
318
321
|
}
|
|
319
322
|
|
|
320
323
|
if (signalPromise) {
|
|
324
|
+
promises ??= []
|
|
321
325
|
promises.push(signalPromise)
|
|
322
326
|
}
|
|
323
327
|
|
|
324
|
-
|
|
328
|
+
if (promises) {
|
|
329
|
+
await Promise.race(promises)
|
|
330
|
+
}
|
|
325
331
|
}
|
|
326
332
|
|
|
327
333
|
if (this._updating.size) {
|
|
328
|
-
|
|
334
|
+
let promises
|
|
329
335
|
|
|
330
336
|
{
|
|
331
337
|
const updatingPromises = []
|
|
332
338
|
for (const callbacks of this._updating.values()) {
|
|
333
339
|
updatingPromises.push(new Promise((resolve) => callbacks.push(resolve)))
|
|
334
340
|
}
|
|
341
|
+
promises ??= []
|
|
335
342
|
promises.push(Promise.all(updatingPromises))
|
|
336
343
|
}
|
|
337
344
|
|
|
338
345
|
if (timeout) {
|
|
346
|
+
promises ??= []
|
|
339
347
|
promises.push(
|
|
340
348
|
new Promise((resolve) => {
|
|
341
349
|
const updatingTimeout = timers.setTimeout(() => {
|
|
@@ -346,39 +354,52 @@ class RecordHandler {
|
|
|
346
354
|
)
|
|
347
355
|
resolve(null)
|
|
348
356
|
}, timeout)
|
|
357
|
+
disposers ??= []
|
|
349
358
|
disposers.push(() => timers.clearTimeout(updatingTimeout))
|
|
350
359
|
}),
|
|
351
360
|
)
|
|
352
361
|
}
|
|
353
362
|
|
|
354
|
-
|
|
363
|
+
if (promises) {
|
|
364
|
+
await Promise.race(promises)
|
|
365
|
+
}
|
|
355
366
|
}
|
|
356
367
|
|
|
357
368
|
{
|
|
358
|
-
const
|
|
369
|
+
const syncPromise = new Promise((resolve) => this._sync(resolve))
|
|
359
370
|
|
|
360
|
-
promises
|
|
371
|
+
let promises
|
|
361
372
|
|
|
362
373
|
if (timeout) {
|
|
374
|
+
promises ??= []
|
|
363
375
|
promises.push(
|
|
364
376
|
new Promise((resolve, reject) => {
|
|
365
377
|
const serverTimeout = timers.setTimeout(() => {
|
|
366
378
|
reject(new Error('sync server timeout'))
|
|
367
379
|
}, timeout)
|
|
380
|
+
disposers ??= []
|
|
368
381
|
disposers.push(() => timers.clearTimeout(serverTimeout))
|
|
369
382
|
}),
|
|
370
383
|
)
|
|
371
384
|
}
|
|
372
385
|
|
|
373
386
|
if (signalPromise) {
|
|
387
|
+
promises ??= []
|
|
374
388
|
promises.push(signalPromise)
|
|
375
389
|
}
|
|
376
390
|
|
|
377
|
-
|
|
391
|
+
if (promises) {
|
|
392
|
+
promises.push(syncPromise)
|
|
393
|
+
await Promise.race(promises)
|
|
394
|
+
} else {
|
|
395
|
+
await syncPromise
|
|
396
|
+
}
|
|
378
397
|
}
|
|
379
398
|
} finally {
|
|
380
|
-
|
|
381
|
-
disposer
|
|
399
|
+
if (disposers) {
|
|
400
|
+
for (const disposer of disposers) {
|
|
401
|
+
disposer()
|
|
402
|
+
}
|
|
382
403
|
}
|
|
383
404
|
}
|
|
384
405
|
}
|
package/src/record/record.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import type RecordHandler from './record-handler.js'
|
|
2
|
-
import type { EmptyObject, SingleKeyObject } from 'type-fest'
|
|
3
|
-
|
|
4
|
-
type Paths<T> = keyof T
|
|
5
|
-
type Get<Data, Path extends string> = Path extends keyof Data ? Data[Path] : unknown
|
|
6
|
-
|
|
7
|
-
export type { EmptyObject } from 'type-fest'
|
|
2
|
+
import type { Get, EmptyObject, SingleKeyObject } from 'type-fest'
|
|
3
|
+
export type { Get, Paths, EmptyObject } from 'type-fest'
|
|
8
4
|
|
|
9
5
|
// When getting, for convenience, we say the data might be partial under some
|
|
10
6
|
// circumstances.
|
|
@@ -45,12 +41,12 @@ export interface UpdateOptions {
|
|
|
45
41
|
signal?: AbortSignal
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
export default class Record<Data> {
|
|
44
|
+
export default class Record<Data = unknown> {
|
|
49
45
|
constructor(name: string, handler: RecordHandler)
|
|
50
46
|
|
|
51
47
|
readonly name: string
|
|
52
48
|
readonly version: string
|
|
53
|
-
readonly data:
|
|
49
|
+
readonly data: Data
|
|
54
50
|
readonly state: number
|
|
55
51
|
readonly refs: number
|
|
56
52
|
|
|
@@ -61,29 +57,16 @@ export default class Record<Data> {
|
|
|
61
57
|
|
|
62
58
|
get: {
|
|
63
59
|
// with path
|
|
64
|
-
<
|
|
65
|
-
path: Path,
|
|
66
|
-
): DataAtPath | undefined
|
|
60
|
+
<P extends string | string[]>(path: P): Get<Data, P>
|
|
67
61
|
// without path
|
|
68
|
-
():
|
|
69
|
-
// implementation
|
|
70
|
-
<Path extends Paths<Data>, DataAtPath extends Get<Data, Path> = Get<Data, Path>>(
|
|
71
|
-
path?: Path,
|
|
72
|
-
): Path extends undefined ? GettablePossibleEmpty<Data> : DataAtPath | undefined
|
|
62
|
+
(): Data
|
|
73
63
|
}
|
|
74
64
|
|
|
75
65
|
set: {
|
|
76
66
|
// with path
|
|
77
|
-
<
|
|
78
|
-
path: Path,
|
|
79
|
-
dataAtPath: DataAtPath,
|
|
80
|
-
): void
|
|
67
|
+
<P extends string | string[]>(path: P, dataAtPath: Get<Data, P>): void
|
|
81
68
|
// without path
|
|
82
69
|
(data: SettablePossibleEmpty<Data>): void
|
|
83
|
-
// implementation
|
|
84
|
-
<Path extends Paths<Data>, DataAtPath extends Get<Data, Path>>(
|
|
85
|
-
...args: [pathOrData: Path | SettablePossibleEmpty<Data>, value?: DataAtPath]
|
|
86
|
-
): void
|
|
87
70
|
}
|
|
88
71
|
|
|
89
72
|
when: {
|
|
@@ -93,18 +76,17 @@ export default class Record<Data> {
|
|
|
93
76
|
(state: number, options: WhenOptions): Promise<Record<Data>>
|
|
94
77
|
}
|
|
95
78
|
|
|
96
|
-
update
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
): Promise<void>
|
|
79
|
+
update: {
|
|
80
|
+
// without path
|
|
81
|
+
(
|
|
82
|
+
updater: (data: Readonly<Data>) => SettablePossibleEmpty<Data>,
|
|
83
|
+
options?: UpdateOptions,
|
|
84
|
+
): Promise<void>
|
|
85
|
+
// with path
|
|
86
|
+
<P extends string | string[]>(
|
|
87
|
+
path: P,
|
|
88
|
+
updater: (dataAtPath: Readonly<Get<Data, P>>) => Get<Data, P>,
|
|
89
|
+
options?: UpdateOptions,
|
|
90
|
+
): Promise<void>
|
|
91
|
+
}
|
|
110
92
|
}
|