@atcute/firehose 0.1.0 → 1.0.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/README.md CHANGED
@@ -1,23 +1,211 @@
1
1
  # @atcute/firehose
2
2
 
3
- lightweight and cute XRPC subscription client for AT Protocol.
3
+ lightweight XRPC subscription client for AT Protocol.
4
+
5
+ ```sh
6
+ npm install @atcute/firehose
7
+ ```
8
+
9
+ this package provides a generic client for XRPC subscriptions - the WebSocket-based streaming
10
+ protocol used by AT Protocol. it handles CBOR frame decoding, automatic reconnection, and optional
11
+ schema validation.
12
+
13
+ for consuming the Bluesky network firehose specifically, consider using `@atcute/jetstream` instead,
14
+ which provides a simpler JSON-based interface.
15
+
16
+ ## usage
17
+
18
+ ### subscribing to the relay firehose
4
19
 
5
20
  ```ts
6
21
  import { FirehoseSubscription } from '@atcute/firehose';
7
22
  import { ComAtprotoSyncSubscribeRepos } from '@atcute/atproto';
8
23
 
24
+ const subscription = new FirehoseSubscription({
25
+ service: 'wss://bsky.network',
26
+ nsid: ComAtprotoSyncSubscribeRepos.mainSchema,
27
+ });
28
+
29
+ for await (const message of subscription) {
30
+ console.log(message.$type, message.seq);
31
+ }
32
+ ```
33
+
34
+ the connection opens when you start iterating and closes when you break out of the loop. the
35
+ underlying WebSocket automatically reconnects on disconnection.
36
+
37
+ ### handling message types
38
+
39
+ messages include a `$type` field indicating their type:
40
+
41
+ ```ts
42
+ for await (const message of subscription) {
43
+ switch (message.$type) {
44
+ case 'com.atproto.sync.subscribeRepos#commit': {
45
+ // repository commit (record creates, updates, deletes)
46
+ console.log('commit:', message.repo, message.rev);
47
+ break;
48
+ }
49
+
50
+ case 'com.atproto.sync.subscribeRepos#handle': {
51
+ // handle change
52
+ console.log('handle:', message.did, message.handle);
53
+ break;
54
+ }
55
+
56
+ case 'com.atproto.sync.subscribeRepos#migrate': {
57
+ // account migration
58
+ console.log('migrate:', message.did, message.migrateTo);
59
+ break;
60
+ }
61
+
62
+ case 'com.atproto.sync.subscribeRepos#tombstone': {
63
+ // account deletion
64
+ console.log('tombstone:', message.did);
65
+ break;
66
+ }
67
+
68
+ case 'com.atproto.sync.subscribeRepos#identity': {
69
+ // identity update
70
+ console.log('identity:', message.did);
71
+ break;
72
+ }
73
+
74
+ case 'com.atproto.sync.subscribeRepos#account': {
75
+ // account status change
76
+ console.log('account:', message.did, message.active);
77
+ break;
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ ### tracking cursor for resumption
84
+
85
+ use a function for `params` to provide the current cursor on each connection attempt:
86
+
87
+ ```ts
9
88
  let cursor: number | undefined;
10
89
 
90
+ // load saved cursor if resuming
91
+ const saved = localStorage.getItem('firehose-cursor');
92
+ if (saved) {
93
+ cursor = Number(saved);
94
+ }
95
+
11
96
  const subscription = new FirehoseSubscription({
12
- service: ['wss://bsky.network'],
97
+ service: 'wss://bsky.network',
13
98
  nsid: ComAtprotoSyncSubscribeRepos.mainSchema,
99
+ // function is called on each connection/reconnection
14
100
  params: () => ({ cursor }),
15
101
  });
16
102
 
