@nxtedition/deepstream.io-client-js 31.0.13 → 31.0.15

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.
@@ -0,0 +1,9 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm run test:types:*)"
5
+ ],
6
+ "deny": [],
7
+ "ask": []
8
+ }
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/deepstream.io-client-js",
3
- "version": "31.0.13",
3
+ "version": "31.0.15",
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}": [
@@ -61,6 +62,7 @@
61
62
  "pinst": "^3.0.0",
62
63
  "prettier": "^3.3.3",
63
64
  "rxjs": "^7.8.1",
65
+ "tsd": "^0.33.0",
64
66
  "type-fest": "^4.33.0",
65
67
  "typescript": "^5.6.3",
66
68
  "typescript-eslint": "^8.12.2"
package/src/client.d.ts CHANGED
@@ -1,14 +1,28 @@
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'
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 <Records, Methods>(
7
- url: string,
8
- options?: unknown,
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 { Record, RecordHandler, EventHandler, RpcHandler }
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 typeof ConnectionStateConstants
32
- type ConnectionStateName = (typeof ConnectionStateConstants)[ConnectionStateKey]
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 typeof EventConstants
65
- type EventName = (typeof EventConstants)[EventKey]
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'] })
@@ -5,7 +5,7 @@ const SEP = C.MESSAGE_PART_SEPERATOR
5
5
 
6
6
  let poolBuf
7
7
  let poolPos = 0
8
- let poolSize = 2 * 1024 * 1024
8
+ let poolLen = 2 * 1024 * 1024
9
9
 
10
10
  export function getMsg(topic, action, data, binary) {
11
11
  if (data && !(data instanceof Array)) {
@@ -33,8 +33,8 @@ export function getMsg(topic, action, data, binary) {
33
33
  }
34
34
 
35
35
  if (!poolBuf || poolBuf.byteLength - poolPos < estimatedSize * 2) {
36
- poolSize = Math.max(poolSize, estimatedSize * 2)
37
- poolBuf = Buffer.allocUnsafeSlow(poolSize)
36
+ poolLen = Math.max(poolLen, estimatedSize * 2)
37
+ poolBuf = Buffer.allocUnsafeSlow(poolLen)
38
38
  poolPos = 0
39
39
  }
40
40
 
@@ -79,7 +79,7 @@ export function getMsg(topic, action, data, binary) {
79
79
  dataPos += len
80
80
 
81
81
  if (dataPos >= poolPos + poolBuf.byteLength) {
82
- poolSize *= poolPos === 0 ? 2 : 1
82
+ poolLen *= poolPos === 0 ? 2 : 1
83
83
  poolBuf = null
84
84
  poolPos = 0
85
85
  return getMsg(topic, action, data, binary)
@@ -1,10 +1,10 @@
1
1
  import type { Observable } from 'rxjs'
2
- import type Record, { EmptyObject, GettablePossibleEmpty, SettablePossibleEmpty } from './record.js'
2
+ import type DsRecord from './record.js'
3
+ import type { EmptyObject, Get, Paths } from './record.js'
3
4
 
4
- type Paths<T> = keyof T
5
- type Get<Data, Path extends string> = Path extends keyof Data ? Data[Path] : unknown
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: <Name extends keyof Records, Data extends Records[Name] = Records[Name]>(
23
+ getRecord<Name extends string, Data = Name extends keyof Lookup ? Lookup[Name] : unknown>(
24
24
  name: Name,
25
- ) => Record<Data>
25
+ ): DsRecord<Data>
26
26
 
27
- provide: <Data>(
27
+ provide: (
28
28
  pattern: string,
29
- callback: (key: string) => Data,
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 keyof Records>(name: Name, data: SettablePossibleEmpty<Records[Name]>): void
37
+ <Name extends string>(name: Name, data: Lookup[Name] | EmptyObject): void
38
38
 
39
39
  // with path:
40
- <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data>>(
40
+ <Name extends string, Path extends string | string[]>(
41
41
  name: Name,
42
42
  path: Path,
43
- data: Get<Data, Path>,
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 keyof Records, Data extends Records[Name]>(
49
+ <Name extends string>(
50
50
  name: Name,
51
- updater: (data: Readonly<GettablePossibleEmpty<Data>>) => SettablePossibleEmpty<Data>,
51
+ updater: (data: Lookup[Name]) => Lookup[Name] | EmptyObject,
52
52
  ): Promise<void>
53
53
 
54
54
  // with path:
55
- <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data>>(
55
+ <Name extends string, Path extends string | string[]>(
56
56
  name: Name,
57
57
  path: Path,
58
- updater: (data: Readonly<Get<Data, Path>> | undefined) => Get<Data, Path>,
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 keyof Records, Data extends Records[Name]>(
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 keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
67
+ <Name extends string, Path extends string | string[]>(
70
68
  name: Name,
71
69
  path: Path,
72
- ): Observable<Get<Data, Path> | undefined>
70
+ ): Observable<Get<Lookup[Name], Path>>
73
71
 
74
72
  // with state:
75
- <Name extends keyof Records, Data extends Records[Name]>(
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 keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
76
+ <Name extends string, Path extends string | string[]>(
82
77
  name: Name,
83
78
  path: Path,
84
79
  state: number,
85
- ): Observable<Get<Data, Path> | undefined>
80
+ ): Observable<Get<Lookup[Name], Path>>
86
81
  }
87
82
 
88
83
  get: {
89
84
  // without path:
90
- <Name extends keyof Records, Data extends Records[Name]>(
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 keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
88
+ <Name extends string, Path extends string | string[]>(
97
89
  name: Name,
98
- path?: Path,
90
+ path: Path,
99
91
  state?: number,
100
- ): Promise<Get<Data, Path> | undefined>
92
+ ): Promise<Get<Lookup[Name], Path>>
101
93
  }
102
94
 
103
95
  observe2: {
104
96
  // without path:
105
- <Name extends keyof Records, Data extends Records[Name]>(
97
+ <Name extends string>(
106
98
  name: Name,
107
99
  ): Observable<{
108
- name: Name
100
+ name: string
109
101
  version: string
110
102
  state: number
111
- data: GettablePossibleEmpty<Data>
103
+ data: Lookup[Name]
112
104
  }>
113
105
 
114
106
  // with path:
115
- <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
107
+ <Name extends string, Path extends string | string[]>(
116
108
  name: Name,
117
109
  path: Path,
118
110
  ): Observable<{
119
- name: Name
111
+ name: string
120
112
  version: string
121
113
  state: number
122
- data: Get<Data, Path> | undefined
114
+ data: Get<Lookup[Name], Path>
123
115
  }>
124
116
 
125
117
  // with state:
126
- <Name extends keyof Records, Data extends Records[Name]>(
118
+ <Name extends string>(
127
119
  name: Name,
128
120
  state: number,
129
121
  ): Observable<{
130
- name: Name
122
+ name: string
131
123
  version: string
132
124
  state: number
133
- data: GettablePossibleEmpty<Data>
125
+ data: Lookup[Name]
134
126
  }>
135
127
 
136
128
  // with path and state:
137
- <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
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: Name
134
+ name: string
143
135
  version: string
144
136
  state: number
145
- data: Get<Data, Path> | undefined
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
+ }
@@ -215,7 +215,10 @@ class RecordHandler {
215
215
  */
216
216
  getRecord(name) {
217
217
  invariant(
218
- typeof name === 'string' && name.length > 0 && name !== '[object Object]',
218
+ typeof name === 'string' &&
219
+ name.length > 0 &&
220
+ name !== '[object Object]' &&
221
+ name.length <= 4096,
219
222
  `invalid name ${name}`,
220
223
  )
221
224
 
@@ -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: GettablePossibleEmpty<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
- <Path extends Paths<Data>, DataAtPath extends Get<Data, Path> = Get<Data, Path>>(
65
- path: Path,
66
- ): DataAtPath | undefined
60
+ <P extends string | string[]>(path: P): Get<Data, P>
67
61
  // without path
68
- (): GettablePossibleEmpty<Data>
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
- <Path extends Paths<Data>, DataAtPath extends Get<Data, Path>>(
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
- Path extends Paths<Data>,
98
- PathOrUpdater extends
99
- | Path
100
- | ((data: Readonly<GettablePossibleEmpty<Data>>) => SettablePossibleEmpty<Data>),
101
- >(
102
- ...args: PathOrUpdater extends Path
103
- ? [
104
- path: Path,
105
- updater: (dataAtPath: Readonly<Get<Data, Path>> | undefined) => Get<Data, Path>,
106
- options?: UpdateOptions,
107
- ]
108
- : [updater: PathOrUpdater, options?: UpdateOptions]
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
  }