@atproto/tap 0.1.3 → 0.2.0
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/CHANGELOG.md +17 -0
- package/LICENSE.txt +1 -1
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js +15 -10
- package/dist/channel.js.map +1 -1
- package/dist/lex-indexer.d.ts.map +1 -1
- package/dist/lex-indexer.js +8 -6
- package/dist/lex-indexer.js.map +1 -1
- package/dist/types.d.ts +107 -258
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +33 -30
- package/dist/types.js.map +1 -1
- package/package.json +8 -9
- package/src/channel.ts +17 -13
- package/src/lex-indexer.ts +14 -8
- package/src/types.ts +41 -37
- package/tests/_util.ts +24 -1
- package/tests/channel.test.ts +40 -48
- package/tests/client.test.ts +6 -5
- package/tests/lex-indexer.test.ts +4 -1
- package/tests/simple-indexer.test.ts +1 -0
- package/tests/util.test.ts +1 -0
- package/tsconfig.json +4 -1
- package/tsconfig.tests.json +9 -0
- package/vitest.config.ts +5 -0
- package/jest.config.js +0 -10
package/dist/types.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.repoInfoSchema = exports.parseTapEvent = exports.tapEventSchema = exports.identityEventSchema = exports.recordEventSchema = exports.identityEventDataSchema = exports.recordEventDataSchema = void 0;
|
|
4
|
-
const
|
|
5
|
-
exports.recordEventDataSchema =
|
|
6
|
-
did:
|
|
7
|
-
rev:
|
|
8
|
-
collection:
|
|
9
|
-
rkey:
|
|
10
|
-
action:
|
|
11
|
-
record:
|
|
12
|
-
cid:
|
|
13
|
-
live:
|
|
4
|
+
const lex_1 = require("@atproto/lex");
|
|
5
|
+
exports.recordEventDataSchema = lex_1.l.object({
|
|
6
|
+
did: lex_1.l.string({ format: 'did' }),
|
|
7
|
+
rev: lex_1.l.string(),
|
|
8
|
+
collection: lex_1.l.string({ format: 'nsid' }),
|
|
9
|
+
rkey: lex_1.l.string({ format: 'record-key' }),
|
|
10
|
+
action: lex_1.l.enum(['create', 'update', 'delete']),
|
|
11
|
+
record: lex_1.l.optional(lex_1.l.unknownObject()),
|
|
12
|
+
cid: lex_1.l.optional(lex_1.l.string({ format: 'cid' })),
|
|
13
|
+
live: lex_1.l.boolean(),
|
|
14
14
|
});
|
|
15
|
-
exports.identityEventDataSchema =
|
|
16
|
-
did:
|
|
17
|
-
handle:
|
|
18
|
-
is_active:
|
|
19
|
-
status:
|
|
15
|
+
exports.identityEventDataSchema = lex_1.l.object({
|
|
16
|
+
did: lex_1.l.string({ format: 'did' }),
|
|
17
|
+
handle: lex_1.l.string({ format: 'handle' }),
|
|
18
|
+
is_active: lex_1.l.boolean(),
|
|
19
|
+
status: lex_1.l.enum([
|
|
20
20
|
'active',
|
|
21
21
|
'takendown',
|
|
22
22
|
'suspended',
|
|
@@ -24,17 +24,20 @@ exports.identityEventDataSchema = zod_1.z.object({
|
|
|
24
24
|
'deleted',
|
|
25
25
|
]),
|
|
26
26
|
});
|
|
27
|
-
exports.recordEventSchema =
|
|
28
|
-
id:
|
|
29
|
-
type:
|
|
27
|
+
exports.recordEventSchema = lex_1.l.object({
|
|
28
|
+
id: lex_1.l.integer(),
|
|
29
|
+
type: lex_1.l.literal('record'),
|
|
30
30
|
record: exports.recordEventDataSchema,
|
|
31
31
|
});
|
|
32
|
-
exports.identityEventSchema =
|
|
33
|
-
id:
|
|
34
|
-
type:
|
|
32
|
+
exports.identityEventSchema = lex_1.l.object({
|
|
33
|
+
id: lex_1.l.integer(),
|
|
34
|
+
type: lex_1.l.literal('identity'),
|
|
35
35
|
identity: exports.identityEventDataSchema,
|
|
36
36
|
});
|
|
37
|
-
exports.tapEventSchema =
|
|
37
|
+
exports.tapEventSchema = lex_1.l.discriminatedUnion('type', [
|
|
38
|
+
exports.recordEventSchema,
|
|
39
|
+
exports.identityEventSchema,
|
|
40
|
+
]);
|
|
38
41
|
const parseTapEvent = (data) => {
|
|
39
42
|
const parsed = exports.tapEventSchema.parse(data);
|
|
40
43
|
if (parsed.type === 'identity') {
|
|
@@ -63,13 +66,13 @@ const parseTapEvent = (data) => {
|
|
|
63
66
|
}
|
|
64
67
|
};
|
|
65
68
|
exports.parseTapEvent = parseTapEvent;
|
|
66
|
-
exports.repoInfoSchema =
|
|
67
|
-
did:
|
|
68
|
-
handle:
|
|
69
|
-
state:
|
|
70
|
-
rev:
|
|
71
|
-
records:
|
|
72
|
-
error:
|
|
73
|
-
retries:
|
|
69
|
+
exports.repoInfoSchema = lex_1.l.object({
|
|
70
|
+
did: lex_1.l.string(),
|
|
71
|
+
handle: lex_1.l.string(),
|
|
72
|
+
state: lex_1.l.string(),
|
|
73
|
+
rev: lex_1.l.string(),
|
|
74
|
+
records: lex_1.l.integer(),
|
|
75
|
+
error: lex_1.l.optional(lex_1.l.string()),
|
|
76
|
+
retries: lex_1.l.optional(lex_1.l.integer()),
|
|
74
77
|
});
|
|
75
78
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["import { LexMap, LexValue, l } from '@atproto/lex'\nimport { DidString, HandleString, NsidString } from '@atproto/syntax'\n\nexport const recordEventDataSchema = l.object({\n did: l.string({ format: 'did' }),\n rev: l.string(),\n collection: l.string({ format: 'nsid' }),\n rkey: l.string({ format: 'record-key' }),\n action: l.enum(['create', 'update', 'delete']),\n record: l.optional(l.unknownObject()),\n cid: l.optional(l.string({ format: 'cid' })),\n live: l.boolean(),\n})\n\nexport const identityEventDataSchema = l.object({\n did: l.string({ format: 'did' }),\n handle: l.string({ format: 'handle' }),\n is_active: l.boolean(),\n status: l.enum([\n 'active',\n 'takendown',\n 'suspended',\n 'deactivated',\n 'deleted',\n ]),\n})\n\nexport const recordEventSchema = l.object({\n id: l.integer(),\n type: l.literal('record'),\n record: recordEventDataSchema,\n})\n\nexport const identityEventSchema = l.object({\n id: l.integer(),\n type: l.literal('identity'),\n identity: identityEventDataSchema,\n})\n\nexport const tapEventSchema = l.discriminatedUnion('type', [\n recordEventSchema,\n identityEventSchema,\n])\n\nexport type RecordEvent = {\n id: number\n type: 'record'\n action: 'create' | 'update' | 'delete'\n did: DidString\n rev: string\n collection: NsidString\n rkey: string\n record?: LexMap\n cid?: string\n live: boolean\n}\n\nexport type IdentityEvent = {\n id: number\n type: 'identity'\n did: DidString\n handle: HandleString\n isActive: boolean\n status: RepoStatus\n}\n\nexport type RepoStatus =\n | 'active'\n | 'takendown'\n | 'suspended'\n | 'deactivated'\n | 'deleted'\n\nexport type TapEvent = IdentityEvent | RecordEvent\n\nexport const parseTapEvent = (data: LexValue): TapEvent => {\n const parsed = tapEventSchema.parse(data)\n if (parsed.type === 'identity') {\n return {\n id: parsed.id,\n type: parsed.type,\n did: parsed.identity.did,\n handle: parsed.identity.handle,\n isActive: parsed.identity.is_active,\n status: parsed.identity.status,\n }\n } else {\n return {\n id: parsed.id,\n type: parsed.type,\n action: parsed.record.action,\n did: parsed.record.did,\n rev: parsed.record.rev,\n collection: parsed.record.collection,\n rkey: parsed.record.rkey,\n record: parsed.record.record,\n cid: parsed.record.cid,\n live: parsed.record.live,\n }\n }\n}\n\nexport const repoInfoSchema = l.object({\n did: l.string(),\n handle: l.string(),\n state: l.string(),\n rev: l.string(),\n records: l.integer(),\n error: l.optional(l.string()),\n retries: l.optional(l.integer()),\n})\n\nexport type RepoInfo = l.Infer<typeof repoInfoSchema>\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/tap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "atproto tap client",
|
|
6
6
|
"keywords": [
|
|
@@ -23,22 +23,21 @@
|
|
|
23
23
|
"types": "dist/index.d.ts",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"ws": "^8.12.0",
|
|
26
|
-
"
|
|
27
|
-
"@atproto/
|
|
28
|
-
"@atproto/
|
|
29
|
-
"@atproto/syntax": "^0.4.2",
|
|
26
|
+
"@atproto/common": "^0.5.9",
|
|
27
|
+
"@atproto/lex": "^0.0.12",
|
|
28
|
+
"@atproto/syntax": "^0.4.3",
|
|
30
29
|
"@atproto/ws-client": "^0.0.4"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
32
|
"@types/express": "^4.17.17",
|
|
34
33
|
"@types/ws": "^8.5.4",
|
|
35
34
|
"express": "^4.18.2",
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
35
|
+
"typescript": "^5.6.3",
|
|
36
|
+
"@vitest/coverage-v8": "4.0.16",
|
|
37
|
+
"vitest": "^4.0.16"
|
|
39
38
|
},
|
|
40
39
|
"scripts": {
|
|
41
40
|
"build": "tsc --build tsconfig.build.json",
|
|
42
|
-
"test": "
|
|
41
|
+
"test": "vitest run"
|
|
43
42
|
}
|
|
44
43
|
}
|
package/src/channel.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClientOptions } from 'ws'
|
|
2
2
|
import { Deferrable, createDeferrable } from '@atproto/common'
|
|
3
|
+
import { lexParse } from '@atproto/lex'
|
|
3
4
|
import { WebSocketKeepAlive } from '@atproto/ws-client'
|
|
4
5
|
import { TapEvent, parseTapEvent } from './types'
|
|
5
6
|
import { formatAdminAuthHeader, isCausedBySignal } from './util'
|
|
@@ -94,12 +95,12 @@ export class TapChannel implements AsyncDisposable {
|
|
|
94
95
|
await this.sendAck(ack.id)
|
|
95
96
|
ack.defer.resolve()
|
|
96
97
|
this.bufferedAcks = this.bufferedAcks.slice(1)
|
|
97
|
-
} catch (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}),
|
|
98
|
+
} catch (cause) {
|
|
99
|
+
const error = new Error(
|
|
100
|
+
`failed to send ack for event ${this.bufferedAcks[0]}`,
|
|
101
|
+
{ cause },
|
|
102
102
|
)
|
|
103
|
+
this.handler.onError(error)
|
|
103
104
|
return
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -123,10 +124,14 @@ export class TapChannel implements AsyncDisposable {
|
|
|
123
124
|
private async processWsEvent(chunk: Uint8Array) {
|
|
124
125
|
let evt: TapEvent
|
|
125
126
|
try {
|
|
126
|
-
const data = chunk.toString()
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
const data = lexParse(chunk.toString(), {
|
|
128
|
+
// Reject invalid CIDs and blobs
|
|
129
|
+
strict: true,
|
|
130
|
+
})
|
|
131
|
+
evt = parseTapEvent(data)
|
|
132
|
+
} catch (cause) {
|
|
133
|
+
const error = new Error(`Failed to parse message`, { cause })
|
|
134
|
+
this.handler.onError(error)
|
|
130
135
|
return
|
|
131
136
|
}
|
|
132
137
|
|
|
@@ -137,11 +142,10 @@ export class TapChannel implements AsyncDisposable {
|
|
|
137
142
|
await this.ackEvent(evt.id)
|
|
138
143
|
},
|
|
139
144
|
})
|
|
140
|
-
} catch (
|
|
145
|
+
} catch (cause) {
|
|
141
146
|
// Don't ack on error - let Tap retry
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
)
|
|
147
|
+
const error = new Error(`Failed to process event ${evt.id}`, { cause })
|
|
148
|
+
this.handler.onError(error)
|
|
145
149
|
return
|
|
146
150
|
}
|
|
147
151
|
}
|
package/src/lex-indexer.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Infer, Main, RecordSchema, getMain } from '@atproto/lex'
|
|
2
|
-
import {
|
|
2
|
+
import { AtUriString, NsidString } from '@atproto/syntax'
|
|
3
3
|
import { HandlerOpts, TapHandler } from './channel'
|
|
4
4
|
import { IdentityEvent, RecordEvent, TapEvent } from './types'
|
|
5
5
|
|
|
@@ -73,12 +73,15 @@ export class LexIndexer implements TapHandler {
|
|
|
73
73
|
private identityHandler: IdentityHandler | undefined
|
|
74
74
|
private errorHandler: ErrorHandler | undefined
|
|
75
75
|
|
|
76
|
-
private handlerKey(
|
|
76
|
+
private handlerKey(
|
|
77
|
+
collection: NsidString,
|
|
78
|
+
action: RecordEvent['action'],
|
|
79
|
+
): string {
|
|
77
80
|
return `${collection}:${action}`
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
private register<const T extends RecordSchema>(
|
|
81
|
-
action:
|
|
84
|
+
action: RecordEvent['action'],
|
|
82
85
|
ns: Main<T>,
|
|
83
86
|
handler: RecordHandler<Infer<T>>,
|
|
84
87
|
): this {
|
|
@@ -117,7 +120,8 @@ export class LexIndexer implements TapHandler {
|
|
|
117
120
|
handler: PutHandler<Infer<T>>,
|
|
118
121
|
): this {
|
|
119
122
|
this.register('create', ns, handler)
|
|
120
|
-
|
|
123
|
+
this.register('update', ns, handler)
|
|
124
|
+
return this
|
|
121
125
|
}
|
|
122
126
|
|
|
123
127
|
other(fn: UntypedHandler): this {
|
|
@@ -167,10 +171,12 @@ export class LexIndexer implements TapHandler {
|
|
|
167
171
|
}
|
|
168
172
|
|
|
169
173
|
if (action === 'create' || action === 'update') {
|
|
170
|
-
const match = registered.schema.
|
|
171
|
-
if (!match) {
|
|
172
|
-
const uriStr =
|
|
173
|
-
throw new Error(`Record validation failed for ${uriStr}
|
|
174
|
+
const match = registered.schema.safeValidate(evt.record)
|
|
175
|
+
if (!match.success) {
|
|
176
|
+
const uriStr: AtUriString = `at://${evt.did}/${evt.collection}/${evt.rkey}`
|
|
177
|
+
throw new Error(`Record validation failed for ${uriStr}`, {
|
|
178
|
+
cause: match.reason,
|
|
179
|
+
})
|
|
174
180
|
}
|
|
175
181
|
}
|
|
176
182
|
|
package/src/types.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LexMap, LexValue, l } from '@atproto/lex'
|
|
2
|
+
import { DidString, HandleString, NsidString } from '@atproto/syntax'
|
|
2
3
|
|
|
3
|
-
export const recordEventDataSchema =
|
|
4
|
-
did:
|
|
5
|
-
rev:
|
|
6
|
-
collection:
|
|
7
|
-
rkey:
|
|
8
|
-
action:
|
|
9
|
-
record:
|
|
10
|
-
cid:
|
|
11
|
-
live:
|
|
4
|
+
export const recordEventDataSchema = l.object({
|
|
5
|
+
did: l.string({ format: 'did' }),
|
|
6
|
+
rev: l.string(),
|
|
7
|
+
collection: l.string({ format: 'nsid' }),
|
|
8
|
+
rkey: l.string({ format: 'record-key' }),
|
|
9
|
+
action: l.enum(['create', 'update', 'delete']),
|
|
10
|
+
record: l.optional(l.unknownObject()),
|
|
11
|
+
cid: l.optional(l.string({ format: 'cid' })),
|
|
12
|
+
live: l.boolean(),
|
|
12
13
|
})
|
|
13
14
|
|
|
14
|
-
export const identityEventDataSchema =
|
|
15
|
-
did:
|
|
16
|
-
handle:
|
|
17
|
-
is_active:
|
|
18
|
-
status:
|
|
15
|
+
export const identityEventDataSchema = l.object({
|
|
16
|
+
did: l.string({ format: 'did' }),
|
|
17
|
+
handle: l.string({ format: 'handle' }),
|
|
18
|
+
is_active: l.boolean(),
|
|
19
|
+
status: l.enum([
|
|
19
20
|
'active',
|
|
20
21
|
'takendown',
|
|
21
22
|
'suspended',
|
|
@@ -24,29 +25,32 @@ export const identityEventDataSchema = z.object({
|
|
|
24
25
|
]),
|
|
25
26
|
})
|
|
26
27
|
|
|
27
|
-
export const recordEventSchema =
|
|
28
|
-
id:
|
|
29
|
-
type:
|
|
28
|
+
export const recordEventSchema = l.object({
|
|
29
|
+
id: l.integer(),
|
|
30
|
+
type: l.literal('record'),
|
|
30
31
|
record: recordEventDataSchema,
|
|
31
32
|
})
|
|
32
33
|
|
|
33
|
-
export const identityEventSchema =
|
|
34
|
-
id:
|
|
35
|
-
type:
|
|
34
|
+
export const identityEventSchema = l.object({
|
|
35
|
+
id: l.integer(),
|
|
36
|
+
type: l.literal('identity'),
|
|
36
37
|
identity: identityEventDataSchema,
|
|
37
38
|
})
|
|
38
39
|
|
|
39
|
-
export const tapEventSchema =
|
|
40
|
+
export const tapEventSchema = l.discriminatedUnion('type', [
|
|
41
|
+
recordEventSchema,
|
|
42
|
+
identityEventSchema,
|
|
43
|
+
])
|
|
40
44
|
|
|
41
45
|
export type RecordEvent = {
|
|
42
46
|
id: number
|
|
43
47
|
type: 'record'
|
|
44
48
|
action: 'create' | 'update' | 'delete'
|
|
45
|
-
did:
|
|
49
|
+
did: DidString
|
|
46
50
|
rev: string
|
|
47
|
-
collection:
|
|
51
|
+
collection: NsidString
|
|
48
52
|
rkey: string
|
|
49
|
-
record?:
|
|
53
|
+
record?: LexMap
|
|
50
54
|
cid?: string
|
|
51
55
|
live: boolean
|
|
52
56
|
}
|
|
@@ -54,8 +58,8 @@ export type RecordEvent = {
|
|
|
54
58
|
export type IdentityEvent = {
|
|
55
59
|
id: number
|
|
56
60
|
type: 'identity'
|
|
57
|
-
did:
|
|
58
|
-
handle:
|
|
61
|
+
did: DidString
|
|
62
|
+
handle: HandleString
|
|
59
63
|
isActive: boolean
|
|
60
64
|
status: RepoStatus
|
|
61
65
|
}
|
|
@@ -69,7 +73,7 @@ export type RepoStatus =
|
|
|
69
73
|
|
|
70
74
|
export type TapEvent = IdentityEvent | RecordEvent
|
|
71
75
|
|
|
72
|
-
export const parseTapEvent = (data:
|
|
76
|
+
export const parseTapEvent = (data: LexValue): TapEvent => {
|
|
73
77
|
const parsed = tapEventSchema.parse(data)
|
|
74
78
|
if (parsed.type === 'identity') {
|
|
75
79
|
return {
|
|
@@ -96,14 +100,14 @@ export const parseTapEvent = (data: unknown): TapEvent => {
|
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
102
|
|
|
99
|
-
export const repoInfoSchema =
|
|
100
|
-
did:
|
|
101
|
-
handle:
|
|
102
|
-
state:
|
|
103
|
-
rev:
|
|
104
|
-
records:
|
|
105
|
-
error:
|
|
106
|
-
retries:
|
|
103
|
+
export const repoInfoSchema = l.object({
|
|
104
|
+
did: l.string(),
|
|
105
|
+
handle: l.string(),
|
|
106
|
+
state: l.string(),
|
|
107
|
+
rev: l.string(),
|
|
108
|
+
records: l.integer(),
|
|
109
|
+
error: l.optional(l.string()),
|
|
110
|
+
retries: l.optional(l.integer()),
|
|
107
111
|
})
|
|
108
112
|
|
|
109
|
-
export type RepoInfo =
|
|
113
|
+
export type RepoInfo = l.Infer<typeof repoInfoSchema>
|
package/tests/_util.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WebSocketServer } from 'ws'
|
|
1
2
|
import { HandlerOpts } from '../src/channel'
|
|
2
3
|
import { IdentityEvent, RecordEvent } from '../src/types'
|
|
3
4
|
|
|
@@ -25,7 +26,7 @@ export const createRecordEvent = (
|
|
|
25
26
|
rkey: 'abc123',
|
|
26
27
|
action: 'create',
|
|
27
28
|
record: { text: 'hello' },
|
|
28
|
-
cid: '
|
|
29
|
+
cid: 'bafyreiclp443lavogvhj3d2ob2cxbfuscni2k5jk7bebjzg7khl3esabwq',
|
|
29
30
|
live: true,
|
|
30
31
|
...overrides,
|
|
31
32
|
})
|
|
@@ -38,3 +39,25 @@ export const createIdentityEvent = (): IdentityEvent => ({
|
|
|
38
39
|
isActive: true,
|
|
39
40
|
status: 'active',
|
|
40
41
|
})
|
|
42
|
+
|
|
43
|
+
export async function createWebSocketServer() {
|
|
44
|
+
return new Promise<WebSocketServer & AsyncDisposable>((resolve, reject) => {
|
|
45
|
+
const server = new WebSocketServer({ port: 0 }, () => {
|
|
46
|
+
server.off('error', reject)
|
|
47
|
+
resolve(
|
|
48
|
+
Object.defineProperty(server, Symbol.asyncDispose, {
|
|
49
|
+
value: disposeWebSocketServer,
|
|
50
|
+
}) as WebSocketServer & AsyncDisposable,
|
|
51
|
+
)
|
|
52
|
+
}).once('error', reject)
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function disposeWebSocketServer(this: WebSocketServer) {
|
|
57
|
+
return new Promise<void>((resolve, reject) => {
|
|
58
|
+
this.close((err) => {
|
|
59
|
+
if (err) reject(err)
|
|
60
|
+
else resolve()
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
}
|