@atproto/xrpc-server 0.10.20 → 0.11.0-next.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 +36 -0
- package/dist/auth.js +25 -65
- package/dist/auth.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +59 -85
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -28
- package/dist/index.js.map +1 -1
- package/dist/logger.js +4 -7
- package/dist/logger.js.map +1 -1
- package/dist/rate-limiter.d.ts +1 -1
- package/dist/rate-limiter.d.ts.map +1 -1
- package/dist/rate-limiter.js +27 -91
- package/dist/rate-limiter.js.map +1 -1
- package/dist/server.d.ts +4 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +94 -178
- package/dist/server.js.map +1 -1
- package/dist/stream/frames.d.ts +1 -1
- package/dist/stream/frames.d.ts.map +1 -1
- package/dist/stream/frames.js +20 -50
- package/dist/stream/frames.js.map +1 -1
- package/dist/stream/index.d.ts +5 -5
- package/dist/stream/index.d.ts.map +1 -1
- package/dist/stream/index.js +5 -21
- package/dist/stream/index.js.map +1 -1
- package/dist/stream/logger.js +3 -6
- package/dist/stream/logger.js.map +1 -1
- package/dist/stream/server.d.ts +3 -2
- package/dist/stream/server.d.ts.map +1 -1
- package/dist/stream/server.js +12 -22
- package/dist/stream/server.js.map +1 -1
- package/dist/stream/stream.d.ts +2 -2
- package/dist/stream/stream.d.ts.map +1 -1
- package/dist/stream/stream.js +12 -18
- package/dist/stream/stream.js.map +1 -1
- package/dist/stream/subscription.d.ts +1 -1
- package/dist/stream/subscription.d.ts.map +1 -1
- package/dist/stream/subscription.js +9 -18
- package/dist/stream/subscription.js.map +1 -1
- package/dist/stream/types.js +12 -15
- package/dist/stream/types.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +22 -29
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +2 -2
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +75 -116
- package/dist/util.js.map +1 -1
- package/{jest.config.js → jest.config.cjs} +8 -2
- package/package.json +28 -22
- package/src/auth.ts +1 -1
- package/src/errors.ts +4 -1
- package/src/index.ts +8 -8
- package/src/rate-limiter.ts +2 -2
- package/src/server.ts +11 -6
- package/src/stream/frames.ts +2 -2
- package/src/stream/index.ts +5 -5
- package/src/stream/server.ts +4 -3
- package/src/stream/stream.ts +1 -1
- package/src/stream/subscription.ts +2 -2
- package/src/types.ts +2 -2
- package/src/util.ts +6 -3
- package/tests/_util.ts +1 -1
- package/tests/auth.test.ts +6 -3
- package/tests/bodies.test.ts +4 -3
- package/tests/errors.test.ts +2 -2
- package/tests/frames.test.ts +1 -1
- package/tests/ipld.test.ts +2 -2
- package/tests/parameters.test.ts +2 -2
- package/tests/parsing.test.ts +1 -1
- package/tests/procedures.test.ts +2 -2
- package/tests/queries.test.ts +2 -2
- package/tests/rate-limiter.test.ts +3 -3
- package/tests/responses.test.ts +2 -2
- package/tests/stream.test.ts +1 -1
- package/tests/subscriptions.test.ts +11 -5
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.tests.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../src/stream/frames.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAiB,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,kBAAkB,EAGnB,MAAM,
|
|
1
|
+
{"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../src/stream/frames.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAiB,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,kBAAkB,EAGnB,MAAM,YAAY,CAAA;AAEnB,8BAAsB,KAAK,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ;IACvD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAEhB,IAAI,EAAE,IAAI,SAAS,CAElB;IACD,OAAO,IAAI,UAAU;IAGrB,SAAS,IAAI,IAAI,IAAI,YAAY;IAGjC,OAAO,IAAI,IAAI,IAAI,UAAU;IAG7B,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU;CA8BnC;AAED,qBAAa,YAAY,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,KAAK,CAAC,CAAC,CAAC;IACvE,MAAM,EAAE,kBAAkB,CAAA;IAC1B,IAAI,EAAE,CAAC,CAAA;gBAEK,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;IAQ7C,IAAI,IAAI,uBAEP;IAED,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM;;;CAsBjD;AAED,qBAAa,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,KAAK,CAC9D,cAAc,CAAC,CAAC,CAAC,CAClB;IACC,MAAM,EAAE,gBAAgB,CAAA;IACxB,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;gBAEX,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;IAKnC,IAAI,IAAI,MAEP;IACD,IAAI,OAAO,uBAEV;IAED,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU;CAK3C"}
|
package/dist/stream/frames.js
CHANGED
|
@@ -1,43 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const errors_1 = require("../errors");
|
|
7
|
-
const types_1 = require("./types");
|
|
8
|
-
class Frame {
|
|
1
|
+
import { decodeAll, encode } from '@atproto/lex-cbor';
|
|
2
|
+
import { isPlainObject } from '@atproto/lex-data';
|
|
3
|
+
import { XRPCError } from '../errors.js';
|
|
4
|
+
import { FrameType, errorFrameBody, frameHeader, } from './types.js';
|
|
5
|
+
export class Frame {
|
|
9
6
|
get op() {
|
|
10
7
|
return this.header.op;
|
|
11
8
|
}
|
|
12
9
|
toBytes() {
|
|
13
|
-
return Buffer.concat([
|
|
10
|
+
return Buffer.concat([encode(this.header), encode(this.body)]);
|
|
14
11
|
}
|
|
15
12
|
isMessage() {
|
|
16
|
-
return this.op ===
|
|
13
|
+
return this.op === FrameType.Message;
|
|
17
14
|
}
|
|
18
15
|
isError() {
|
|
19
|
-
return this.op ===
|
|
16
|
+
return this.op === FrameType.Error;
|
|
20
17
|
}
|
|
21
18
|
static fromBytes(bytes) {
|
|
22
|
-
const [header, body, ...rest] =
|
|
19
|
+
const [header, body, ...rest] = decodeAll(bytes);
|
|
23
20
|
if (rest.length) {
|
|
24
21
|
throw new Error('Too many CBOR data items in frame');
|
|
25
22
|
}
|
|
26
23
|
else if (body === undefined) {
|
|
27
24
|
throw new Error('Missing frame body');
|
|
28
25
|
}
|
|
29
|
-
const parsedHeader =
|
|
26
|
+
const parsedHeader = frameHeader.safeParse(header);
|
|
30
27
|
if (!parsedHeader.success) {
|
|
31
28
|
throw new Error(`Invalid frame header: ${parsedHeader.reason.message}`);
|
|
32
29
|
}
|
|
33
30
|
const frameOp = parsedHeader.value.op;
|
|
34
|
-
if (frameOp ===
|
|
31
|
+
if (frameOp === FrameType.Message) {
|
|
35
32
|
return new MessageFrame(body, {
|
|
36
33
|
type: parsedHeader.value.t,
|
|
37
34
|
});
|
|
38
35
|
}
|
|
39
|
-
else if (frameOp ===
|
|
40
|
-
const parsedBody =
|
|
36
|
+
else if (frameOp === FrameType.Error) {
|
|
37
|
+
const parsedBody = errorFrameBody.safeParse(body);
|
|
41
38
|
if (!parsedBody.success) {
|
|
42
39
|
throw new Error(`Invalid error frame body: ${parsedBody.reason.message}`);
|
|
43
40
|
}
|
|
@@ -49,33 +46,20 @@ class Frame {
|
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
|
-
|
|
53
|
-
class MessageFrame extends Frame {
|
|
49
|
+
export class MessageFrame extends Frame {
|
|
54
50
|
constructor(body, opts) {
|
|
55
51
|
super();
|
|
56
|
-
Object.defineProperty(this, "header", {
|
|
57
|
-
enumerable: true,
|
|
58
|
-
configurable: true,
|
|
59
|
-
writable: true,
|
|
60
|
-
value: void 0
|
|
61
|
-
});
|
|
62
|
-
Object.defineProperty(this, "body", {
|
|
63
|
-
enumerable: true,
|
|
64
|
-
configurable: true,
|
|
65
|
-
writable: true,
|
|
66
|
-
value: void 0
|
|
67
|
-
});
|
|
68
52
|
this.header =
|
|
69
53
|
opts?.type !== undefined
|
|
70
|
-
? { op:
|
|
71
|
-
: { op:
|
|
54
|
+
? { op: FrameType.Message, t: opts?.type }
|
|
55
|
+
: { op: FrameType.Message };
|
|
72
56
|
this.body = body;
|
|
73
57
|
}
|
|
74
58
|
get type() {
|
|
75
59
|
return this.header.t;
|
|
76
60
|
}
|
|
77
61
|
static fromLexValue(data, nsid) {
|
|
78
|
-
if (!
|
|
62
|
+
if (!isPlainObject(data)) {
|
|
79
63
|
return new MessageFrame(data);
|
|
80
64
|
}
|
|
81
65
|
const $type = data?.['$type'];
|
|
@@ -94,23 +78,10 @@ class MessageFrame extends Frame {
|
|
|
94
78
|
return new MessageFrame(clone, { type });
|
|
95
79
|
}
|
|
96
80
|
}
|
|
97
|
-
|
|
98
|
-
class ErrorFrame extends Frame {
|
|
81
|
+
export class ErrorFrame extends Frame {
|
|
99
82
|
constructor(body) {
|
|
100
83
|
super();
|
|
101
|
-
|
|
102
|
-
enumerable: true,
|
|
103
|
-
configurable: true,
|
|
104
|
-
writable: true,
|
|
105
|
-
value: void 0
|
|
106
|
-
});
|
|
107
|
-
Object.defineProperty(this, "body", {
|
|
108
|
-
enumerable: true,
|
|
109
|
-
configurable: true,
|
|
110
|
-
writable: true,
|
|
111
|
-
value: void 0
|
|
112
|
-
});
|
|
113
|
-
this.header = { op: types_1.FrameType.Error };
|
|
84
|
+
this.header = { op: FrameType.Error };
|
|
114
85
|
this.body = body;
|
|
115
86
|
}
|
|
116
87
|
get code() {
|
|
@@ -122,9 +93,8 @@ class ErrorFrame extends Frame {
|
|
|
122
93
|
static fromError(err) {
|
|
123
94
|
if (err instanceof ErrorFrame)
|
|
124
95
|
return err;
|
|
125
|
-
const { error = 'Unknown', message } =
|
|
96
|
+
const { error = 'Unknown', message } = XRPCError.fromError(err).payload;
|
|
126
97
|
return new ErrorFrame({ error, message });
|
|
127
98
|
}
|
|
128
99
|
}
|
|
129
|
-
exports.ErrorFrame = ErrorFrame;
|
|
130
100
|
//# sourceMappingURL=frames.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../../src/stream/frames.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../../src/stream/frames.ts"],"names":[],"mappings":"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","sourcesContent":["import { decodeAll, encode } from '@atproto/lex-cbor'\nimport { LexValue, isPlainObject } from '@atproto/lex-data'\nimport { XRPCError } from '../errors.js'\nimport {\n ErrorFrameBody,\n ErrorFrameHeader,\n FrameHeader,\n FrameType,\n MessageFrameHeader,\n errorFrameBody,\n frameHeader,\n} from './types.js'\n\nexport abstract class Frame<T extends LexValue = LexValue> {\n abstract header: FrameHeader\n abstract body: T\n\n get op(): FrameType {\n return this.header.op\n }\n toBytes(): Uint8Array {\n return Buffer.concat([encode(this.header), encode(this.body)])\n }\n isMessage(): this is MessageFrame {\n return this.op === FrameType.Message\n }\n isError(): this is ErrorFrame {\n return this.op === FrameType.Error\n }\n static fromBytes(bytes: Uint8Array) {\n const [header, body, ...rest] = decodeAll(bytes)\n if (rest.length) {\n throw new Error('Too many CBOR data items in frame')\n } else if (body === undefined) {\n throw new Error('Missing frame body')\n }\n\n const parsedHeader = frameHeader.safeParse(header)\n if (!parsedHeader.success) {\n throw new Error(`Invalid frame header: ${parsedHeader.reason.message}`)\n }\n const frameOp = parsedHeader.value.op\n if (frameOp === FrameType.Message) {\n return new MessageFrame(body, {\n type: parsedHeader.value.t,\n })\n } else if (frameOp === FrameType.Error) {\n const parsedBody = errorFrameBody.safeParse(body)\n if (!parsedBody.success) {\n throw new Error(\n `Invalid error frame body: ${parsedBody.reason.message}`,\n )\n }\n return new ErrorFrame(parsedBody.value)\n } else {\n const exhaustiveCheck: never = frameOp\n throw new Error(`Unknown frame op: ${exhaustiveCheck}`)\n }\n }\n}\n\nexport class MessageFrame<T extends LexValue = LexValue> extends Frame<T> {\n header: MessageFrameHeader\n body: T\n\n constructor(body: T, opts?: { type?: string }) {\n super()\n this.header =\n opts?.type !== undefined\n ? { op: FrameType.Message, t: opts?.type }\n : { op: FrameType.Message }\n this.body = body\n }\n get type() {\n return this.header.t\n }\n\n static fromLexValue(data: LexValue, nsid: string) {\n if (!isPlainObject(data)) {\n return new MessageFrame(data)\n }\n\n const $type = data?.['$type']\n if (typeof $type !== 'string') {\n return new MessageFrame(data)\n }\n\n let type: string\n\n const split = $type.split('#')\n if (split.length === 2 && (split[0] === '' || split[0] === nsid)) {\n type = `#${split[1]}`\n } else {\n type = $type\n }\n\n const { $type: _, ...clone } = data\n return new MessageFrame(clone, { type })\n }\n}\n\nexport class ErrorFrame<T extends string = string> extends Frame<\n ErrorFrameBody<T>\n> {\n header: ErrorFrameHeader\n body: ErrorFrameBody<T>\n\n constructor(body: ErrorFrameBody<T>) {\n super()\n this.header = { op: FrameType.Error }\n this.body = body\n }\n get code() {\n return this.body.error\n }\n get message() {\n return this.body.message\n }\n\n static fromError(err: unknown): ErrorFrame {\n if (err instanceof ErrorFrame) return err\n const { error = 'Unknown', message } = XRPCError.fromError(err).payload\n return new ErrorFrame({ error, message })\n }\n}\n"]}
|
package/dist/stream/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export * from './types';
|
|
2
|
-
export * from './frames';
|
|
3
|
-
export * from './stream';
|
|
4
|
-
export * from './subscription';
|
|
5
|
-
export * from './server';
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './frames.js';
|
|
3
|
+
export * from './stream.js';
|
|
4
|
+
export * from './subscription.js';
|
|
5
|
+
export * from './server.js';
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stream/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stream/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA"}
|
package/dist/stream/index.js
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./types"), exports);
|
|
18
|
-
__exportStar(require("./frames"), exports);
|
|
19
|
-
__exportStar(require("./stream"), exports);
|
|
20
|
-
__exportStar(require("./subscription"), exports);
|
|
21
|
-
__exportStar(require("./server"), exports);
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './frames.js';
|
|
3
|
+
export * from './stream.js';
|
|
4
|
+
export * from './subscription.js';
|
|
5
|
+
export * from './server.js';
|
|
22
6
|
//# sourceMappingURL=index.js.map
|
package/dist/stream/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/stream/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/stream/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA","sourcesContent":["export * from './types.js'\nexport * from './frames.js'\nexport * from './stream.js'\nexport * from './subscription.js'\nexport * from './server.js'\n"]}
|
package/dist/stream/logger.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const common_1 = require("@atproto/common");
|
|
5
|
-
exports.logger = (0, common_1.subsystemLogger)('xrpc-stream');
|
|
6
|
-
exports.default = exports.logger;
|
|
1
|
+
import { subsystemLogger } from '@atproto/common';
|
|
2
|
+
export const logger = subsystemLogger('xrpc-stream');
|
|
3
|
+
export default logger;
|
|
7
4
|
//# sourceMappingURL=logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/stream/logger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/stream/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,MAAM,CAAC,MAAM,MAAM,GACjB,eAAe,CAAC,aAAa,CAAC,CAAA;AAEhC,eAAe,MAAM,CAAA","sourcesContent":["import { subsystemLogger } from '@atproto/common'\n\nexport const logger: ReturnType<typeof subsystemLogger> =\n subsystemLogger('xrpc-stream')\n\nexport default logger\n"]}
|
package/dist/stream/server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IncomingMessage } from 'node:http';
|
|
2
|
-
import { ServerOptions
|
|
3
|
-
import {
|
|
2
|
+
import type { ServerOptions } from 'ws';
|
|
3
|
+
import { WebSocket, WebSocketServer } from 'ws';
|
|
4
|
+
import { Frame } from './frames.js';
|
|
4
5
|
export declare class XrpcStreamServer {
|
|
5
6
|
wss: WebSocketServer;
|
|
6
7
|
constructor(opts: ServerOptions & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/stream/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/stream/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AAE/C,OAAO,EAAc,KAAK,EAAE,MAAM,aAAa,CAAA;AAG/C,qBAAa,gBAAgB;IAC3B,GAAG,EAAE,eAAe,CAAA;gBACR,IAAI,EAAE,aAAa,GAAG;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE;CAqCvD;AAED,MAAM,MAAM,OAAO,GAAG,CACpB,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,gBAAgB,KACrB,aAAa,CAAC,KAAK,CAAC,CAAA"}
|
package/dist/stream/server.js
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const frames_1 = require("./frames");
|
|
7
|
-
const logger_1 = require("./logger");
|
|
8
|
-
class XrpcStreamServer {
|
|
1
|
+
import { WebSocketServer } from 'ws';
|
|
2
|
+
import { CloseCode, DisconnectError } from '@atproto/ws-client';
|
|
3
|
+
import { ErrorFrame } from './frames.js';
|
|
4
|
+
import { logger } from './logger.js';
|
|
5
|
+
export class XrpcStreamServer {
|
|
9
6
|
constructor(opts) {
|
|
10
|
-
Object.defineProperty(this, "wss", {
|
|
11
|
-
enumerable: true,
|
|
12
|
-
configurable: true,
|
|
13
|
-
writable: true,
|
|
14
|
-
value: void 0
|
|
15
|
-
});
|
|
16
7
|
const { handler, ...serverOpts } = opts;
|
|
17
|
-
this.wss = new
|
|
8
|
+
this.wss = new WebSocketServer(serverOpts);
|
|
18
9
|
this.wss.on('connection', async (socket, req) => {
|
|
19
|
-
socket.on('error', (err) =>
|
|
10
|
+
socket.on('error', (err) => logger.error(err, 'websocket error'));
|
|
20
11
|
try {
|
|
21
12
|
const ac = new AbortController();
|
|
22
13
|
const iterator = unwrapIterator(handler(req, ac.signal, socket, this));
|
|
@@ -35,25 +26,24 @@ class XrpcStreamServer {
|
|
|
35
26
|
res(undefined);
|
|
36
27
|
});
|
|
37
28
|
});
|
|
38
|
-
if (frame instanceof
|
|
39
|
-
throw new
|
|
29
|
+
if (frame instanceof ErrorFrame) {
|
|
30
|
+
throw new DisconnectError(CloseCode.Policy, frame.body.error);
|
|
40
31
|
}
|
|
41
32
|
}
|
|
42
33
|
}
|
|
43
34
|
catch (err) {
|
|
44
|
-
if (err instanceof
|
|
35
|
+
if (err instanceof DisconnectError) {
|
|
45
36
|
return socket.close(err.wsCode, err.xrpcCode);
|
|
46
37
|
}
|
|
47
38
|
else {
|
|
48
|
-
|
|
39
|
+
logger.error({ err }, 'websocket server error');
|
|
49
40
|
return socket.terminate();
|
|
50
41
|
}
|
|
51
42
|
}
|
|
52
|
-
socket.close(
|
|
43
|
+
socket.close(CloseCode.Normal);
|
|
53
44
|
});
|
|
54
45
|
}
|
|
55
46
|
}
|
|
56
|
-
exports.XrpcStreamServer = XrpcStreamServer;
|
|
57
47
|
function unwrapIterator(iterable) {
|
|
58
48
|
return iterable[Symbol.asyncIterator]();
|
|
59
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/stream/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/stream/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,eAAe,EAAE,MAAM,IAAI,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAS,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,OAAO,gBAAgB;IAE3B,YAAY,IAA0C;QACpD,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,CAAA;QACvC,IAAI,CAAC,GAAG,GAAG,IAAI,eAAe,CAAC,UAAU,CAAC,CAAA;QAC1C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;YAC9C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAA;YACjE,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAA;gBAChC,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;gBACtE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;oBACxB,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAA;oBACnB,EAAE,CAAC,KAAK,EAAE,CAAA;gBACZ,CAAC,CAAC,CAAA;gBACF,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;gBACzC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;oBACrC,MAAM,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;wBAC7B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;4BACrD,oEAAoE;4BACpE,4DAA4D;4BAC5D,IAAI,GAAG;gCAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAA;4BACxB,GAAG,CAAC,SAAS,CAAC,CAAA;wBAChB,CAAC,CAAC,CAAA;oBACJ,CAAC,CAAC,CAAA;oBACF,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;wBAChC,MAAM,IAAI,eAAe,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;oBAC/D,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;oBACnC,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;gBAC/C,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAA;oBAC/C,OAAO,MAAM,CAAC,SAAS,EAAE,CAAA;gBAC3B,CAAC;YACH,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QAChC,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AASD,SAAS,cAAc,CAAI,QAA0B;IACnD,OAAO,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAA;AACzC,CAAC;AAED,SAAS,YAAY,CAAI,QAA0B;IACjD,OAAO;QACL,CAAC,MAAM,CAAC,aAAa,CAAC;YACpB,OAAO,QAAQ,CAAA;QACjB,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["import { IncomingMessage } from 'node:http'\nimport type { ServerOptions } from 'ws'\nimport { WebSocket, WebSocketServer } from 'ws'\nimport { CloseCode, DisconnectError } from '@atproto/ws-client'\nimport { ErrorFrame, Frame } from './frames.js'\nimport { logger } from './logger.js'\n\nexport class XrpcStreamServer {\n wss: WebSocketServer\n constructor(opts: ServerOptions & { handler: Handler }) {\n const { handler, ...serverOpts } = opts\n this.wss = new WebSocketServer(serverOpts)\n this.wss.on('connection', async (socket, req) => {\n socket.on('error', (err) => logger.error(err, 'websocket error'))\n try {\n const ac = new AbortController()\n const iterator = unwrapIterator(handler(req, ac.signal, socket, this))\n socket.once('close', () => {\n iterator.return?.()\n ac.abort()\n })\n const safeFrames = wrapIterator(iterator)\n for await (const frame of safeFrames) {\n await new Promise((res, rej) => {\n socket.send(frame.toBytes(), { binary: true }, (err) => {\n // @TODO this callback may give more aggressive on backpressure than\n // we ultimately want, but trying it out for the time being.\n if (err) return rej(err)\n res(undefined)\n })\n })\n if (frame instanceof ErrorFrame) {\n throw new DisconnectError(CloseCode.Policy, frame.body.error)\n }\n }\n } catch (err) {\n if (err instanceof DisconnectError) {\n return socket.close(err.wsCode, err.xrpcCode)\n } else {\n logger.error({ err }, 'websocket server error')\n return socket.terminate()\n }\n }\n socket.close(CloseCode.Normal)\n })\n }\n}\n\nexport type Handler = (\n req: IncomingMessage,\n signal: AbortSignal,\n socket: WebSocket,\n server: XrpcStreamServer,\n) => AsyncIterable<Frame>\n\nfunction unwrapIterator<T>(iterable: AsyncIterable<T>): AsyncIterator<T> {\n return iterable[Symbol.asyncIterator]()\n}\n\nfunction wrapIterator<T>(iterator: AsyncIterator<T>): AsyncIterable<T> {\n return {\n [Symbol.asyncIterator]() {\n return iterator\n },\n }\n}\n"]}
|
package/dist/stream/stream.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { DuplexOptions } from 'node:stream';
|
|
2
2
|
import { WebSocket } from 'ws';
|
|
3
|
-
import { MessageFrame } from './frames';
|
|
3
|
+
import { MessageFrame } from './frames.js';
|
|
4
4
|
export declare function streamByteChunks(ws: WebSocket, options?: DuplexOptions): import("stream").Duplex;
|
|
5
|
-
export declare function byFrame(ws: WebSocket, options?: DuplexOptions): AsyncGenerator<MessageFrame<import("@atproto/lex-data").LexValue> | import("./frames").ErrorFrame<string>, void, unknown>;
|
|
5
|
+
export declare function byFrame(ws: WebSocket, options?: DuplexOptions): AsyncGenerator<MessageFrame<import("@atproto/lex-data").LexValue> | import("./frames.js").ErrorFrame<string>, void, unknown>;
|
|
6
6
|
export declare function byMessage(ws: WebSocket, options?: DuplexOptions): AsyncGenerator<MessageFrame<import("@atproto/lex-data").LexValue>, void, unknown>;
|
|
7
7
|
export declare function ensureChunkIsMessage(chunk: Uint8Array): MessageFrame;
|
|
8
8
|
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/stream/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAyB,MAAM,IAAI,CAAA;AAErD,OAAO,EAAS,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/stream/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAyB,MAAM,IAAI,CAAA;AAErD,OAAO,EAAS,YAAY,EAAE,MAAM,aAAa,CAAA;AAEjD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,aAAa,2BAKtE;AAED,wBAAuB,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,aAAa,gIAKpE;AAED,wBAAuB,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,aAAa,qFAMtE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,CAWpE"}
|
package/dist/stream/stream.js
CHANGED
|
@@ -1,43 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
exports.ensureChunkIsMessage = ensureChunkIsMessage;
|
|
7
|
-
const ws_1 = require("ws");
|
|
8
|
-
const xrpc_1 = require("@atproto/xrpc");
|
|
9
|
-
const frames_1 = require("./frames");
|
|
10
|
-
function streamByteChunks(ws, options) {
|
|
11
|
-
return (0, ws_1.createWebSocketStream)(ws, {
|
|
1
|
+
import { createWebSocketStream } from 'ws';
|
|
2
|
+
import { ResponseType, XRPCError } from '@atproto/xrpc';
|
|
3
|
+
import { Frame } from './frames.js';
|
|
4
|
+
export function streamByteChunks(ws, options) {
|
|
5
|
+
return createWebSocketStream(ws, {
|
|
12
6
|
...options,
|
|
13
7
|
readableObjectMode: true, // Ensures frame bytes don't get buffered/combined together
|
|
14
8
|
});
|
|
15
9
|
}
|
|
16
|
-
async function* byFrame(ws, options) {
|
|
10
|
+
export async function* byFrame(ws, options) {
|
|
17
11
|
const wsStream = streamByteChunks(ws, options);
|
|
18
12
|
for await (const chunk of wsStream) {
|
|
19
|
-
yield
|
|
13
|
+
yield Frame.fromBytes(chunk);
|
|
20
14
|
}
|
|
21
15
|
}
|
|
22
|
-
async function* byMessage(ws, options) {
|
|
16
|
+
export async function* byMessage(ws, options) {
|
|
23
17
|
const wsStream = streamByteChunks(ws, options);
|
|
24
18
|
for await (const chunk of wsStream) {
|
|
25
19
|
const msg = ensureChunkIsMessage(chunk);
|
|
26
20
|
yield msg;
|
|
27
21
|
}
|
|
28
22
|
}
|
|
29
|
-
function ensureChunkIsMessage(chunk) {
|
|
30
|
-
const frame =
|
|
23
|
+
export function ensureChunkIsMessage(chunk) {
|
|
24
|
+
const frame = Frame.fromBytes(chunk);
|
|
31
25
|
if (frame.isMessage()) {
|
|
32
26
|
return frame;
|
|
33
27
|
}
|
|
34
28
|
else if (frame.isError()) {
|
|
35
29
|
// @TODO work -1 error code into XRPCError
|
|
36
30
|
// @ts-ignore
|
|
37
|
-
throw new
|
|
31
|
+
throw new XRPCError(-1, frame.code, frame.message);
|
|
38
32
|
}
|
|
39
33
|
else {
|
|
40
|
-
throw new
|
|
34
|
+
throw new XRPCError(ResponseType.Unknown, undefined, 'Unknown frame type');
|
|
41
35
|
}
|
|
42
36
|
}
|
|
43
37
|
//# sourceMappingURL=stream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/stream/stream.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/stream/stream.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,qBAAqB,EAAE,MAAM,IAAI,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,EAAE,KAAK,EAAgB,MAAM,aAAa,CAAA;AAEjD,MAAM,UAAU,gBAAgB,CAAC,EAAa,EAAE,OAAuB;IACrE,OAAO,qBAAqB,CAAC,EAAE,EAAE;QAC/B,GAAG,OAAO;QACV,kBAAkB,EAAE,IAAI,EAAE,2DAA2D;KACtF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,OAAO,CAAC,EAAa,EAAE,OAAuB;IACnE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IAC9C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QACnC,MAAM,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC,EAAa,EAAE,OAAuB;IACrE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IAC9C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAA;QACvC,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAiB;IACpD,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IACpC,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;QACtB,OAAO,KAAK,CAAA;IACd,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QAC3B,0CAA0C;QAC1C,aAAa;QACb,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;IACpD,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,SAAS,EAAE,oBAAoB,CAAC,CAAA;IAC5E,CAAC;AACH,CAAC","sourcesContent":["import { DuplexOptions } from 'node:stream'\nimport { WebSocket, createWebSocketStream } from 'ws'\nimport { ResponseType, XRPCError } from '@atproto/xrpc'\nimport { Frame, MessageFrame } from './frames.js'\n\nexport function streamByteChunks(ws: WebSocket, options?: DuplexOptions) {\n return createWebSocketStream(ws, {\n ...options,\n readableObjectMode: true, // Ensures frame bytes don't get buffered/combined together\n })\n}\n\nexport async function* byFrame(ws: WebSocket, options?: DuplexOptions) {\n const wsStream = streamByteChunks(ws, options)\n for await (const chunk of wsStream) {\n yield Frame.fromBytes(chunk)\n }\n}\n\nexport async function* byMessage(ws: WebSocket, options?: DuplexOptions) {\n const wsStream = streamByteChunks(ws, options)\n for await (const chunk of wsStream) {\n const msg = ensureChunkIsMessage(chunk)\n yield msg\n }\n}\n\nexport function ensureChunkIsMessage(chunk: Uint8Array): MessageFrame {\n const frame = Frame.fromBytes(chunk)\n if (frame.isMessage()) {\n return frame\n } else if (frame.isError()) {\n // @TODO work -1 error code into XRPCError\n // @ts-ignore\n throw new XRPCError(-1, frame.code, frame.message)\n } else {\n throw new XRPCError(ResponseType.Unknown, undefined, 'Unknown frame type')\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/stream/subscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/stream/subscription.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AAKvC,qBAAa,YAAY,CAAC,CAAC,GAAG,OAAO;IAE1B,IAAI,EAAE,aAAa,GAAG;QAC3B,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;QACd,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,MAAM,CAAC,EAAE,WAAW,CAAA;QACpB,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,GAAG,SAAS,CAAA;QACzC,gBAAgB,CAAC,EAAE,CACjB,KAAK,EAAE,OAAO,EACd,CAAC,EAAE,MAAM,EACT,YAAY,EAAE,OAAO,KAClB,IAAI,CAAA;QACT,SAAS,CAAC,EAAE,MACR,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAC5C,SAAS,CAAA;KACd;gBAhBM,IAAI,EAAE,aAAa,GAAG;QAC3B,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;QACd,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,MAAM,CAAC,EAAE,WAAW,CAAA;QACpB,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,GAAG,SAAS,CAAA;QACzC,gBAAgB,CAAC,EAAE,CACjB,KAAK,EAAE,OAAO,EACd,CAAC,EAAE,MAAM,EACT,YAAY,EAAE,OAAO,KAClB,IAAI,CAAA;QACT,SAAS,CAAC,EAAE,MACR,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAC5C,SAAS,CAAA;KACd;IAGI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC;CA4BnD;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -1,20 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const ws_client_1 = require("@atproto/ws-client");
|
|
6
|
-
const stream_1 = require("./stream");
|
|
7
|
-
class Subscription {
|
|
1
|
+
import { isPlainObject } from '@atproto/lex-data';
|
|
2
|
+
import { WebSocketKeepAlive } from '@atproto/ws-client';
|
|
3
|
+
import { ensureChunkIsMessage } from './stream.js';
|
|
4
|
+
export class Subscription {
|
|
8
5
|
constructor(opts) {
|
|
9
|
-
|
|
10
|
-
enumerable: true,
|
|
11
|
-
configurable: true,
|
|
12
|
-
writable: true,
|
|
13
|
-
value: opts
|
|
14
|
-
});
|
|
6
|
+
this.opts = opts;
|
|
15
7
|
}
|
|
16
8
|
async *[Symbol.asyncIterator]() {
|
|
17
|
-
const ws = new
|
|
9
|
+
const ws = new WebSocketKeepAlive({
|
|
18
10
|
...this.opts,
|
|
19
11
|
getUrl: async () => {
|
|
20
12
|
const params = (await this.opts.getParams?.()) ?? {};
|
|
@@ -23,9 +15,9 @@ class Subscription {
|
|
|
23
15
|
},
|
|
24
16
|
});
|
|
25
17
|
for await (const chunk of ws) {
|
|
26
|
-
const message =
|
|
18
|
+
const message = ensureChunkIsMessage(chunk);
|
|
27
19
|
const t = message.header.t;
|
|
28
|
-
const typedBody =
|
|
20
|
+
const typedBody = isPlainObject(message.body)
|
|
29
21
|
? t !== undefined
|
|
30
22
|
? {
|
|
31
23
|
...message.body,
|
|
@@ -40,8 +32,7 @@ class Subscription {
|
|
|
40
32
|
}
|
|
41
33
|
}
|
|
42
34
|
}
|
|
43
|
-
|
|
44
|
-
exports.default = Subscription;
|
|
35
|
+
export default Subscription;
|
|
45
36
|
function encodeQueryParams(obj) {
|
|
46
37
|
const params = new URLSearchParams();
|
|
47
38
|
Object.entries(obj).forEach(([key, value]) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../src/stream/subscription.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../src/stream/subscription.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ClientOptions } from 'ws'\nimport { isPlainObject } from '@atproto/lex-data'\nimport { WebSocketKeepAlive } from '@atproto/ws-client'\nimport { ensureChunkIsMessage } from './stream.js'\n\nexport class Subscription<T = unknown> {\n constructor(\n public opts: ClientOptions & {\n service: string\n method: string\n maxReconnectSeconds?: number\n heartbeatIntervalMs?: number\n signal?: AbortSignal\n validate: (obj: unknown) => T | undefined\n onReconnectError?: (\n error: unknown,\n n: number,\n initialSetup: boolean,\n ) => void\n getParams?: () =>\n | Record<string, unknown>\n | Promise<Record<string, unknown> | undefined>\n | undefined\n },\n ) {}\n\n async *[Symbol.asyncIterator](): AsyncGenerator<T> {\n const ws = new WebSocketKeepAlive({\n ...this.opts,\n getUrl: async () => {\n const params = (await this.opts.getParams?.()) ?? {}\n const query = encodeQueryParams(params)\n return `${this.opts.service}/xrpc/${this.opts.method}?${query}`\n },\n })\n for await (const chunk of ws) {\n const message = ensureChunkIsMessage(chunk)\n const t = message.header.t\n\n const typedBody = isPlainObject(message.body)\n ? t !== undefined\n ? {\n ...message.body,\n $type: t.startsWith('#') ? this.opts.method + t : t,\n }\n : message.body\n : undefined\n\n const result = this.opts.validate(typedBody)\n if (result !== undefined) {\n yield result\n }\n }\n }\n}\n\nexport default Subscription\n\nfunction encodeQueryParams(obj: Record<string, unknown>): string {\n const params = new URLSearchParams()\n Object.entries(obj).forEach(([key, value]) => {\n const encoded = encodeQueryParam(value)\n if (Array.isArray(encoded)) {\n encoded.forEach((enc) => params.append(key, enc))\n } else {\n params.set(key, encoded)\n }\n })\n return params.toString()\n}\n\n// Adapted from xrpc, but without any lex-specific knowledge\nfunction encodeQueryParam(value: unknown): string | string[] {\n if (typeof value === 'string') {\n return value\n }\n if (typeof value === 'number') {\n return value.toString()\n }\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false'\n }\n if (typeof value === 'undefined') {\n return ''\n }\n if (typeof value === 'object') {\n if (value instanceof Date) {\n return value.toISOString()\n } else if (Array.isArray(value)) {\n return value.flatMap(encodeQueryParam)\n } else if (!value) {\n return ''\n }\n }\n throw new Error(`Cannot encode ${typeof value}s into query params`)\n}\n"]}
|
package/dist/stream/types.js
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.frameHeader = exports.errorFrameBody = exports.errorFrameHeader = exports.messageFrameHeader = exports.FrameType = void 0;
|
|
4
|
-
const lex_schema_1 = require("@atproto/lex-schema");
|
|
5
|
-
var FrameType;
|
|
1
|
+
import { l } from '@atproto/lex-schema';
|
|
2
|
+
export var FrameType;
|
|
6
3
|
(function (FrameType) {
|
|
7
4
|
FrameType[FrameType["Message"] = 1] = "Message";
|
|
8
5
|
FrameType[FrameType["Error"] = -1] = "Error";
|
|
9
|
-
})(FrameType || (
|
|
10
|
-
|
|
11
|
-
op:
|
|
12
|
-
t:
|
|
6
|
+
})(FrameType || (FrameType = {}));
|
|
7
|
+
export const messageFrameHeader = l.object({
|
|
8
|
+
op: l.literal(FrameType.Message), // Frame op
|
|
9
|
+
t: l.optional(l.string()), // Message body type discriminator
|
|
13
10
|
});
|
|
14
|
-
|
|
15
|
-
op:
|
|
11
|
+
export const errorFrameHeader = l.object({
|
|
12
|
+
op: l.literal(FrameType.Error),
|
|
16
13
|
});
|
|
17
|
-
|
|
18
|
-
error:
|
|
19
|
-
message:
|
|
14
|
+
export const errorFrameBody = l.object({
|
|
15
|
+
error: l.string(), // Error code
|
|
16
|
+
message: l.optional(l.string()), // Error message
|
|
20
17
|
});
|
|
21
|
-
|
|
18
|
+
export const frameHeader = l.union([messageFrameHeader, errorFrameHeader]);
|
|
22
19
|
//# sourceMappingURL=types.js.map
|
package/dist/stream/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/stream/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/stream/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,qBAAqB,CAAA;AAEvC,MAAM,CAAN,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,+CAAW,CAAA;IACX,4CAAU,CAAA;AACZ,CAAC,EAHW,SAAS,KAAT,SAAS,QAGpB;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,WAAW;IAC7C,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,kCAAkC;CAC9D,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC;CAC/B,CAAC,CAAA;AACF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,aAAa;IAChC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,gBAAgB;CAClD,CAAC,CAAA;AAMF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC,CAAA","sourcesContent":["import { l } from '@atproto/lex-schema'\n\nexport enum FrameType {\n Message = 1,\n Error = -1,\n}\n\nexport const messageFrameHeader = l.object({\n op: l.literal(FrameType.Message), // Frame op\n t: l.optional(l.string()), // Message body type discriminator\n})\nexport type MessageFrameHeader = l.Infer<typeof messageFrameHeader>\n\nexport const errorFrameHeader = l.object({\n op: l.literal(FrameType.Error),\n})\nexport const errorFrameBody = l.object({\n error: l.string(), // Error code\n message: l.optional(l.string()), // Error message\n})\nexport type ErrorFrameHeader = l.Infer<typeof errorFrameHeader>\nexport type ErrorFrameBody<T extends string = string> = { error: T } & l.Infer<\n typeof errorFrameBody\n>\n\nexport const frameHeader = l.union([messageFrameHeader, errorFrameHeader])\nexport type FrameHeader = l.Infer<typeof frameHeader>\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { IncomingMessage } from 'node:http';
|
|
|
2
2
|
import { Readable } from 'node:stream';
|
|
3
3
|
import { NextFunction, Request, Response } from 'express';
|
|
4
4
|
import { l } from '@atproto/lex-schema';
|
|
5
|
-
import { ErrorResult, XRPCError } from './errors';
|
|
6
|
-
import { CalcKeyFn, CalcPointsFn, RateLimiterI } from './rate-limiter';
|
|
5
|
+
import { ErrorResult, XRPCError } from './errors.js';
|
|
6
|
+
import { CalcKeyFn, CalcPointsFn, RateLimiterI } from './rate-limiter.js';
|
|
7
7
|
export type Awaitable<T> = T | Promise<T>;
|
|
8
8
|
export type CatchallHandler = (req: Request, res: Response, next: NextFunction) => unknown;
|
|
9
9
|
export type Options = {
|