@nxtedition/deepstream.io-client-js 28.1.4 → 28.1.6
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/nxtedition-deepstream.io-client-js-28.1.6-1.tgz +0 -0
- package/package.json +2 -1
- package/src/client.d.ts +4 -4
- package/src/record/record-handler.d.ts +29 -28
- package/src/record/record.d.ts +47 -10
- package/src/test.ts +177 -0
|
Binary file
|
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.6",
|
|
4
4
|
"description": "the javascript client for deepstream.io",
|
|
5
5
|
"homepage": "http://deepstream.io",
|
|
6
6
|
"type": "module",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"pinst": "^3.0.0",
|
|
61
61
|
"prettier": "^3.3.3",
|
|
62
62
|
"rxjs": "^7.8.1",
|
|
63
|
+
"type-fest": "^4.33.0",
|
|
63
64
|
"typescript": "^5.6.3",
|
|
64
65
|
"typescript-eslint": "^8.12.2"
|
|
65
66
|
},
|
package/src/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import Record from './record/record.js'
|
|
2
|
-
import RecordHandler, { RecordStats } from './record/record-handler.js'
|
|
3
|
-
import EventHandler, { EventStats } from './event/event-handler.js'
|
|
4
|
-
import RpcHandler, { RpcStats, RpcMethodDef } from './rpc/rpc-handler.js'
|
|
1
|
+
import type Record from './record/record.js'
|
|
2
|
+
import type RecordHandler, { RecordStats } from './record/record-handler.js'
|
|
3
|
+
import type EventHandler, { EventStats } from './event/event-handler.js'
|
|
4
|
+
import type RpcHandler, { RpcStats, RpcMethodDef } from './rpc/rpc-handler.js'
|
|
5
5
|
|
|
6
6
|
export default function <Records, Methods>(
|
|
7
7
|
url: string,
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import type { Observable } from 'rxjs'
|
|
2
|
-
import Record from './record.js'
|
|
2
|
+
import type Record, { EmptyObject, GettablePossibleEmpty, SettablePossibleEmpty } from './record.js'
|
|
3
3
|
|
|
4
4
|
type Paths<T> = keyof T
|
|
5
5
|
type Get<Data, Path extends string> = Path extends keyof Data ? Data[Path] : unknown
|
|
6
6
|
|
|
7
7
|
export default class RecordHandler<Records> {
|
|
8
|
-
VOID:
|
|
9
|
-
CLIENT:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
VOID: 0
|
|
9
|
+
CLIENT: 1
|
|
10
|
+
SERVER: 2
|
|
11
|
+
STALE: 3
|
|
12
|
+
PROVIDER: 4
|
|
13
13
|
|
|
14
14
|
JSON: {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
18
|
-
EMPTY_OBJ: Readonly<{}>
|
|
15
|
+
EMPTY: EmptyObject
|
|
16
|
+
EMPTY_OBJ: EmptyObject
|
|
19
17
|
EMPTY_ARR: Readonly<unknown[]>
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
connected: boolean
|
|
23
21
|
stats: RecordStats
|
|
22
|
+
|
|
24
23
|
getRecord: <Name extends keyof Records, Data extends Records[Name] = Records[Name]>(
|
|
25
24
|
name: Name,
|
|
26
25
|
) => Record<Data>
|
|
@@ -35,7 +34,7 @@ export default class RecordHandler<Records> {
|
|
|
35
34
|
|
|
36
35
|
set: {
|
|
37
36
|
// without path:
|
|
38
|
-
<Name extends keyof Records>(name: Name, data: Records[Name]): void
|
|
37
|
+
<Name extends keyof Records>(name: Name, data: SettablePossibleEmpty<Records[Name]>): void
|
|
39
38
|
|
|
40
39
|
// with path:
|
|
41
40
|
<Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data>>(
|
|
@@ -49,39 +48,41 @@ export default class RecordHandler<Records> {
|
|
|
49
48
|
// without path:
|
|
50
49
|
<Name extends keyof Records, Data extends Records[Name]>(
|
|
51
50
|
name: Name,
|
|
52
|
-
updater: (data: Data) => Data
|
|
51
|
+
updater: (data: Readonly<GettablePossibleEmpty<Data>>) => SettablePossibleEmpty<Data>,
|
|
53
52
|
): Promise<void>
|
|
54
53
|
|
|
55
54
|
// with path:
|
|
56
55
|
<Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data>>(
|
|
57
56
|
name: Name,
|
|
58
57
|
path: Path,
|
|
59
|
-
updater: (data: Get<Data, Path
|
|
58
|
+
updater: (data: Readonly<Get<Data, Path>> | undefined) => Get<Data, Path>,
|
|
60
59
|
): Promise<void>
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
observe: {
|
|
64
63
|
// without path:
|
|
65
|
-
<Name extends keyof Records, Data extends Records[Name]>(
|
|
64
|
+
<Name extends keyof Records, Data extends Records[Name]>(
|
|
65
|
+
name: Name,
|
|
66
|
+
): Observable<GettablePossibleEmpty<Data>>
|
|
66
67
|
|
|
67
68
|
// with path:
|
|
68
69
|
<Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
|
|
69
70
|
name: Name,
|
|
70
71
|
path: Path,
|
|
71
|
-
): Observable<Get<Data, Path
|
|
72
|
+
): Observable<Get<Data, Path> | undefined>
|
|
72
73
|
|
|
73
74
|
// with state:
|
|
74
75
|
<Name extends keyof Records, Data extends Records[Name]>(
|
|
75
76
|
name: Name,
|
|
76
|
-
state:
|
|
77
|
-
): Observable<Data
|
|
77
|
+
state: number,
|
|
78
|
+
): Observable<GettablePossibleEmpty<Data>>
|
|
78
79
|
|
|
79
80
|
// with path and state:
|
|
80
81
|
<Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
|
|
81
82
|
name: Name,
|
|
82
83
|
path: Path,
|
|
83
84
|
state: number,
|
|
84
|
-
): Observable<Get<Data, Path
|
|
85
|
+
): Observable<Get<Data, Path> | undefined>
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
get: {
|
|
@@ -89,14 +90,14 @@ export default class RecordHandler<Records> {
|
|
|
89
90
|
<Name extends keyof Records, Data extends Records[Name]>(
|
|
90
91
|
name: Name,
|
|
91
92
|
state?: number,
|
|
92
|
-
): Promise<Data
|
|
93
|
+
): Promise<GettablePossibleEmpty<Data>>
|
|
93
94
|
|
|
94
95
|
// with path:
|
|
95
96
|
<Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
|
|
96
97
|
name: Name,
|
|
97
98
|
path?: Path,
|
|
98
99
|
state?: number,
|
|
99
|
-
): Promise<Get<Data, Path
|
|
100
|
+
): Promise<Get<Data, Path> | undefined>
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
observe2: {
|
|
@@ -107,7 +108,7 @@ export default class RecordHandler<Records> {
|
|
|
107
108
|
name: Name
|
|
108
109
|
version: string
|
|
109
110
|
state: number
|
|
110
|
-
data: Data
|
|
111
|
+
data: GettablePossibleEmpty<Data>
|
|
111
112
|
}>
|
|
112
113
|
|
|
113
114
|
// with path:
|
|
@@ -116,20 +117,20 @@ export default class RecordHandler<Records> {
|
|
|
116
117
|
path: Path,
|
|
117
118
|
): Observable<{
|
|
118
119
|
name: Name
|
|
119
|
-
version:
|
|
120
|
+
version: string
|
|
120
121
|
state: number
|
|
121
|
-
data: Data
|
|
122
|
+
data: Get<Data, Path> | undefined
|
|
122
123
|
}>
|
|
123
124
|
|
|
124
125
|
// with state:
|
|
125
126
|
<Name extends keyof Records, Data extends Records[Name]>(
|
|
126
127
|
name: Name,
|
|
127
|
-
state:
|
|
128
|
+
state: number,
|
|
128
129
|
): Observable<{
|
|
129
130
|
name: Name
|
|
130
|
-
version:
|
|
131
|
+
version: string
|
|
131
132
|
state: number
|
|
132
|
-
data: Data
|
|
133
|
+
data: GettablePossibleEmpty<Data>
|
|
133
134
|
}>
|
|
134
135
|
|
|
135
136
|
// with path and state:
|
|
@@ -139,9 +140,9 @@ export default class RecordHandler<Records> {
|
|
|
139
140
|
state: number,
|
|
140
141
|
): Observable<{
|
|
141
142
|
name: Name
|
|
142
|
-
version:
|
|
143
|
+
version: string
|
|
143
144
|
state: number
|
|
144
|
-
data: Get<Data, Path>
|
|
145
|
+
data: Get<Data, Path> | undefined
|
|
145
146
|
}>
|
|
146
147
|
}
|
|
147
148
|
}
|
package/src/record/record.d.ts
CHANGED
|
@@ -1,10 +1,42 @@
|
|
|
1
|
-
import RecordHandler from './record-handler.js'
|
|
1
|
+
import type RecordHandler from './record-handler.js'
|
|
2
|
+
import type { EmptyObject, SingleKeyObject } from 'type-fest'
|
|
2
3
|
|
|
3
4
|
type Paths<T> = keyof T
|
|
4
5
|
type Get<Data, Path extends string> = Path extends keyof Data ? Data[Path] : unknown
|
|
5
6
|
|
|
7
|
+
export type { EmptyObject } from 'type-fest'
|
|
8
|
+
|
|
9
|
+
// When getting, for convenience, we say the data might be partial under some
|
|
10
|
+
// circumstances.
|
|
11
|
+
//
|
|
12
|
+
// When you e.g. do record.get or record.update, there is always a possibility
|
|
13
|
+
// that the data object is empty. The naive correct type for that would be
|
|
14
|
+
// `Data | EmptyObject`. However, that forces the user to always type guard
|
|
15
|
+
// against the empty object case. This type tries to allow the user to skip
|
|
16
|
+
// that check in some cases, where it should be safe to do so.
|
|
17
|
+
export type GettablePossibleEmpty<Data> = keyof Data extends never
|
|
18
|
+
? EmptyObject // If there are no keys at all
|
|
19
|
+
: Partial<Data> extends Data
|
|
20
|
+
? // All properties in Data are already optional, so we can safely return it
|
|
21
|
+
// as is. The user just need to check the properties themselves instead.
|
|
22
|
+
Data
|
|
23
|
+
: SingleKeyObject<Data> extends never
|
|
24
|
+
? // There are more than one property in Data, and some of them are
|
|
25
|
+
// required. That means that the user must always check for the empty
|
|
26
|
+
// object case.
|
|
27
|
+
Data | EmptyObject
|
|
28
|
+
: // There is exactly one property in Data, and it is required. In this
|
|
29
|
+
// particular case, we can safely use Data as the "empty" type, but
|
|
30
|
+
// with the single property turned optional.
|
|
31
|
+
{
|
|
32
|
+
[K in keyof Data]+?: Data[K]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// When setting the data must fully adhere to the Data type, or exactly an
|
|
36
|
+
// empty object.
|
|
37
|
+
export type SettablePossibleEmpty<Data> = Data | EmptyObject
|
|
38
|
+
|
|
6
39
|
export interface WhenOptions {
|
|
7
|
-
state?: number
|
|
8
40
|
timeout?: number
|
|
9
41
|
signal?: AbortSignal
|
|
10
42
|
}
|
|
@@ -18,7 +50,7 @@ export default class Record<Data> {
|
|
|
18
50
|
|
|
19
51
|
readonly name: string
|
|
20
52
|
readonly version: string
|
|
21
|
-
readonly data: Data
|
|
53
|
+
readonly data: GettablePossibleEmpty<Data>
|
|
22
54
|
readonly state: number
|
|
23
55
|
readonly refs: number
|
|
24
56
|
|
|
@@ -31,13 +63,13 @@ export default class Record<Data> {
|
|
|
31
63
|
// with path
|
|
32
64
|
<Path extends Paths<Data>, DataAtPath extends Get<Data, Path> = Get<Data, Path>>(
|
|
33
65
|
path: Path,
|
|
34
|
-
): DataAtPath
|
|
66
|
+
): DataAtPath | undefined
|
|
35
67
|
// without path
|
|
36
|
-
(): Data
|
|
68
|
+
(): GettablePossibleEmpty<Data>
|
|
37
69
|
// implementation
|
|
38
70
|
<Path extends Paths<Data>, DataAtPath extends Get<Data, Path> = Get<Data, Path>>(
|
|
39
71
|
path?: Path,
|
|
40
|
-
): Path extends undefined ? Data : DataAtPath
|
|
72
|
+
): Path extends undefined ? GettablePossibleEmpty<Data> : DataAtPath | undefined
|
|
41
73
|
}
|
|
42
74
|
|
|
43
75
|
set: {
|
|
@@ -47,10 +79,10 @@ export default class Record<Data> {
|
|
|
47
79
|
dataAtPath: DataAtPath,
|
|
48
80
|
): void
|
|
49
81
|
// without path
|
|
50
|
-
(data: Data): void
|
|
82
|
+
(data: SettablePossibleEmpty<Data>): void
|
|
51
83
|
// implementation
|
|
52
84
|
<Path extends Paths<Data>, DataAtPath extends Get<Data, Path>>(
|
|
53
|
-
...args: [pathOrData: Path | Data
|
|
85
|
+
...args: [pathOrData: Path | SettablePossibleEmpty<Data>, value?: DataAtPath]
|
|
54
86
|
): void
|
|
55
87
|
}
|
|
56
88
|
|
|
@@ -61,11 +93,16 @@ export default class Record<Data> {
|
|
|
61
93
|
(state: number, options: WhenOptions): Promise<Record<Data>>
|
|
62
94
|
}
|
|
63
95
|
|
|
64
|
-
update<
|
|
96
|
+
update<
|
|
97
|
+
Path extends Paths<Data>,
|
|
98
|
+
PathOrUpdater extends
|
|
99
|
+
| Path
|
|
100
|
+
| ((data: Readonly<GettablePossibleEmpty<Data>>) => SettablePossibleEmpty<Data>),
|
|
101
|
+
>(
|
|
65
102
|
...args: PathOrUpdater extends Path
|
|
66
103
|
? [
|
|
67
104
|
path: Path,
|
|
68
|
-
updater: (dataAtPath: Get<Data, Path
|
|
105
|
+
updater: (dataAtPath: Readonly<Get<Data, Path>> | undefined) => Get<Data, Path>,
|
|
69
106
|
options?: UpdateOptions,
|
|
70
107
|
]
|
|
71
108
|
: [updater: PathOrUpdater, options?: UpdateOptions]
|
package/src/test.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import make from './client.js'
|
|
2
|
+
import {
|
|
3
|
+
EmptyObject,
|
|
4
|
+
GettablePossibleEmpty,
|
|
5
|
+
PossiblyEmptyData,
|
|
6
|
+
SettablePossibleEmpty,
|
|
7
|
+
} from './record/record.js'
|
|
8
|
+
import { assertNonEmpty } from './record/record-handler.js'
|
|
9
|
+
|
|
10
|
+
interface Records {
|
|
11
|
+
test: {
|
|
12
|
+
name: string
|
|
13
|
+
age: number
|
|
14
|
+
}
|
|
15
|
+
foo: {
|
|
16
|
+
bar: number
|
|
17
|
+
}
|
|
18
|
+
tjena: {
|
|
19
|
+
optional?: string
|
|
20
|
+
}
|
|
21
|
+
num: number
|
|
22
|
+
str: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface Methods {
|
|
26
|
+
test: [{ name: string }, { age: number }]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ds = make<Records, Methods>('http://localhost:3000')
|
|
30
|
+
|
|
31
|
+
const y = await ds.record.get('test')
|
|
32
|
+
if ('age' in y) {
|
|
33
|
+
console.log(y.name)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const q: PossiblyEmptyData<{ test: number }> = {}
|
|
37
|
+
console.log(q.test)
|
|
38
|
+
if ('test' in q) {
|
|
39
|
+
console.log(q.test)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const w: PossiblyEmptyData<{ test: number; haj: number }> = { test: 22, haj: 22 }
|
|
43
|
+
|
|
44
|
+
function test<D>(cb: (data: GettablePossibleEmpty<D>) => SettablePossibleEmpty<D>) {
|
|
45
|
+
// cb({})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
test<{ foo: number; bar: number }>((data) => {
|
|
49
|
+
return data
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test<{ foo?: number; bar: number }>(() => {
|
|
53
|
+
return {
|
|
54
|
+
foo: 22,
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test<{ foo?: number; bar: number }>((data) => {
|
|
59
|
+
// return data
|
|
60
|
+
const a= {
|
|
61
|
+
...data,
|
|
62
|
+
foo: 22,
|
|
63
|
+
}
|
|
64
|
+
return a
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test<{ foo?: number; bar?: number }>((data) => {
|
|
68
|
+
return {
|
|
69
|
+
...data,
|
|
70
|
+
foo: 22,
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const y = await ds.record.get('test')
|
|
75
|
+
if ('age' in y) {
|
|
76
|
+
console.log(y.name)
|
|
77
|
+
|
|
78
|
+
test<{ foo?: number }>((data) => {
|
|
79
|
+
return data
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test<{ foo: number }>((data) => {
|
|
83
|
+
return {
|
|
84
|
+
...data,
|
|
85
|
+
foo: 22,
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
if ('test' in w) {
|
|
90
|
+
console.log(w.haj)
|
|
91
|
+
}
|
|
92
|
+
console.log(w.test)
|
|
93
|
+
console.log(w.test)
|
|
94
|
+
|
|
95
|
+
const m: PossiblyEmptyData<{ test?: number }> = {}
|
|
96
|
+
console.log(m.test)
|
|
97
|
+
|
|
98
|
+
assertNonEmpty(q)
|
|
99
|
+
q.test
|
|
100
|
+
// q.test
|
|
101
|
+
|
|
102
|
+
// q
|
|
103
|
+
|
|
104
|
+
ds.record.set('test', ds.record.JSON.EMPTY_OBJ)
|
|
105
|
+
|
|
106
|
+
ds.record.update('test', (data) => {
|
|
107
|
+
const a = {
|
|
108
|
+
// ...data,
|
|
109
|
+
age: 22,
|
|
110
|
+
}
|
|
111
|
+
console.log(data.name)
|
|
112
|
+
return {
|
|
113
|
+
...data,
|
|
114
|
+
age: 22,
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
ds.record.provide('test', () => {})
|
|
119
|
+
|
|
120
|
+
ds.record.set('test', {
|
|
121
|
+
name: 23,
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
ds.record.set('foo', { value: 'namn' })
|
|
125
|
+
ds.record.set('foo', { bar: 22 })
|
|
126
|
+
ds.record.set('foo', {})
|
|
127
|
+
|
|
128
|
+
ds.record.set('test', 'name', '23')
|
|
129
|
+
|
|
130
|
+
ds.record.provide('test', () => {
|
|
131
|
+
return {
|
|
132
|
+
name: 23,
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
ds.record.update('test', 'name', (name) => {
|
|
137
|
+
return name
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
const r = ds.record.getRecord('test')
|
|
141
|
+
//const name = r.get('bar')
|
|
142
|
+
|
|
143
|
+
r.update('name', (name) => name + 'a2', { signal: new AbortSignal() })
|
|
144
|
+
|
|
145
|
+
r.update((name) => ({ name: 'hej', age: 22 }))
|
|
146
|
+
|
|
147
|
+
r.update('age', (age) => age + 1, { signal: new AbortSignal() })
|
|
148
|
+
|
|
149
|
+
r.set({ age: 23, name: 'test' })
|
|
150
|
+
r.set({ age: '23', name: 'test' })
|
|
151
|
+
|
|
152
|
+
r.set('name', 22)
|
|
153
|
+
r.set('name', 'name')
|
|
154
|
+
r.set('age', true)
|
|
155
|
+
r.set('age', 22)
|
|
156
|
+
|
|
157
|
+
ds.record.set('test', {})
|
|
158
|
+
|
|
159
|
+
const a1 = r.get()
|
|
160
|
+
const a2 = r.get('age')
|
|
161
|
+
const a3 = r.get('name')
|
|
162
|
+
const a4 = r.get('what')
|
|
163
|
+
|
|
164
|
+
const name = r.get('age')
|
|
165
|
+
|
|
166
|
+
const s = Object.freeze({})
|
|
167
|
+
|
|
168
|
+
ds.record.JSON.EMPTY
|
|
169
|
+
|
|
170
|
+
ds.event.provide('test', (what) => {}, {})
|
|
171
|
+
|
|
172
|
+
const a = ds.rpc.provide('test', (args, response) => {
|
|
173
|
+
console.log(args.name)
|
|
174
|
+
response.send({ age: 22 })
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
a()
|