@nxtedition/deepstream.io-client-js 28.1.3 → 28.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/deepstream.io-client-js",
3
- "version": "28.1.3",
3
+ "version": "28.1.5",
4
4
  "description": "the javascript client for deepstream.io",
5
5
  "homepage": "http://deepstream.io",
6
6
  "type": "module",
@@ -14,6 +14,7 @@
14
14
  "license": "Apache-2.0",
15
15
  "author": "deepstreamHub GmbH",
16
16
  "main": "src/client.js",
17
+ "types": "src/client.d.ts",
17
18
  "browser": {
18
19
  "ws": false
19
20
  },
@@ -45,6 +46,7 @@
45
46
  "xxhash-wasm": "^1.0.2"
46
47
  },
47
48
  "devDependencies": {
49
+ "@types/node": "^22.10.3",
48
50
  "eslint": "^9.14.0",
49
51
  "eslint-config-prettier": "^9.1.0",
50
52
  "eslint-config-standard": "^17.1.0",
@@ -0,0 +1,104 @@
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'
5
+
6
+ export default function <Records, Methods>(
7
+ url: string,
8
+ options?: unknown,
9
+ ): DeepstreamClient<Records, Methods>
10
+
11
+ export type { Record, RecordHandler, EventHandler, RpcHandler }
12
+
13
+ type RecordStateConstants = Readonly<{
14
+ VOID: 0
15
+ CLIENT: 1
16
+ SERVER: 2
17
+ STALE: 3
18
+ PROVIDER: 4
19
+ }>
20
+
21
+ type ConnectionStateConstants = Readonly<{
22
+ CLOSED: 'CLOSED'
23
+ AWAITING_CONNECTION: 'AWAITING_CONNECTION'
24
+ CHALLENGING: 'CHALLENGING'
25
+ AWAITING_AUTHENTICATION: 'AWAITING_AUTHENTICATION'
26
+ AUTHENTICATING: 'AUTHENTICATING'
27
+ OPEN: 'OPEN'
28
+ ERROR: 'ERROR'
29
+ RECONNECTING: 'RECONNECTING'
30
+ }>
31
+ type ConnectionStateKey = keyof typeof ConnectionStateConstants
32
+ type ConnectionStateName = (typeof ConnectionStateConstants)[ConnectionStateKey]
33
+
34
+ type EventConstants = Readonly<{
35
+ CONNECTION_ERROR: 'connectionError'
36
+ CONNECTION_STATE_CHANGED: 'connectionStateChanged'
37
+ CONNECTED: 'connected'
38
+ MAX_RECONNECTION_ATTEMPTS_REACHED: 'MAX_RECONNECTION_ATTEMPTS_REACHED'
39
+ CONNECTION_AUTHENTICATION_TIMEOUT: 'CONNECTION_AUTHENTICATION_TIMEOUT'
40
+ NO_RPC_PROVIDER: 'NO_RPC_PROVIDER'
41
+ RPC_ERROR: 'RPC_ERROR'
42
+ TIMEOUT: 'TIMEOUT'
43
+ UNSOLICITED_MESSAGE: 'UNSOLICITED_MESSAGE'
44
+ MESSAGE_DENIED: 'MESSAGE_DENIED'
45
+ NOT_CONNECTED: 'NOT_CONNECTED'
46
+ MESSAGE_PARSE_ERROR: 'MESSAGE_PARSE_ERROR'
47
+ NOT_AUTHENTICATED: 'NOT_AUTHENTICATED'
48
+ MESSAGE_PERMISSION_ERROR: 'MESSAGE_PERMISSION_ERROR'
49
+ LISTENER_EXISTS: 'LISTENER_EXISTS'
50
+ PROVIDER_ERROR: 'PROVIDER_ERROR'
51
+ CACHE_ERROR: 'CACHE_ERROR'
52
+ UPDATE_ERROR: 'UPDATE_ERROR'
53
+ USER_ERROR: 'USER_ERROR'
54
+ REF_ERROR: 'REF_ERROR'
55
+ PROVIDER_EXISTS: 'PROVIDER_EXISTS'
56
+ NOT_LISTENING: 'NOT_LISTENING'
57
+ NOT_PROVIDING: 'NOT_PROVIDING'
58
+ LISTENER_ERROR: 'LISTENER_ERROR'
59
+ TOO_MANY_AUTH_ATTEMPTS: 'TOO_MANY_AUTH_ATTEMPTS'
60
+ IS_CLOSED: 'IS_CLOSED'
61
+ RECORD_NOT_FOUND: 'RECORD_NOT_FOUND'
62
+ NOT_SUBSCRIBED: 'NOT_SUBSCRIBED'
63
+ }>
64
+ type EventKey = keyof typeof EventConstants
65
+ type EventName = (typeof EventConstants)[EventKey]
66
+
67
+ export interface DeepstreamClient<
68
+ Records = Record<string, unknown>,
69
+ Methods = Record<string, RpcMethodDef>,
70
+ > {
71
+ nuid: () => string
72
+ event: EventHandler
73
+ rpc: RpcHandler<Methods>
74
+ record: RecordHandler<Records>
75
+ user: string | null
76
+ on: (evt: EventName, callback: (...args: unknown[]) => void) => void
77
+ off: (evt: EventName, callback: (...args: unknown[]) => void) => void
78
+ getConnectionState: () => ConnectionStateName
79
+ close: () => void
80
+ login: unknown
81
+ stats: {
82
+ record: RecordStats
83
+ rpc: RpcStats
84
+ event: EventStats
85
+ }
86
+
87
+ isSameOrNewer(a: string, b: string): boolean
88
+
89
+ CONSTANTS: {
90
+ CONNECTION_STATE: ConnectionStateConstants
91
+ RECORD_STATE: RecordStateConstants
92
+ EVENT: EventConstants
93
+ }
94
+ }
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,20 @@
1
+ import { Observable } from 'rxjs'
2
+
3
+ export default class EventHandler {
4
+ connected: boolean
5
+ stats: EventStats
6
+ subscribe: (name: string, callback: () => void) => void
7
+ unsubscribe: (name: string, callback: () => void) => void
8
+ on: (name: string, callback: () => void) => this
9
+ once: (name: string, callback: () => void) => this
10
+ off: (name: string, callback: () => void) => this
11
+ observe: <Data>(name: string) => Observable<Data>
12
+ emit: <Data>(name: string, data: Data) => void
13
+ provide: (pattern: string, callback: (name: string) => void, options: unknown) => () => void
14
+ }
15
+
16
+ export interface EventStats {
17
+ emitted: number
18
+ listeners: number
19
+ events: number
20
+ }
@@ -0,0 +1,157 @@
1
+ import type { Observable } from 'rxjs'
2
+ import Record from './record.js'
3
+
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> {
8
+ VOID: 0
9
+ CLIENT: 1
10
+ SERVER: 2
11
+ STALE: 3
12
+ PROVIDER: 4
13
+
14
+ JSON: {
15
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
16
+ EMPTY: Readonly<{}>
17
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
18
+ EMPTY_OBJ: Readonly<{}>
19
+ EMPTY_ARR: Readonly<unknown[]>
20
+ }
21
+
22
+ connected: boolean
23
+ stats: RecordStats
24
+ getRecord: <Name extends keyof Records, Data extends Records[Name] = Records[Name]>(
25
+ name: Name,
26
+ ) => Record<Data>
27
+
28
+ provide: <Data>(
29
+ pattern: string,
30
+ callback: (key: string) => Data,
31
+ optionsOrRecursive?: ProvideOptions | boolean,
32
+ ) => void | (() => void)
33
+
34
+ sync: (options?: SyncOptions) => Promise<void>
35
+
36
+ set: {
37
+ // without path:
38
+ <Name extends keyof Records>(name: Name, data: Records[Name]): void
39
+
40
+ // with path:
41
+ <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data>>(
42
+ name: Name,
43
+ path: Path,
44
+ data: Get<Data, Path>,
45
+ ): void
46
+ }
47
+
48
+ update: {
49
+ // without path:
50
+ <Name extends keyof Records, Data extends Records[Name]>(
51
+ name: Name,
52
+ updater: (data: Data) => Data,
53
+ ): Promise<void>
54
+
55
+ // with path:
56
+ <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data>>(
57
+ name: Name,
58
+ path: Path,
59
+ updater: (data: Get<Data, Path>) => Get<Data, Path>,
60
+ ): Promise<void>
61
+ }
62
+
63
+ observe: {
64
+ // without path:
65
+ <Name extends keyof Records, Data extends Records[Name]>(name: Name): Observable<Data>
66
+
67
+ // with path:
68
+ <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
69
+ name: Name,
70
+ path: Path,
71
+ ): Observable<Get<Data, Path>>
72
+
73
+ // with state:
74
+ <Name extends keyof Records, Data extends Records[Name]>(
75
+ name: Name,
76
+ state: number,
77
+ ): Observable<Data>
78
+
79
+ // with path and state:
80
+ <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
81
+ name: Name,
82
+ path: Path,
83
+ state: number,
84
+ ): Observable<Get<Data, Path>>
85
+ }
86
+
87
+ get: {
88
+ // without path:
89
+ <Name extends keyof Records, Data extends Records[Name]>(
90
+ name: Name,
91
+ state?: number,
92
+ ): Promise<Data>
93
+
94
+ // with path:
95
+ <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
96
+ name: Name,
97
+ path?: Path,
98
+ state?: number,
99
+ ): Promise<Get<Data, Path>>
100
+ }
101
+
102
+ observe2: {
103
+ // without path:
104
+ <Name extends keyof Records, Data extends Records[Name]>(
105
+ name: Name,
106
+ ): Observable<{
107
+ name: Name
108
+ version: string
109
+ state: number
110
+ data: Data
111
+ }>
112
+
113
+ // with path:
114
+ <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
115
+ name: Name,
116
+ path: Path,
117
+ ): Observable<{
118
+ name: Name
119
+ version: Get<Data, Path>
120
+ state: number
121
+ data: Data
122
+ }>
123
+
124
+ // with state:
125
+ <Name extends keyof Records, Data extends Records[Name]>(
126
+ name: Name,
127
+ state: number,
128
+ ): Observable<{
129
+ name: Name
130
+ version: Get<Data, Path>
131
+ state: number
132
+ data: Data
133
+ }>
134
+
135
+ // with path and state:
136
+ <Name extends keyof Records, Data extends Records[Name], Path extends Paths<Data> & string>(
137
+ name: Name,
138
+ path: Path,
139
+ state: number,
140
+ ): Observable<{
141
+ name: Name
142
+ version: Get<Data, Path>
143
+ state: number
144
+ data: Get<Data, Path>
145
+ }>
146
+ }
147
+ }
148
+
149
+ export interface RecordStats {
150
+ updating: number
151
+ created: number
152
+ destroyed: number
153
+ records: number
154
+ pruning: number
155
+ patching: number
156
+ subscriptions: number
157
+ }
@@ -0,0 +1,73 @@
1
+ import RecordHandler from './record-handler.js'
2
+
3
+ type Paths<T> = keyof T
4
+ type Get<Data, Path extends string> = Path extends keyof Data ? Data[Path] : unknown
5
+
6
+ export interface WhenOptions {
7
+ state?: number
8
+ timeout?: number
9
+ signal?: AbortSignal
10
+ }
11
+
12
+ export interface UpdateOptions {
13
+ signal?: AbortSignal
14
+ }
15
+
16
+ export default class Record<Data> {
17
+ constructor(name: string, handler: RecordHandler)
18
+
19
+ readonly name: string
20
+ readonly version: string
21
+ readonly data: Data
22
+ readonly state: number
23
+ readonly refs: number
24
+
25
+ ref(): Record<Data>
26
+ unref(): Record<Data>
27
+ subscribe(callback: (record: Record<Data>) => void, opaque?: unknown): Record<Data>
28
+ unsubscribe(callback: (record: Record<Data>) => void, opaque?: unknown): Record<Data>
29
+
30
+ get: {
31
+ // with path
32
+ <Path extends Paths<Data>, DataAtPath extends Get<Data, Path> = Get<Data, Path>>(
33
+ path: Path,
34
+ ): DataAtPath
35
+ // without path
36
+ (): Data
37
+ // implementation
38
+ <Path extends Paths<Data>, DataAtPath extends Get<Data, Path> = Get<Data, Path>>(
39
+ path?: Path,
40
+ ): Path extends undefined ? Data : DataAtPath
41
+ }
42
+
43
+ set: {
44
+ // with path
45
+ <Path extends Paths<Data>, DataAtPath extends Get<Data, Path>>(
46
+ path: Path,
47
+ dataAtPath: DataAtPath,
48
+ ): void
49
+ // without path
50
+ (data: Data): void
51
+ // implementation
52
+ <Path extends Paths<Data>, DataAtPath extends Get<Data, Path>>(
53
+ ...args: [pathOrData: Path | Data, value?: DataAtPath]
54
+ ): void
55
+ }
56
+
57
+ when: {
58
+ (): Promise<Record<Data>>
59
+ (state: number): Promise<Record<Data>>
60
+ (options: WhenOptions): Promise<Record<Data>>
61
+ (state: number, options: WhenOptions): Promise<Record<Data>>
62
+ }
63
+
64
+ update<Path extends Paths<Data>, PathOrUpdater extends Path | ((data: Data) => Data)>(
65
+ ...args: PathOrUpdater extends Path
66
+ ? [
67
+ path: Path,
68
+ updater: (dataAtPath: Get<Data, Path>) => Get<Data, Path>,
69
+ options?: UpdateOptions,
70
+ ]
71
+ : [updater: PathOrUpdater, options?: UpdateOptions]
72
+ ): Promise<void>
73
+ }
@@ -0,0 +1,31 @@
1
+ import RpcResponse from './rpc-response.js'
2
+
3
+ export type RpcMethodDef = [arguments: unknown, response: unknown]
4
+
5
+ export default class RpcHandler<Methods extends Record<string, RpcMethodDef>> {
6
+ connected: boolean
7
+ stats: RpcStats
8
+
9
+ provide: <Name extends keyof Methods>(
10
+ name: Name,
11
+ callback: (args: Methods[Name][0], response: RpcResponse<Methods[Name][1]>) => void,
12
+ ) => UnprovideFn
13
+
14
+ unprovide: <Name extends keyof Methods>(name: Name) => void
15
+
16
+ make: {
17
+ <Name extends keyof Methods>(
18
+ name: Name,
19
+ args: Methods[Name][0],
20
+ callback: (error: unknown, response: Methods[Name][1]) => void,
21
+ ): void
22
+ <Name extends keyof Methods>(name: Name, args: Methods[Name][0]): Promise<Methods[Name][1]>
23
+ }
24
+ }
25
+
26
+ type UnprovideFn = () => void
27
+
28
+ export interface RpcStats {
29
+ listeners: number
30
+ rpcs: number
31
+ }
@@ -0,0 +1,5 @@
1
+ export default class RpcResponse<Data> {
2
+ reject: () => void
3
+ error: (error: Error | string) => void
4
+ send: (data: Data) => void
5
+ }
package/src/test.ts ADDED
@@ -0,0 +1,78 @@
1
+ import make from './client.js'
2
+
3
+ interface Records {
4
+ test: {
5
+ name: string
6
+ age: number
7
+ }
8
+ foo: {
9
+ bar: number
10
+ }
11
+ num: number
12
+ str: string
13
+ }
14
+
15
+ interface Methods {
16
+ test: [{ name: string }, { age: number }]
17
+ }
18
+
19
+ const ds = make<Records, Methods>('http://localhost:3000')
20
+
21
+ ds.record.provide('test', () => {})
22
+
23
+ ds.record.set('test', {
24
+ name: 23,
25
+ })
26
+
27
+ ds.record.set('foo', { value: 'namn' })
28
+
29
+ ds.record.set('test', 'name', '23')
30
+
31
+ ds.record.provide('test', () => {
32
+ return {
33
+ name: 23,
34
+ }
35
+ })
36
+
37
+ ds.record.update('test', 'name', (name) => {
38
+ return name
39
+ })
40
+
41
+ const r = ds.record.getRecord('test')
42
+ //const name = r.get('bar')
43
+
44
+ r.update('name', (name) => name + 'a2', { signal: new AbortSignal() })
45
+
46
+ r.update((name) => ({ name: 'hej', age: 22 }))
47
+
48
+ r.update('age', (age) => age + 1, { signal: new AbortSignal() })
49
+
50
+ r.set({ age: 23, name: 'test' })
51
+ r.set({ age: '23', name: 'test' })
52
+
53
+ r.set('name', 22)
54
+ r.set('name', 'name')
55
+ r.set('age', true)
56
+ r.set('age', 22)
57
+
58
+ const a1 = r.get()
59
+ const a2 = r.get('age')
60
+ const a3 = r.get('name')
61
+ const a4 = r.get('what')
62
+
63
+ const name = r.get('age')
64
+
65
+ const s = Object.freeze({})
66
+
67
+ ds.record.JSON.EMPTY
68
+
69
+ ds.event.provide('test', (what) => {
70
+ }, {})
71
+
72
+ const a = ds.rpc.provide('test', (args, response) => {
73
+ console.log(args.name)
74
+ response.send({ age: 22 })
75
+ })
76
+
77
+ a()
78
+
@@ -84,11 +84,11 @@ export default class Listener {
84
84
  },
85
85
  })
86
86
 
87
+ this._subscriptions.set(name, subscription)
88
+
87
89
  subscription.add(() => {
88
90
  this._subscriptions.delete(name)
89
91
  })
90
-
91
- this._subscriptions.set(name, subscription)
92
92
  } else {
93
93
  this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, name])
94
94
  }