@atcute/xrpc-server-deno 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,17 +1,24 @@
1
1
  # @atcute/xrpc-server-deno
2
2
 
3
- Deno WebSocket adapter for `@atcute/xrpc-server`.
3
+ Deno WebSocket adapter for [`@atcute/xrpc-server`](../xrpc-server/).
4
+
5
+ ```sh
6
+ deno add npm:@atcute/xrpc-server-deno
7
+ ```
8
+
9
+ see the [subscriptions section](../xrpc-server/#subscriptions) in the main package for usage
10
+ details.
4
11
 
5
12
  ```ts
6
13
  import { XRPCRouter } from '@atcute/xrpc-server';
7
14
  import { createDenoWebSocket } from '@atcute/xrpc-server-deno';
8
15
 
9
- import { ComAtprotoSyncSubscribeRepos } from './lexicons/index.ts';
16
+ import { ComExampleSubscribe } from './lexicons/index.ts';
10
17
 
11
18
  const adapter = createDenoWebSocket();
12
19
  const router = new XRPCRouter({ websocket: adapter });
13
20
 
14
- router.addSubscription(ComAtprotoSyncSubscribeRepos.mainSchema, {
21
+ router.addSubscription(ComExampleSubscribe.mainSchema, {
15
22
  async *handler({ params, signal }) {
16
23
  while (!signal.aborted) {
17
24
  yield {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,9 @@
1
1
  import type { WebSocketAdapter } from '@atcute/xrpc-server';
2
- export declare const createDenoWebSocket: () => WebSocketAdapter;
2
+ export interface CreateDenoWebSocketOptions {
3
+ /** backpressure high water mark in bytes; defaults to 250 KB. */
4
+ highWaterMark?: number;
5
+ /** backpressure low water mark in bytes; defaults to 50 KB. */
6
+ lowWaterMark?: number;
7
+ }
8
+ export declare const createDenoWebSocket: ({ highWaterMark, lowWaterMark, }?: CreateDenoWebSocketOptions) => WebSocketAdapter;
3
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAuB,MAAM,qBAAqB,CAAC;AAEjF,eAAO,MAAM,mBAAmB,QAAO,gBA2BtC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAuB,MAAM,qBAAqB,CAAC;AAEjF,MAAM,WAAW,0BAA0B;IAC1C,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,sCAG7B,0BAA0B,KAAQ,gBAyCpC,CAAC"}
package/dist/index.js CHANGED
@@ -1,13 +1,24 @@
1
- export const createDenoWebSocket = () => {
1
+ export const createDenoWebSocket = ({ highWaterMark = 250_000, lowWaterMark = 50_000, } = {}) => {
2
2
  return {
3
3
  async upgrade(request, handler) {
4
4
  const { response, socket } = Deno.upgradeWebSocket(request);
5
5
  const controller = new AbortController();
6
+ const signal = controller.signal;
6
7
  const connection = {
7
- signal: controller.signal,
8
+ signal: signal,
8
9
  send(data) {
9
10
  socket.send(data);
10
11
  },
12
+ async drain() {
13
+ if (socket.bufferedAmount <= highWaterMark) {
14
+ return;
15
+ }
16
+ while (!signal.aborted &&
17
+ socket.readyState === WebSocket.OPEN &&
18
+ socket.bufferedAmount > lowWaterMark) {
19
+ await sleep(10, signal);
20
+ }
21
+ },
11
22
  close(code, reason) {
12
23
  socket.close(code, reason);
13
24
  },
@@ -22,4 +33,17 @@ export const createDenoWebSocket = () => {
22
33
  },
23
34
  };
24
35
  };
36
+ const sleep = (ms, signal) => {
37
+ return new Promise((resolve) => {
38
+ const timer = setTimeout(() => {
39
+ signal.removeEventListener('abort', onAbort);
40
+ resolve();
41
+ }, ms);
42
+ const onAbort = () => {
43
+ clearTimeout(timer);
44
+ resolve();
45
+ };
46
+ signal.addEventListener('abort', onAbort, { once: true });
47
+ });
48
+ };
25
49
  //# 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":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAqB,EAAE;IACzD,OAAO;QACN,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO;YAC7B,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAE5D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,UAAU,GAAwB;gBACvC,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,IAAI,CAAC,IAAgB;oBACpB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACnB,CAAC;gBACD,KAAK,CAAC,IAAa,EAAE,MAAe;oBACnC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC5B,CAAC;aACD,CAAC;YAEF,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;gBACpB,OAAO,CAAC,UAAU,CAAC,CAAC;YACrB,CAAC,CAAC;YAEF,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,EAAE,EAAE;gBACvB,UAAU,CAAC,KAAK,CAAC,yCAAyC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YACtE,CAAC,CAAC;YAEF,OAAO,QAAQ,CAAC;QACjB,CAAC;KACD,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EACnC,aAAa,GAAG,OAAO,EACvB,YAAY,GAAG,MAAM,GACrB,GAA+B,EAAE,EAAoB,EAAE;IACvD,OAAO;QACN,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO;YAC7B,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAE5D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;YACjC,MAAM,UAAU,GAAwB;gBACvC,MAAM,EAAE,MAAM;gBACd,IAAI,CAAC,IAAgB;oBACpB,MAAM,CAAC,IAAI,CAAC,IAA+B,CAAC,CAAC;gBAC9C,CAAC;gBACD,KAAK,CAAC,KAAK;oBACV,IAAI,MAAM,CAAC,cAAc,IAAI,aAAa,EAAE,CAAC;wBAC5C,OAAO;oBACR,CAAC;oBAED,OACC,CAAC,MAAM,CAAC,OAAO;wBACf,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;wBACpC,MAAM,CAAC,cAAc,GAAG,YAAY,EACnC,CAAC;wBACF,MAAM,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;oBACzB,CAAC;gBACF,CAAC;gBACD,KAAK,CAAC,IAAa,EAAE,MAAe;oBACnC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC5B,CAAC;aACD,CAAC;YAEF,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;gBACpB,OAAO,CAAC,UAAU,CAAC,CAAC;YACrB,CAAC,CAAC;YAEF,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,EAAE,EAAE;gBACvB,UAAU,CAAC,KAAK,CAAC,yCAAyC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YACtE,CAAC,CAAC;YAEF,OAAO,QAAQ,CAAC;QACjB,CAAC;KACD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,MAAmB,EAAiB,EAAE;IAChE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,EAAE,CAAC;QACX,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,MAAM,OAAO,GAAG,GAAG,EAAE;YACpB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;QACX,CAAC,CAAC;QAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC"}
package/lib/index.ts CHANGED
@@ -1,15 +1,39 @@
1
1
  import type { WebSocketAdapter, WebSocketConnection } from '@atcute/xrpc-server';
2
2
 
3
- export const createDenoWebSocket = (): WebSocketAdapter => {
3
+ export interface CreateDenoWebSocketOptions {
4
+ /** backpressure high water mark in bytes; defaults to 250 KB. */
5
+ highWaterMark?: number;
6
+ /** backpressure low water mark in bytes; defaults to 50 KB. */
7
+ lowWaterMark?: number;
8
+ }
9
+
10
+ export const createDenoWebSocket = ({
11
+ highWaterMark = 250_000,
12
+ lowWaterMark = 50_000,
13
+ }: CreateDenoWebSocketOptions = {}): WebSocketAdapter => {
4
14
  return {
5
15
  async upgrade(request, handler) {
6
16
  const { response, socket } = Deno.upgradeWebSocket(request);
7
17
 
8
18
  const controller = new AbortController();
19
+ const signal = controller.signal;
9
20
  const connection: WebSocketConnection = {
10
- signal: controller.signal,
21
+ signal: signal,
11
22
  send(data: Uint8Array) {
12
- socket.send(data);
23
+ socket.send(data as Uint8Array<ArrayBuffer>);
24
+ },
25
+ async drain() {
26
+ if (socket.bufferedAmount <= highWaterMark) {
27
+ return;
28
+ }
29
+
30
+ while (
31
+ !signal.aborted &&
32
+ socket.readyState === WebSocket.OPEN &&
33
+ socket.bufferedAmount > lowWaterMark
34
+ ) {
35
+ await sleep(10, signal);
36
+ }
13
37
  },
14
38
  close(code?: number, reason?: string) {
15
39
  socket.close(code, reason);
@@ -28,3 +52,19 @@ export const createDenoWebSocket = (): WebSocketAdapter => {
28
52
  },
29
53
  };
30
54
  };
55
+
56
+ const sleep = (ms: number, signal: AbortSignal): Promise<void> => {
57
+ return new Promise((resolve) => {
58
+ const timer = setTimeout(() => {
59
+ signal.removeEventListener('abort', onAbort);
60
+ resolve();
61
+ }, ms);
62
+
63
+ const onAbort = () => {
64
+ clearTimeout(timer);
65
+ resolve();
66
+ };
67
+
68
+ signal.addEventListener('abort', onAbort, { once: true });
69
+ });
70
+ };
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
- "type": "module",
3
2
  "name": "@atcute/xrpc-server-deno",
4
- "version": "0.1.0",
3
+ "version": "1.0.0",
5
4
  "description": "Deno WebSocket adapter for @atcute/xrpc-server",
6
5
  "license": "0BSD",
7
6
  "repository": {
@@ -12,19 +11,24 @@
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
  },
20
- "peerDependencies": {
21
- "@atcute/xrpc-server": "^0.1.3"
21
+ "publishConfig": {
22
+ "access": "public"
22
23
  },
23
24
  "devDependencies": {
24
25
  "@types/deno": "^2.5.0"
25
26
  },
27
+ "peerDependencies": {
28
+ "@atcute/xrpc-server": "^1.0.0"
29
+ },
26
30
  "scripts": {
27
- "build": "tsc --project tsconfig.build.json",
31
+ "build": "tsgo",
28
32
  "prepublish": "rm -rf dist; pnpm run build"
29
33
  }
30
34
  }