@blackglory/estore-js 0.5.1 → 0.5.3
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/lib/utils/rpc-client.browser.d.ts +1 -3
- package/lib/utils/rpc-client.browser.js +1 -7
- package/lib/utils/rpc-client.browser.js.map +1 -1
- package/package.json +3 -2
- package/src/contract.ts +45 -0
- package/src/estore-client.ts +143 -0
- package/src/index.ts +1 -0
- package/src/utils/rpc-client.browser.ts +27 -0
- package/src/utils/rpc-client.ts +28 -0
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { IAPI } from "../contract.js";
|
|
2
|
-
import { ClientProxy
|
|
2
|
+
import { ClientProxy } from 'delight-rpc';
|
|
3
3
|
export declare function createRPCClient(url: string, retryIntervalForReconnection?: number): Promise<{
|
|
4
4
|
client: ClientProxy<IAPI>;
|
|
5
|
-
batchClient: BatchClient<IAPI>;
|
|
6
|
-
proxy: BatchClientProxy<IAPI, unknown>;
|
|
7
5
|
close: () => Promise<void>;
|
|
8
6
|
}>;
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
import { expectedVersion } from "../contract.js";
|
|
2
|
-
import {
|
|
3
|
-
import { createClient, createBatchClient } from '@delight-rpc/extra-native-websocket';
|
|
2
|
+
import { createClient } from '@delight-rpc/extra-native-websocket';
|
|
4
3
|
import { ExtraNativeWebSocket, autoReconnect } from 'extra-native-websocket';
|
|
5
4
|
export async function createRPCClient(url, retryIntervalForReconnection) {
|
|
6
5
|
const ws = new ExtraNativeWebSocket(() => new WebSocket(url));
|
|
7
6
|
const cancelAutoReconnect = autoReconnect(ws, retryIntervalForReconnection);
|
|
8
7
|
await ws.connect();
|
|
9
8
|
const [client, closeClient] = createClient(ws, { expectedVersion });
|
|
10
|
-
const [batchClient, closeBatchClient] = createBatchClient(ws, { expectedVersion });
|
|
11
|
-
const proxy = createBatchProxy();
|
|
12
9
|
return {
|
|
13
10
|
client,
|
|
14
|
-
batchClient,
|
|
15
|
-
proxy,
|
|
16
11
|
close: async () => {
|
|
17
12
|
closeClient();
|
|
18
|
-
closeBatchClient();
|
|
19
13
|
cancelAutoReconnect();
|
|
20
14
|
await ws.close();
|
|
21
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-client.browser.js","sourceRoot":"","sources":["../../src/utils/rpc-client.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,eAAe,EAAE,uBAAwB;
|
|
1
|
+
{"version":3,"file":"rpc-client.browser.js","sourceRoot":"","sources":["../../src/utils/rpc-client.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,eAAe,EAAE,uBAAwB;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AAClE,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAE5E,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAW,EACX,4BAAqC;IAKrC,MAAM,EAAE,GAAG,IAAI,oBAAoB,CAAC,GAAG,EAAE,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IAC7D,MAAM,mBAAmB,GAAG,aAAa,CAAC,EAAE,EAAE,4BAA4B,CAAC,CAAA;IAC3E,MAAM,EAAE,CAAC,OAAO,EAAE,CAAA;IAElB,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,YAAY,CAAO,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,CAAA;IAEzE,OAAO;QACL,MAAM;QACN,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,WAAW,EAAE,CAAA;YACb,mBAAmB,EAAE,CAAA;YACrB,MAAM,EAAE,CAAC,KAAK,EAAE,CAAA;QAClB,CAAC;KACF,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
package/src/contract.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CustomError } from '@blackglory/errors'
|
|
2
|
+
import { JSONValue } from 'justypes'
|
|
3
|
+
|
|
4
|
+
export const expectedVersion = '^0.4.0'
|
|
5
|
+
|
|
6
|
+
export interface INamespaceStats {
|
|
7
|
+
items: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface IAPI {
|
|
11
|
+
getAllNamespaces(): string[]
|
|
12
|
+
getAllItemIds(namespace: string): string[]
|
|
13
|
+
getAllEvents(namespace: string, itemId: string): JSONValue[]
|
|
14
|
+
|
|
15
|
+
getNamespaceStats(namespace: string): INamespaceStats
|
|
16
|
+
|
|
17
|
+
clearItemsByNamespace(namespace: string): null
|
|
18
|
+
|
|
19
|
+
removeItem(namespace: string, itemId: string): null
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 获得指定项目内包含的事件数量, 该值等同于下一个事件插入时的索引号.
|
|
23
|
+
* 对于不存在的项目, 它会返回0.
|
|
24
|
+
*/
|
|
25
|
+
getItemSize(namespace: string, itemId: string): number
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param nextEventIndex 如果指定, 则会在eventIndex不等于下一个index时抛出EventIndexConflict错误.
|
|
29
|
+
* @throws {EventIndexConflict}
|
|
30
|
+
*/
|
|
31
|
+
appendEvent(
|
|
32
|
+
namespace: string
|
|
33
|
+
, itemId: string
|
|
34
|
+
, event: JSONValue
|
|
35
|
+
, nextEventIndex?: number
|
|
36
|
+
): null
|
|
37
|
+
|
|
38
|
+
getEvent(
|
|
39
|
+
namespace: string
|
|
40
|
+
, itemId: string
|
|
41
|
+
, eventIndex: number
|
|
42
|
+
): JSONValue | null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class EventIndexConflict extends CustomError {}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createRPCClient } from '@utils/rpc-client.js'
|
|
2
|
+
import { ClientProxy } from 'delight-rpc'
|
|
3
|
+
import { IAPI, INamespaceStats } from './contract.js'
|
|
4
|
+
import { timeoutSignal, withAbortSignal } from 'extra-abort'
|
|
5
|
+
import { isUndefined, JSONValue } from '@blackglory/prelude'
|
|
6
|
+
export { INamespaceStats } from './contract.js'
|
|
7
|
+
export { EventIndexConflict } from './contract.js'
|
|
8
|
+
|
|
9
|
+
export interface IEStoreClientOptions {
|
|
10
|
+
server: string
|
|
11
|
+
timeout?: number
|
|
12
|
+
retryIntervalForReconnection?: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class EStoreClient {
|
|
16
|
+
static async create(options: IEStoreClientOptions): Promise<EStoreClient> {
|
|
17
|
+
const { client, close } = await createRPCClient(
|
|
18
|
+
options.server
|
|
19
|
+
, options.retryIntervalForReconnection
|
|
20
|
+
)
|
|
21
|
+
return new EStoreClient(client, close, options.timeout)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private constructor(
|
|
25
|
+
private client: ClientProxy<IAPI>
|
|
26
|
+
, private closeClients: () => Promise<void>
|
|
27
|
+
, private timeout?: number
|
|
28
|
+
) {}
|
|
29
|
+
|
|
30
|
+
async close(): Promise<void> {
|
|
31
|
+
await this.closeClients()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async getNamespaceStats(
|
|
35
|
+
namespace: string
|
|
36
|
+
, timeout?: number
|
|
37
|
+
): Promise<INamespaceStats> {
|
|
38
|
+
return await this.withTimeout(
|
|
39
|
+
() => this.client.getNamespaceStats(namespace)
|
|
40
|
+
, timeout ?? this.timeout
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async getAllNamespaces(timeout?: number): Promise<string[]> {
|
|
45
|
+
return await this.withTimeout(
|
|
46
|
+
() => this.client.getAllNamespaces()
|
|
47
|
+
, timeout ?? this.timeout
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async getAllItemIds(namespace: string, timeout?: number): Promise<string[]> {
|
|
52
|
+
return await this.withTimeout(
|
|
53
|
+
() => this.client.getAllItemIds(namespace)
|
|
54
|
+
, timeout ?? this.timeout
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async getAllEvents(
|
|
59
|
+
namespace: string
|
|
60
|
+
, itemId: string
|
|
61
|
+
, timeout?: number
|
|
62
|
+
): Promise<JSONValue[]> {
|
|
63
|
+
return await this.withTimeout(
|
|
64
|
+
() => this.client.getAllEvents(namespace, itemId)
|
|
65
|
+
, timeout ?? this.timeout
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async clearItemsByNamespace(namespace: string, timeout?: number): Promise<void> {
|
|
70
|
+
await this.withTimeout(
|
|
71
|
+
() => this.client.clearItemsByNamespace(namespace)
|
|
72
|
+
, timeout ?? this.timeout
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async removeItem(
|
|
77
|
+
namespace: string
|
|
78
|
+
, itemId: string
|
|
79
|
+
, timeout?: number
|
|
80
|
+
): Promise<void> {
|
|
81
|
+
await this.withTimeout(
|
|
82
|
+
() => this.client.removeItem(namespace, itemId)
|
|
83
|
+
, timeout ?? this.timeout
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async getItemSize(
|
|
88
|
+
namespace: string
|
|
89
|
+
, itemId: string
|
|
90
|
+
, timeout?: number
|
|
91
|
+
): Promise<number> {
|
|
92
|
+
return await this.withTimeout(
|
|
93
|
+
() => this.client.getItemSize(namespace, itemId)
|
|
94
|
+
, timeout ?? this.timeout
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @param nextEventIndex 如果指定, 则会在eventIndex不等于下一个index时抛出EventIndexConflict错误.
|
|
100
|
+
* @throws {EventIndexConflict}
|
|
101
|
+
*/
|
|
102
|
+
async appendEvent(
|
|
103
|
+
namespace: string
|
|
104
|
+
, itemId: string
|
|
105
|
+
, event: JSONValue
|
|
106
|
+
, nextEventIndex?: number
|
|
107
|
+
, timeout?: number
|
|
108
|
+
): Promise<void> {
|
|
109
|
+
await this.withTimeout(
|
|
110
|
+
() => {
|
|
111
|
+
if (isUndefined(nextEventIndex)) {
|
|
112
|
+
return this.client.appendEvent(namespace, itemId, event)
|
|
113
|
+
} else {
|
|
114
|
+
return this.client.appendEvent(namespace, itemId, event, nextEventIndex)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
, timeout ?? this.timeout
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async getEvent(
|
|
122
|
+
namespace: string
|
|
123
|
+
, itemId: string
|
|
124
|
+
, index: number
|
|
125
|
+
, timeout?: number
|
|
126
|
+
): Promise<JSONValue | null> {
|
|
127
|
+
return await this.withTimeout(
|
|
128
|
+
() => this.client.getEvent(namespace, itemId, index)
|
|
129
|
+
, timeout ?? this.timeout
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private async withTimeout<T>(
|
|
134
|
+
fn: () => PromiseLike<T>
|
|
135
|
+
, timeout: number | undefined = this.timeout
|
|
136
|
+
): Promise<T> {
|
|
137
|
+
if (timeout) {
|
|
138
|
+
return await withAbortSignal(timeoutSignal(timeout), fn)
|
|
139
|
+
} else {
|
|
140
|
+
return await fn()
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './estore-client.js'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { IAPI, expectedVersion } from '@src/contract.js'
|
|
2
|
+
import { ClientProxy } from 'delight-rpc'
|
|
3
|
+
import { createClient } from '@delight-rpc/extra-native-websocket'
|
|
4
|
+
import { ExtraNativeWebSocket, autoReconnect } from 'extra-native-websocket'
|
|
5
|
+
|
|
6
|
+
export async function createRPCClient(
|
|
7
|
+
url: string
|
|
8
|
+
, retryIntervalForReconnection?: number
|
|
9
|
+
): Promise<{
|
|
10
|
+
client: ClientProxy<IAPI>
|
|
11
|
+
close: () => Promise<void>
|
|
12
|
+
}> {
|
|
13
|
+
const ws = new ExtraNativeWebSocket(() => new WebSocket(url))
|
|
14
|
+
const cancelAutoReconnect = autoReconnect(ws, retryIntervalForReconnection)
|
|
15
|
+
await ws.connect()
|
|
16
|
+
|
|
17
|
+
const [client, closeClient] = createClient<IAPI>(ws, { expectedVersion })
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
client
|
|
21
|
+
, close: async () => {
|
|
22
|
+
closeClient()
|
|
23
|
+
cancelAutoReconnect()
|
|
24
|
+
await ws.close()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { IAPI, expectedVersion } from '@src/contract.js'
|
|
2
|
+
import { ClientProxy } from 'delight-rpc'
|
|
3
|
+
import { createClient } from '@delight-rpc/extra-websocket'
|
|
4
|
+
import { WebSocket } from 'ws'
|
|
5
|
+
import { ExtraWebSocket, autoReconnect } from 'extra-websocket'
|
|
6
|
+
|
|
7
|
+
export async function createRPCClient(
|
|
8
|
+
url: string
|
|
9
|
+
, retryIntervalForReconnection?: number
|
|
10
|
+
): Promise<{
|
|
11
|
+
client: ClientProxy<IAPI>
|
|
12
|
+
close: () => Promise<void>
|
|
13
|
+
}> {
|
|
14
|
+
const ws = new ExtraWebSocket(() => new WebSocket(url))
|
|
15
|
+
const cancelAutoReconnect = autoReconnect(ws, retryIntervalForReconnection)
|
|
16
|
+
await ws.connect()
|
|
17
|
+
|
|
18
|
+
const [client, closeClient] = createClient<IAPI>(ws, { expectedVersion })
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
client
|
|
22
|
+
, close: async () => {
|
|
23
|
+
closeClient()
|
|
24
|
+
cancelAutoReconnect()
|
|
25
|
+
await ws.close()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|