17
103
  for await (const message of subscription) {
18
- if (message.$type === 'com.atproto.sync.subscribeRepos#commit') {
104
+ if ('seq' in message) {
19
105
  cursor = message.seq;
20
- console.log('commit:', message.seq, message.repo);
106
+
107
+ // periodically save cursor for recovery
108
+ if (cursor % 1000 === 0) {
109
+ localStorage.setItem('firehose-cursor', String(cursor));
110
+ }
21
111
  }
22
112
  }
23
113
  ```
114
+
115
+ the params function is called on each connection attempt, so when the WebSocket reconnects after a
116
+ disconnection, it automatically uses the latest cursor value.
117
+
118
+ ### using multiple servers
119
+
120
+ pass an array of URLs for automatic failover. the client randomly selects one on each connection:
121
+
122
+ ```ts
123
+ const subscription = new FirehoseSubscription({
124
+ service: ['wss://bsky.network', 'wss://bsky-relay.example.com'],
125
+ nsid: ComAtprotoSyncSubscribeRepos.mainSchema,
126
+ });
127
+ ```
128
+
129
+ ### handling errors
130
+
131
+ XRPC subscriptions can send error frames. handle them with the `onError` callback:
132
+
133
+ ```ts
134
+ const subscription = new FirehoseSubscription({
135
+ service: 'wss://bsky.network',
136
+ nsid: ComAtprotoSyncSubscribeRepos.mainSchema,
137
+ onError(error, message) {
138
+ console.error('firehose error:', error, message);
139
+ // common errors:
140
+ // - "FutureCursor": cursor is ahead of the server
141
+ // - "ConsumerTooSlow": client is not consuming messages fast enough
142
+ },
143
+ });
144
+ ```
145
+
146
+ ### connection lifecycle callbacks
147
+
148
+ handle connection events for logging or UI updates:
149
+
150
+ ```ts
151
+ const subscription = new FirehoseSubscription({
152
+ service: 'wss://bsky.network',
153
+ nsid: ComAtprotoSyncSubscribeRepos.mainSchema,
154
+ onConnectionOpen(event) {
155
+ console.log('connected to firehose');
156
+ },
157
+ onConnectionClose(event) {
158
+ console.log('disconnected:', event.code, event.reason);
159
+ },
160
+ onConnectionError(event) {
161
+ console.error('connection error:', event.error);
162
+ },
163
+ });
164
+ ```
165
+
166
+ ### updating options at runtime
167
+
168
+ change options using `updateOptions()`. this triggers a reconnection:
169
+
170
+ ```ts
171
+ const subscription = new FirehoseSubscription({
172
+ service: 'wss://bsky.network',
173
+ nsid: ComAtprotoSyncSubscribeRepos.mainSchema,
174
+ });
175
+
176
+ // later, switch to a different service
177
+ subscription.updateOptions({
178
+ service: 'wss://different-relay.example.com',
179
+ });
180
+ ```
181
+
182
+ ### disabling message validation
183
+
184
+ by default, messages are validated against the schema. disable this for better performance if you
185
+ trust the server:
186
+
187
+ ```ts
188
+ const subscription = new FirehoseSubscription({
189
+ service: 'wss://bsky.network',
190
+ nsid: ComAtprotoSyncSubscribeRepos.mainSchema,
191
+ validateMessages: false,
192
+ });
193
+ ```
194
+
195
+ ### WebSocket options
196
+
197
+ pass options to the underlying
198
+ [partysocket](https://github.com/partykit/partykit/tree/main/packages/partysocket) WebSocket for
199
+ custom reconnection behavior:
200
+
201
+ ```ts
202
+ const subscription = new FirehoseSubscription({
203
+ service: 'wss://bsky.network',
204
+ nsid: ComAtprotoSyncSubscribeRepos.mainSchema,
205
+ ws: {
206
+ maxRetries: 10,
207
+ minReconnectionDelay: 1000,
208
+ maxReconnectionDelay: 30000,
209
+ },
210
+ });
211
+ ```
@@ -1,4 +1,4 @@
1
- import type { DecodedFrame } from './types.js';
1
+ import type { DecodedFrame } from './types.ts';
2
2
  /**
3
3
  * decodes a CBOR frame from a buffer
4
4
  */
@@ -1 +1 @@
1
- {"version":3,"file":"frame-decoder.d.ts","sourceRoot":"","sources":["../lib/frame-decoder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAA+B,MAAM,YAAY,CAAC;AAE5E;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,UAAU,KAAG,YAuBhD,CAAC;AAeF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,eAAe,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,KAAG,MAAM,GAAG,SAU1F,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,OAAO,EAAE,eAAe,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,KAAG,OAQ9F,CAAC"}
1
+ {"version":3,"file":"frame-decoder.d.ts","sourceRoot":"","sources":["../lib/frame-decoder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAA+B,MAAM,YAAY,CAAC;AAE5E;;GAEG;AACH,eAAO,MAAM,WAAW,WAAY,UAAU,KAAG,YAuBhD,CAAC;AAeF;;GAEG;AACH,eAAO,MAAM,eAAe,kBAAmB,MAAM,GAAG,SAAS,QAAQ,MAAM,KAAG,MAAM,GAAG,SAU1F,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,SAAU,OAAO,iBAAiB,MAAM,GAAG,SAAS,QAAQ,MAAM,KAAG,OAQ9F,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { FirehoseSubscription } from './subscription.js';
2
- export type { FirehoseSubscriptionOptions, MessageOf, ParamsOf } from './types.js';
1
+ export { FirehoseError, FirehoseSubscription } from './subscription.ts';
2
+ export type { FirehoseSubscriptionOptions, MessageOf, ParamsOf } from './types.ts';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,YAAY,EAAE,2BAA2B,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACxE,YAAY,EAAE,2BAA2B,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { FirehoseSubscription } from './subscription.js';
1
+ export { FirehoseError, FirehoseSubscription } from './subscription.js';
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1,7 +1,17 @@
1
1
  import { type XRPCSubscriptionMetadata } from '@atcute/lexicons/validations';
2
2
  import { EventIterator } from '@mary-ext/event-iterator';
3
3
  import type { ReadonlyDeep } from 'type-fest';
4
- import type { FirehoseSubscriptionOptions, MessageOf } from './types.js';
4
+ import type { FirehoseSubscriptionOptions, MessageOf } from './types.ts';
5
+ /**
6
+ * non-fatal error frame received from the upstream firehose, carrying the
7
+ * atproto-spec `error` code alongside the human-readable `message`.
8
+ */
9
+ export declare class FirehoseError extends Error {
10
+ readonly name = "FirehoseError";
11
+ /** atproto error code from the error frame */
12
+ readonly error: string;
13
+ constructor(error: string, message?: string);
14
+ }
5
15
  /**
6
16
  * generic XRPC subscription client for AT Protocol
7
17
  */
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../lib/subscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAExF,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAKzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,OAAO,KAAK,EAAE,2BAA2B,EAAE,SAAS,EAAY,MAAM,YAAY,CAAC;AAEnF;;GAEG;AACH,qBAAa,oBAAoB,CAAC,OAAO,SAAS,wBAAwB;;IAQzE;;OAEG;gBACS,OAAO,EAAE,2BAA2B,CAAC,OAAO,CAAC;IA4FzD,CAAC,MAAM,CAAC,aAAa,CAAC;IAoBtB;;OAEG;IACH,UAAU,IAAI,YAAY,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC;IAIhE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI;CAQ3E"}
1
+ {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../lib/subscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAExF,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,OAAO,KAAK,EAAE,2BAA2B,EAAE,SAAS,EAAY,MAAM,YAAY,CAAC;AAEnF;;;GAGG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACvC,SAAkB,IAAI,mBAAmB;IACzC,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,YAAY,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAG1C;CACD;AAED;;GAEG;AACH,qBAAa,oBAAoB,CAAC,OAAO,SAAS,wBAAwB;;IAQzE;;OAEG;IACH,YAAY,OAAO,EAAE,2BAA2B,CAAC,OAAO,CAAC,EAExD;IAiGD,CAAC,MAAM,CAAC,aAAa,CAAC,sCAkBrB;IAED;;OAEG;IACH,UAAU,IAAI,YAAY,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,CAE/D;IAED;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAO1E;CACD"}
@@ -3,6 +3,17 @@ import { EventIterator } from '@mary-ext/event-iterator';
3
3
  import { SimpleEventEmitter } from '@mary-ext/simple-event-emitter';
4
4
  import { WebSocket as ReconnectingWebSocket } from 'partysocket';
5
5
  import { addTypeToBody, decodeFrame } from './frame-decoder.js';
6
+ /**
7
+ * non-fatal error frame received from the upstream firehose, carrying the
8
+ * atproto-spec `error` code alongside the human-readable `message`.
9
+ */
10
+ export class FirehoseError extends Error {
11
+ constructor(error, message) {
12
+ super(message ?? error);
13
+ this.name = 'FirehoseError';
14
+ this.error = error;
15
+ }
16
+ }
6
17
  /**
7
18
  * generic XRPC subscription client for AT Protocol
8
19
  */
@@ -21,7 +32,7 @@ export class FirehoseSubscription {
21
32
  if (this.#ws !== undefined) {
22
33
  return;
23
34
  }
24
- const { service: wsUrls, nsid, params, ws: wsOptions, validateMessages = true, onConnectionClose, onConnectionError, onConnectionOpen, onError, } = this.#options;
35
+ const { service: wsUrls, nsid, params, ws: wsOptions, validateEvents = true, onConnectionClose, onConnectionError, onConnectionOpen, onError, } = this.#options;
25
36
  const emitter = this.#emitter;
26
37
  const getUrl = () => {
27
38
  let selectedUrl;
@@ -54,13 +65,21 @@ export class FirehoseSubscription {
54
65
  const buffer = new Uint8Array(ev.data);
55
66
  const frame = decodeFrame(buffer);
56
67
  if (frame.type === 'error') {
57
- onError?.(frame.error, frame.message);
68
+ onError?.(new FirehoseError(frame.error, frame.message));
58
69
  return;
59
70
  }
60
71
  let body = addTypeToBody(frame.body, frame.discriminator, nsid.nsid);
61
- if (validateMessages && nsid.message !== null) {
72
+ if (validateEvents && nsid.message !== null) {
62
73
  const result = safeParse(nsid.message, body);
63
74
  if (!result.ok) {
75
+ if (onError) {
76
+ try {
77
+ result.throw();
78
+ }
79
+ catch (err) {
80
+ onError(err);
81
+ }
82
+ }
64
83
  return;
65
84
  }
66
85
  body = result.value;
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../lib/subscription.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../lib/subscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAiC,MAAM,8BAA8B,CAAC;AAExF,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,SAAS,IAAI,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGhE;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAIvC,YAAY,KAAa,EAAE,OAAgB;QAC1C,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC;QAJP,SAAI,GAAG,eAAe,CAAC;QAKxC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,CAAC;CACD;AAED;;GAEG;AACH,MAAM,OAAO,oBAAoB;IAChC,UAAU,GAAG,CAAC,CAAC;IACf,GAAG,CAAyB;IAE5B,QAAQ,GAAG,IAAI,kBAAkB,EAAiC,CAAC;IAEnE,QAAQ,CAAuC;IAE/C;;OAEG;IACH,YAAY,OAA6C;QACxD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,OAAO;QACN,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO;QACR,CAAC;QAED,MAAM,EACL,OAAO,EAAE,MAAM,EACf,IAAI,EACJ,MAAM,EACN,EAAE,EAAE,SAAS,EACb,cAAc,GAAG,IAAI,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,OAAO,GACP,GAAG,IAAI,CAAC,QAAQ,CAAC;QAElB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC;QAE9B,MAAM,MAAM,GAAG,GAAG,EAAE;YACnB,IAAI,WAAmB,CAAC;YAExB,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAChC,WAAW,GAAG,MAAM,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACP,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACjE,CAAC;YAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YAEvD,MAAM,aAAa,GAAsB,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YAE1F,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;gBAC3D,MAAM,QAAQ,GAAG,aAAwC,CAAC;gBAC1D,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;oBAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;oBAC5B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;wBAC3C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;oBAC1C,CAAC;gBACF,CAAC;YACF,CAAC;YAED,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;QACvB,CAAC,CAAC;QAEF,MAAM,EAAE,GAAG,IAAI,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QAEd,EAAE,CAAC,UAAU,GAAG,aAAa,CAAC;QAE9B,EAAE,CAAC,OAAO,GAAG,iBAAiB,IAAI,IAAI,CAAC;QACvC,EAAE,CAAC,OAAO,GAAG,iBAAiB,IAAI,IAAI,CAAC;QACvC,EAAE,CAAC,MAAM,GAAG,gBAAgB,IAAI,IAAI,CAAC;QAErC,EAAE,CAAC,SAAS,GAAG,CAAC,EAAE,EAAE,EAAE;YACrB,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YACvC,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;YAElC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5B,OAAO,EAAE,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;gBACzD,OAAO;YACR,CAAC;YAED,IAAI,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAErE,IAAI,cAAc,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;gBAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAC7C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;oBAChB,IAAI,OAAO,EAAE,CAAC;wBACb,IAAI,CAAC;4BACJ,MAAM,CAAC,KAAK,EAAE,CAAC;wBAChB,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACd,OAAO,CAAC,GAAG,CAAC,CAAC;wBACd,CAAC;oBACF,CAAC;oBACD,OAAO;gBACR,CAAC;gBACD,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;YACrB,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,IAA0B,CAAC,CAAC;QAC1C,CAAC,CAAC;IACH,CAAC;IAED,QAAQ;QACP,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC;QACpB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACtB,OAAO;QACR,CAAC;QAED,EAAE,CAAC,KAAK,EAAE,CAAC;QAEX,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC;IACtB,CAAC;IAED,CAAC,MAAM,CAAC,aAAa,CAAC;QACrB,OAAO,IAAI,aAAa,CAAqB,CAAC,IAAI,EAAE,EAAE;YACrD,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,CAAC;YAED,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAE9B,OAAO,GAAG,EAAE;gBACX,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;oBAC3B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACjB,CAAC;gBAED,IAAI,CAAC,UAAU,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC,CAAC;QACH,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,UAAU;QACT,OAAO,IAAI,CAAC,QAA8D,CAAC;IAC5E,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,OAAsD;QACnE,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;QAEjD,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,EAAE,CAAC;QAChB,CAAC;IACF,CAAC;CACD"}
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { InferOutput, XRPCSubscriptionMetadata } from '@atcute/lexicons/validations';
2
- import type { CloseEvent, ErrorEvent, Options } from 'partysocket/ws';
3
2
  import type { BaseSchema } from '@atcute/lexicons/validations';
3
+ import type { CloseEvent, ErrorEvent, Options } from 'partysocket/ws';
4
4
  /**
5
5
  * extracts the params type from an XRPC subscription schema
6
6
  */
@@ -28,14 +28,18 @@ export interface FirehoseSubscriptionOptions<TSchema extends XRPCSubscriptionMet
28
28
  */
29
29
  params?: ParamsOf<TSchema> | (() => ParamsOf<TSchema>);
30
30
  /**
31
- * whether to validate incoming messages against the schema
31
+ * whether to validate incoming events against the schema
32
32
  * @default true
33
33
  */
34
- validateMessages?: boolean;
34
+ validateEvents?: boolean;
35
35
  onConnectionOpen?: (event: Event) => void;
36
36
  onConnectionClose?: (event: CloseEvent) => void;
37
37
  onConnectionError?: (event: ErrorEvent) => void;
38
- onError?: (error: string, message?: string) => void;
38
+ /**
39
+ * called for non-fatal frame-level errors: atproto error frames (passed as `FirehoseError`)
40
+ * and message validation failures (passed as `ValidationError`).
41
+ */
42
+ onError?: (err: unknown) => void;
39
43
  /**
40
44
  * WebSocket connection options
41
45
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAE1F,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,wBAAwB,CAAC,MAAM,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAClF,OAAO,SAAS,IAAI,GACnB,SAAS,GACT,OAAO,SAAS,UAAU,GACzB,WAAW,CAAC,OAAO,CAAC,GACpB,KAAK,GACP,KAAK,CAAC;AAET;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,wBAAwB,CAAC,GAAG,EAAE,MAAM,QAAQ,EAAE,GAAG,CAAC,GACpF,QAAQ,SAAS,IAAI,GACpB,OAAO,GACP,QAAQ,SAAS,UAAU,GAC1B,WAAW,CAAC,QAAQ,CAAC,GACrB,KAAK,GACP,KAAK,CAAC;AAET;;GAEG;AACH,MAAM,WAAW,2BAA2B,CAAC,OAAO,SAAS,wBAAwB;IACpF;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE3B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;;;OAIG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC1C,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAEpD;;OAEG;IACH,EAAE,CAAC,EAAE,OAAO,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B;;OAEG;IACH,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEX;;OAEG;IACH,CAAC,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GACrB;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACtB,GACD;IACA,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IACrB,CAAC,SAAS,wBAAwB,CAAC,MAAM,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GACxD,OAAO,SAAS,IAAI,GACnB,SAAS,GACT,OAAO,SAAS,UAAU,GACzB,WAAW,CAAC,OAAO,CAAC,GACpB,KAAK,GACP,KAAK,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IACtB,CAAC,SAAS,wBAAwB,CAAC,GAAG,EAAE,MAAM,QAAQ,EAAE,GAAG,CAAC,GACzD,QAAQ,SAAS,IAAI,GACpB,OAAO,GACP,QAAQ,SAAS,UAAU,GAC1B,WAAW,CAAC,QAAQ,CAAC,GACrB,KAAK,GACP,KAAK,CAAC;AAEV;;GAEG;AACH,MAAM,WAAW,2BAA2B,CAAC,OAAO,SAAS,wBAAwB;IACpF;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE3B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;;;OAIG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvD;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC1C,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAEjC;;OAEG;IACH,EAAE,CAAC,EAAE,OAAO,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B;;OAEG;IACH,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEX;;OAEG;IACH,CAAC,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GACrB;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACtB,GACD;IACA,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { decode, decodeFirst } from '@atcute/cbor';
2
2
 
3
- import type { DecodedFrame, ErrorFrameBody, FrameHeader } from './types.js';
3
+ import type { DecodedFrame, ErrorFrameBody, FrameHeader } from './types.ts';
4
4
 
5
5
  /**
6
6
  * decodes a CBOR frame from a buffer
package/lib/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { FirehoseSubscription } from './subscription.js';
2
- export type { FirehoseSubscriptionOptions, MessageOf, ParamsOf } from './types.js';
1
+ export { FirehoseError, FirehoseSubscription } from './subscription.ts';
2
+ export type { FirehoseSubscriptionOptions, MessageOf, ParamsOf } from './types.ts';
@@ -2,13 +2,25 @@ import { safeParse, type XRPCSubscriptionMetadata } from '@atcute/lexicons/valid
2
2
 
3
3
  import { EventIterator } from '@mary-ext/event-iterator';
4
4
  import { SimpleEventEmitter } from '@mary-ext/simple-event-emitter';
5
-
6
5
  import { WebSocket as ReconnectingWebSocket } from 'partysocket';
7
-
8
6
  import type { ReadonlyDeep } from 'type-fest';
9
7
 
10
- import { addTypeToBody, decodeFrame } from './frame-decoder.js';
11
- import type { FirehoseSubscriptionOptions, MessageOf, ParamsOf } from './types.js';
8
+ import { addTypeToBody, decodeFrame } from './frame-decoder.ts';
9
+ import type { FirehoseSubscriptionOptions, MessageOf, ParamsOf } from './types.ts';
10
+
11
+ /**
12
+ * non-fatal error frame received from the upstream firehose, carrying the
13
+ * atproto-spec `error` code alongside the human-readable `message`.
14
+ */
15
+ export class FirehoseError extends Error {
16
+ override readonly name = 'FirehoseError';
17
+ /** atproto error code from the error frame */
18
+ readonly error: string;
19
+ constructor(error: string, message?: string) {
20
+ super(message ?? error);
21
+ this.error = error;
22
+ }
23
+ }
12
24
 
13
25
  /**
14
26
  * generic XRPC subscription client for AT Protocol
@@ -38,7 +50,7 @@ export class FirehoseSubscription<TSchema extends XRPCSubscriptionMetadata> {
38
50
  nsid,
39
51
  params,
40
52
  ws: wsOptions,
41
- validateMessages = true,
53
+ validateEvents = true,
42
54
  onConnectionClose,
43
55
  onConnectionError,
44
56
  onConnectionOpen,
@@ -87,15 +99,22 @@ export class FirehoseSubscription<TSchema extends XRPCSubscriptionMetadata> {
87
99
  const frame = decodeFrame(buffer);
88
100
 
89
101
  if (frame.type === 'error') {
90
- onError?.(frame.error, frame.message);
102
+ onError?.(new FirehoseError(frame.error, frame.message));
91
103
  return;
92
104
  }
93
105
 
94
106
  let body = addTypeToBody(frame.body, frame.discriminator, nsid.nsid);
95
107
 
96
- if (validateMessages && nsid.message !== null) {
108
+ if (validateEvents && nsid.message !== null) {
97
109
  const result = safeParse(nsid.message, body);
98
110
  if (!result.ok) {
111
+ if (onError) {
112
+ try {
113
+ result.throw();
114
+ } catch (err) {
115
+ onError(err);
116
+ }
117
+ }
99
118
  return;
100
119
  }
101
120
  body = result.value;
package/lib/types.ts CHANGED
@@ -1,30 +1,31 @@
1
1
  import type { InferOutput, XRPCSubscriptionMetadata } from '@atcute/lexicons/validations';
2
+ import type { BaseSchema } from '@atcute/lexicons/validations';
2
3
 
3
4
  import type { CloseEvent, ErrorEvent, Options } from 'partysocket/ws';
4
5
 
5
- import type { BaseSchema } from '@atcute/lexicons/validations';
6
-
7
6
  /**
8
7
  * extracts the params type from an XRPC subscription schema
9
8
  */
10
- export type ParamsOf<T> = T extends XRPCSubscriptionMetadata<infer TParams, any, any>
11
- ? TParams extends null
12
- ? undefined
13
- : TParams extends BaseSchema
14
- ? InferOutput<TParams>
15
- : never
16
- : never;
9
+ export type ParamsOf<T> =
10
+ T extends XRPCSubscriptionMetadata<infer TParams, any, any>
11
+ ? TParams extends null
12
+ ? undefined
13
+ : TParams extends BaseSchema
14
+ ? InferOutput<TParams>
15
+ : never
16
+ : never;
17
17
 
18
18
  /**
19
19
  * extracts the message type from an XRPC subscription schema
20
20
  */
21
- export type MessageOf<T> = T extends XRPCSubscriptionMetadata<any, infer TMessage, any>
22
- ? TMessage extends null
23
- ? unknown
24
- : TMessage extends BaseSchema
25
- ? InferOutput<TMessage>
26
- : never
27
- : never;
21
+ export type MessageOf<T> =
22
+ T extends XRPCSubscriptionMetadata<any, infer TMessage, any>
23
+ ? TMessage extends null
24
+ ? unknown
25
+ : TMessage extends BaseSchema
26
+ ? InferOutput<TMessage>
27
+ : never
28
+ : never;
28
29
 
29
30
  /**
30
31
  * configuration options for FirehoseSubscription
@@ -48,15 +49,19 @@ export interface FirehoseSubscriptionOptions<TSchema extends XRPCSubscriptionMet
48
49
  params?: ParamsOf<TSchema> | (() => ParamsOf<TSchema>);
49
50
 
50
51
  /**
51
- * whether to validate incoming messages against the schema
52
+ * whether to validate incoming events against the schema
52
53
  * @default true
53
54
  */
54
- validateMessages?: boolean;
55
+ validateEvents?: boolean;
55
56
 
56
57
  onConnectionOpen?: (event: Event) => void;
57
58
  onConnectionClose?: (event: CloseEvent) => void;
58
59
  onConnectionError?: (event: ErrorEvent) => void;
59
- onError?: (error: string, message?: string) => void;
60
+ /**
61
+ * called for non-fatal frame-level errors: atproto error frames (passed as `FirehoseError`)
62
+ * and message validation failures (passed as `ValidationError`).
63
+ */
64
+ onError?: (err: unknown) => void;
60
65
 
61
66
  /**
62
67
  * WebSocket connection options
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
- "type": "module",
3
2
  "name": "@atcute/firehose",
4
- "version": "0.1.0",
3
+ "version": "1.0.0",
5
4
  "description": "lightweight and cute XRPC subscription client for AT Protocol",
6
5
  "license": "0BSD",
7
6
  "repository": {
@@ -12,25 +11,33 @@
12
11
  "dist/",
13
12
  "lib/",
14
13
  "!lib/**/*.bench.ts",
15
- "!lib/**/*.test.ts"
14
+ "!lib/**/*.test.ts",
15
+ "!dist/**/*.{test,bench}.*"
16
16
  ],
17
+ "type": "module",
17
18
  "exports": {
18
19
  ".": "./dist/index.js"
19
20
  },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
20
24
  "dependencies": {
21
25
  "@mary-ext/event-iterator": "^1.0.0",
22
- "@mary-ext/simple-event-emitter": "^1.0.0",
23
- "partysocket": "^1.1.6",
26
+ "@mary-ext/simple-event-emitter": "^1.0.1",
27
+ "partysocket": "^1.1.18",
24
28
  "type-fest": "^4.41.0",
25
- "@atcute/lexicons": "^1.2.2",
26
- "@atcute/cbor": "^2.2.7",
27
- "@atcute/uint8array": "^1.0.5"
29
+ "@atcute/cbor": "^2.3.3",
30
+ "@atcute/lexicons": "^2.0.0",
31
+ "@atcute/uint8array": "^1.1.1"
28
32
  },
29
33
  "devDependencies": {
30
- "@atcute/atproto": "^3.1.8"
34
+ "@atcute/atproto": "^4.0.0"
35
+ },
36
+ "peerDependencies": {
37
+ "@atcute/lexicons": "^2.0.0"
31
38
  },
32
39
  "scripts": {
33
- "build": "tsc --project tsconfig.build.json",
40
+ "build": "tsgo",
34
41
  "prepublish": "rm -rf dist; pnpm run build"
35
42
  }
36
43
  }