@atcute/xrpc-server 0.1.2 → 0.1.4

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.
Files changed (72) hide show
  1. package/README.md +206 -28
  2. package/dist/auth/jwt-creator.d.ts.map +1 -1
  3. package/dist/auth/jwt-creator.js.map +1 -1
  4. package/dist/auth/jwt-verifier.d.ts.map +1 -1
  5. package/dist/auth/jwt-verifier.js.map +1 -1
  6. package/dist/auth/jwt.d.ts +10 -15
  7. package/dist/auth/jwt.d.ts.map +1 -1
  8. package/dist/auth/jwt.js.map +1 -1
  9. package/dist/main/index.d.ts +2 -0
  10. package/dist/main/index.d.ts.map +1 -1
  11. package/dist/main/index.js +2 -0
  12. package/dist/main/index.js.map +1 -1
  13. package/dist/main/response.js.map +1 -1
  14. package/dist/main/router.d.ts +15 -5
  15. package/dist/main/router.d.ts.map +1 -1
  16. package/dist/main/router.js +103 -16
  17. package/dist/main/router.js.map +1 -1
  18. package/dist/main/types/operation.d.ts +16 -1
  19. package/dist/main/types/operation.d.ts.map +1 -1
  20. package/dist/main/types/websocket.d.ts +10 -0
  21. package/dist/main/types/websocket.d.ts.map +1 -0
  22. package/dist/main/types/websocket.js +2 -0
  23. package/dist/main/types/websocket.js.map +1 -0
  24. package/dist/main/utils/event-emitter.d.ts +37 -0
  25. package/dist/main/utils/event-emitter.d.ts.map +1 -0
  26. package/dist/main/utils/event-emitter.js +96 -0
  27. package/dist/main/utils/event-emitter.js.map +1 -0
  28. package/dist/main/utils/frames.d.ts +5 -0
  29. package/dist/main/utils/frames.d.ts.map +1 -0
  30. package/dist/main/utils/frames.js +45 -0
  31. package/dist/main/utils/frames.js.map +1 -0
  32. package/dist/main/utils/middlewares.d.ts.map +1 -1
  33. package/dist/main/utils/middlewares.js.map +1 -1
  34. package/dist/main/utils/namespaced.d.ts +5 -0
  35. package/dist/main/utils/namespaced.d.ts.map +1 -0
  36. package/dist/main/utils/namespaced.js +4 -0
  37. package/dist/main/utils/namespaced.js.map +1 -0
  38. package/dist/main/utils/request-input.d.ts +1 -1
  39. package/dist/main/utils/request-input.d.ts.map +1 -1
  40. package/dist/main/utils/request-input.js.map +1 -1
  41. package/dist/main/utils/request-params.d.ts +1 -1
  42. package/dist/main/utils/request-params.d.ts.map +1 -1
  43. package/dist/main/utils/request-params.js.map +1 -1
  44. package/dist/main/utils/response.d.ts +1 -1
  45. package/dist/main/utils/response.d.ts.map +1 -1
  46. package/dist/main/utils/response.js.map +1 -1
  47. package/dist/main/utils/websocket-mock.d.ts +24 -0
  48. package/dist/main/utils/websocket-mock.d.ts.map +1 -0
  49. package/dist/main/utils/websocket-mock.js +71 -0
  50. package/dist/main/utils/websocket-mock.js.map +1 -0
  51. package/dist/main/xrpc-error.d.ts +12 -1
  52. package/dist/main/xrpc-error.d.ts.map +1 -1
  53. package/dist/main/xrpc-error.js +11 -0
  54. package/dist/main/xrpc-error.js.map +1 -1
  55. package/dist/main/xrpc-handler.d.ts +23 -0
  56. package/dist/main/xrpc-handler.d.ts.map +1 -0
  57. package/dist/main/xrpc-handler.js +19 -0
  58. package/dist/main/xrpc-handler.js.map +1 -0
  59. package/dist/middlewares/cors.d.ts.map +1 -1
  60. package/dist/middlewares/cors.js.map +1 -1
  61. package/lib/auth/jwt.ts +16 -5
  62. package/lib/main/index.ts +3 -0
  63. package/lib/main/router.ts +158 -23
  64. package/lib/main/types/operation.ts +33 -0
  65. package/lib/main/types/websocket.ts +14 -0
  66. package/lib/main/utils/event-emitter.ts +116 -0
  67. package/lib/main/utils/frames.ts +71 -0
  68. package/lib/main/utils/namespaced.ts +5 -0
  69. package/lib/main/utils/websocket-mock.ts +111 -0
  70. package/lib/main/xrpc-error.ts +20 -0
  71. package/lib/main/xrpc-handler.ts +54 -0
  72. package/package.json +17 -12
@@ -0,0 +1,24 @@
1
+ import type { Promisable } from '../../types/misc.js';
2
+ import type { XRPCRouter } from '../router.js';
3
+ import type { WebSocketAdapter, WebSocketConnection } from '../types/websocket.js';
4
+ import { EventEmitter } from './event-emitter.js';
5
+ export interface SubscriptionClient extends Disposable {
6
+ events: EventEmitter<{
7
+ message: [data: Uint8Array];
8
+ close: [event: {
9
+ code: number;
10
+ reason: string;
11
+ wasClean: boolean;
12
+ }];
13
+ }>;
14
+ dispose(): void;
15
+ }
16
+ export interface SubscriptionMock {
17
+ subscribe(url: string): Promise<SubscriptionClient>;
18
+ }
19
+ export declare class MockWebSocketAdapter implements WebSocketAdapter {
20
+ #private;
21
+ upgrade(_request: Request, handler: (ws: WebSocketConnection) => Promisable<void>): Promisable<Response | undefined>;
22
+ attach(router: XRPCRouter): SubscriptionMock;
23
+ }
24
+ //# sourceMappingURL=websocket-mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-mock.d.ts","sourceRoot":"","sources":["../../../lib/main/utils/websocket-mock.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMlD,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACrD,MAAM,EAAE,YAAY,CAAC;QACpB,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC5B,KAAK,EAAE,CAAC,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KACpE,CAAC,CAAC;IACH,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACpD;AAED,qBAAa,oBAAqB,YAAW,gBAAgB;;IAG5D,OAAO,CACN,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,CAAC,EAAE,EAAE,mBAAmB,KAAK,UAAU,CAAC,IAAI,CAAC,GACpD,UAAU,CAAC,QAAQ,GAAG,SAAS,CAAC,CASlC;IAED,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,CAqE3C;CACD"}
@@ -0,0 +1,71 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { EventEmitter } from './event-emitter.js';
3
+ export class MockWebSocketAdapter {
4
+ #context = new AsyncLocalStorage();
5
+ upgrade(_request, handler) {
6
+ const ctx = this.#context.getStore();
7
+ if (!ctx) {
8
+ return undefined;
9
+ }
10
+ ctx.handler = handler;
11
+ return new Response(null);
12
+ }
13
+ attach(router) {
14
+ return {
15
+ subscribe: async (url) => {
16
+ const ctx = {
17
+ handler: null,
18
+ };
19
+ await this.#context.run(ctx, async () => {
20
+ const urlp = new URL(url, 'http://localhost');
21
+ const request = new Request(urlp, {
22
+ headers: {
23
+ upgrade: 'websocket',
24
+ connection: 'upgrade',
25
+ },
26
+ });
27
+ const response = await router.fetch(request);
28
+ return response;
29
+ });
30
+ if (!ctx.handler) {
31
+ throw new Error(`WebSocket upgrade succeeded but no handler was set`);
32
+ }
33
+ const events = new EventEmitter();
34
+ const controller = new AbortController();
35
+ const signal = controller.signal;
36
+ const connection = {
37
+ signal: signal,
38
+ send(data) {
39
+ events.emit('message', data);
40
+ },
41
+ close(code = 1000, reason = '') {
42
+ if (!signal.aborted) {
43
+ events.emit('close', { code, reason, wasClean: true });
44
+ controller.abort();
45
+ }
46
+ },
47
+ };
48
+ {
49
+ const handler = ctx.handler;
50
+ setTimeout(() => {
51
+ handler(connection);
52
+ }, 1);
53
+ }
54
+ const client = {
55
+ events,
56
+ dispose() {
57
+ if (!signal.aborted) {
58
+ events.emit('close', { code: 1000, reason: '', wasClean: true });
59
+ controller.abort();
60
+ }
61
+ },
62
+ [Symbol.dispose]() {
63
+ this.dispose();
64
+ },
65
+ };
66
+ return client;
67
+ },
68
+ };
69
+ }
70
+ }
71
+ //# sourceMappingURL=websocket-mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-mock.js","sourceRoot":"","sources":["../../../lib/main/utils/websocket-mock.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ export declare class InvalidRequestError extends XRPCError {
17
17
  constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
18
18
  }
19
19
  export declare class AuthRequiredError extends XRPCError {
20
- constructor({ status, error, description, }?: Partial<XRPCErrorOptions>);
20
+ constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
21
21
  }
22
22
  export declare class ForbiddenError extends XRPCError {
23
23
  constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
@@ -37,4 +37,15 @@ export declare class NotEnoughResourcesError extends XRPCError {
37
37
  export declare class UpstreamTimeoutError extends XRPCError {
38
38
  constructor({ status, error, description }?: Partial<XRPCErrorOptions>);
39
39
  }
40
+ export interface XRPCSubscriptionErrorOptions {
41
+ closeCode?: number;
42
+ error: string;
43
+ description?: string;
44
+ }
45
+ export declare class XRPCSubscriptionError extends Error {
46
+ readonly closeCode: number;
47
+ readonly error: string;
48
+ readonly description?: string;
49
+ constructor({ closeCode, error, description }: XRPCSubscriptionErrorOptions);
50
+ }
40
51
  //# sourceMappingURL=xrpc-error.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"xrpc-error.d.ts","sourceRoot":"","sources":["../../lib/main/xrpc-error.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,SAAU,SAAQ,KAAK;IACnC,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,iBAAiB;IACjB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;gBAElB,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,gBAAgB;IAS5D,UAAU,IAAI,QAAQ;CAGtB;AAED,qBAAa,mBAAoB,SAAQ,SAAS;gBACrC,EAAE,MAAY,EAAE,KAAwB,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM;CAGnG;AAED,qBAAa,iBAAkB,SAAQ,SAAS;gBACnC,EACX,MAAY,EACZ,KAAgC,EAChC,WAAW,GACX,GAAE,OAAO,CAAC,gBAAgB,CAAM;CAGjC;AAED,qBAAa,cAAe,SAAQ,SAAS;gBAChC,EAAE,MAAY,EAAE,KAAmB,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM;CAG9F;AAED,qBAAa,sBAAuB,SAAQ,SAAS;gBACxC,EAAE,MAAY,EAAE,KAA2B,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM;CAGtG;AAED,qBAAa,mBAAoB,SAAQ,SAAS;gBACrC,EAAE,MAAY,EAAE,KAA6B,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM;CAGxG;AAED,qBAAa,oBAAqB,SAAQ,SAAS;gBACtC,EAAE,MAAY,EAAE,KAAyB,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM;CAGpG;AAED,qBAAa,uBAAwB,SAAQ,SAAS;gBACzC,EAAE,MAAY,EAAE,KAA4B,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM;CAGvG;AAED,qBAAa,oBAAqB,SAAQ,SAAS;gBACtC,EAAE,MAAY,EAAE,KAAyB,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM;CAGpG"}
1
+ {"version":3,"file":"xrpc-error.d.ts","sourceRoot":"","sources":["../../lib/main/xrpc-error.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,SAAU,SAAQ,KAAK;IACnC,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,iBAAiB;IACjB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,gBAAgB,EAO3D;IAED,UAAU,IAAI,QAAQ,CAErB;CACD;AAED,qBAAa,mBAAoB,SAAQ,SAAS;IACjD,YAAY,EAAE,MAAY,EAAE,KAAwB,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM,EAElG;CACD;AAED,qBAAa,iBAAkB,SAAQ,SAAS;IAC/C,YAAY,EACX,MAAY,EACZ,KAAgC,EAChC,WAAW,EACX,GAAE,OAAO,CAAC,gBAAgB,CAAM,EAEhC;CACD;AAED,qBAAa,cAAe,SAAQ,SAAS;IAC5C,YAAY,EAAE,MAAY,EAAE,KAAmB,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM,EAE7F;CACD;AAED,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,YAAY,EAAE,MAAY,EAAE,KAA2B,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM,EAErG;CACD;AAED,qBAAa,mBAAoB,SAAQ,SAAS;IACjD,YAAY,EAAE,MAAY,EAAE,KAA6B,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM,EAEvG;CACD;AAED,qBAAa,oBAAqB,SAAQ,SAAS;IAClD,YAAY,EAAE,MAAY,EAAE,KAAyB,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM,EAEnG;CACD;AAED,qBAAa,uBAAwB,SAAQ,SAAS;IACrD,YAAY,EAAE,MAAY,EAAE,KAA4B,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM,EAEtG;CACD;AAED,qBAAa,oBAAqB,SAAQ,SAAS;IAClD,YAAY,EAAE,MAAY,EAAE,KAAyB,EAAE,WAAW,EAAE,GAAE,OAAO,CAAC,gBAAgB,CAAM,EAEnG;CACD;AAED,MAAM,WAAW,4BAA4B;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B,YAAY,EAAE,SAAgB,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,4BAA4B,EAMjF;CACD"}
@@ -55,4 +55,15 @@ export class UpstreamTimeoutError extends XRPCError {
55
55
  super({ status, error, description });
56
56
  }
57
57
  }
58
+ export class XRPCSubscriptionError extends Error {
59
+ closeCode;
60
+ error;
61
+ description;
62
+ constructor({ closeCode = 1008, error, description }) {
63
+ super(`Subscription error: ${error}${description ? ` - ${description}` : ''}`);
64
+ this.closeCode = closeCode;
65
+ this.error = error;
66
+ this.description = description;
67
+ }
68
+ }
58
69
  //# sourceMappingURL=xrpc-error.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"xrpc-error.js","sourceRoot":"","sources":["../../lib/main/xrpc-error.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,SAAU,SAAQ,KAAK;IACnC,sBAAsB;IACb,MAAM,CAAS;IAExB,iBAAiB;IACR,KAAK,CAAS;IACvB,oBAAoB;IACX,WAAW,CAAU;IAE9B,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAoB;QAC3D,KAAK,CAAC,GAAG,KAAK,MAAM,WAAW,IAAI,2BAA2B,EAAE,CAAC,CAAC;QAElE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,CAAC;IAED,UAAU;QACT,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACjG,CAAC;CACD;AAED,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IACjD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,gBAAgB,EAAE,WAAW,KAAgC,EAAE;QAClG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,iBAAkB,SAAQ,SAAS;IAC/C,YAAY,EACX,MAAM,GAAG,GAAG,EACZ,KAAK,GAAG,wBAAwB,EAChC,WAAW,MACmB,EAAE;QAChC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,cAAe,SAAQ,SAAS;IAC5C,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,WAAW,EAAE,WAAW,KAAgC,EAAE;QAC7F,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,sBAAuB,SAAQ,SAAS;IACpD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,mBAAmB,EAAE,WAAW,KAAgC,EAAE;QACrG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IACjD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,qBAAqB,EAAE,WAAW,KAAgC,EAAE;QACvG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,oBAAqB,SAAQ,SAAS;IAClD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,iBAAiB,EAAE,WAAW,KAAgC,EAAE;QACnG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,uBAAwB,SAAQ,SAAS;IACrD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,oBAAoB,EAAE,WAAW,KAAgC,EAAE;QACtG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD;AAED,MAAM,OAAO,oBAAqB,SAAQ,SAAS;IAClD,YAAY,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAAG,iBAAiB,EAAE,WAAW,KAAgC,EAAE;QACnG,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACvC,CAAC;CACD"}
1
+ {"version":3,"file":"xrpc-error.js","sourceRoot":"","sources":["../../lib/main/xrpc-error.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { XRPCProcedureMetadata, XRPCQueryMetadata } from '@atcute/lexicons/validations';
2
+ import { type XRPCRouterOptions } from './router.js';
3
+ import type { ProcedureConfig, QueryConfig } from './types/operation.js';
4
+ import { type Namespaced } from './utils/namespaced.js';
5
+ type XrpcHandlerRouterOptions = Pick<XRPCRouterOptions, 'middlewares' | 'handleNotFound' | 'handleException'>;
6
+ export type XrpcQueryHandlerOptions<TQuery extends XRPCQueryMetadata> = {
7
+ lxm: TQuery | Namespaced<TQuery>;
8
+ routerOptions?: XrpcHandlerRouterOptions;
9
+ } & QueryConfig<TQuery>;
10
+ export type XrpcProcedureHandlerOptions<TProcedure extends XRPCProcedureMetadata> = {
11
+ lxm: TProcedure | Namespaced<TProcedure>;
12
+ routerOptions?: XrpcHandlerRouterOptions;
13
+ } & ProcedureConfig<TProcedure>;
14
+ export type XrpcHandlerOptions = XrpcQueryHandlerOptions<XRPCQueryMetadata> | XrpcProcedureHandlerOptions<XRPCProcedureMetadata>;
15
+ /**
16
+ * create a fetch handler for a single xrpc query or procedure.
17
+ * requests are expected at `/xrpc/<nsid>`.
18
+ * subscriptions are not supported.
19
+ */
20
+ export declare function createXrpcHandler<TQuery extends XRPCQueryMetadata>(options: XrpcQueryHandlerOptions<TQuery>): (request: Request) => Promise<Response>;
21
+ export declare function createXrpcHandler<TProcedure extends XRPCProcedureMetadata>(options: XrpcProcedureHandlerOptions<TProcedure>): (request: Request) => Promise<Response>;
22
+ export {};
23
+ //# sourceMappingURL=xrpc-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xrpc-handler.d.ts","sourceRoot":"","sources":["../../lib/main/xrpc-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAE7F,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnE,KAAK,wBAAwB,GAAG,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,gBAAgB,GAAG,iBAAiB,CAAC,CAAC;AAE9G,MAAM,MAAM,uBAAuB,CAAC,MAAM,SAAS,iBAAiB,IAAI;IACvE,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,wBAAwB,CAAC;CACzC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAExB,MAAM,MAAM,2BAA2B,CAAC,UAAU,SAAS,qBAAqB,IAC/E;IACC,GAAG,EAAE,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,wBAAwB,CAAC;CACzC,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;AAEjC,MAAM,MAAM,kBAAkB,GAC3B,uBAAuB,CAAC,iBAAiB,CAAC,GAC1C,2BAA2B,CAAC,qBAAqB,CAAC,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,iBAAiB,EACjE,OAAO,EAAE,uBAAuB,CAAC,MAAM,CAAC,GACtC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC3C,wBAAgB,iBAAiB,CAAC,UAAU,SAAS,qBAAqB,EACzE,OAAO,EAAE,2BAA2B,CAAC,UAAU,CAAC,GAC9C,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { XRPCRouter } from './router.js';
2
+ import { unwrapLxm } from './utils/namespaced.js';
3
+ export function createXrpcHandler(options) {
4
+ const { lxm, handler, routerOptions } = options;
5
+ const router = new XRPCRouter(routerOptions);
6
+ const schema = unwrapLxm(lxm);
7
+ switch (schema.type) {
8
+ case 'xrpc_query': {
9
+ router.addQuery(schema, { handler: handler });
10
+ break;
11
+ }
12
+ case 'xrpc_procedure': {
13
+ router.addProcedure(schema, { handler: handler });
14
+ break;
15
+ }
16
+ }
17
+ return router.fetch;
18
+ }
19
+ //# sourceMappingURL=xrpc-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xrpc-handler.js","sourceRoot":"","sources":["../../lib/main/xrpc-handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAA0B,MAAM,aAAa,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAmB,MAAM,uBAAuB,CAAC;AA8BnE,MAAM,UAAU,iBAAiB,CAAC,OAA2B,EAA2C;IACvG,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAEhD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAE9B,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,YAAY,EAAE,CAAC;YACnB,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,OAAoD,EAAE,CAAC,CAAC;YAC3F,MAAM;QACP,CAAC;QACD,KAAK,gBAAgB,EAAE,CAAC;YACvB,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,OAA4D,EAAE,CAAC,CAAC;YACvG,MAAM;QACP,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC,KAAK,CAAC;AAAA,CACpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../lib/middlewares/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC3B,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kCAAkC;IAClC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAsBD,eAAO,MAAM,IAAI,GAAI,UAAS,WAAgB,KAAG,eAsChD,CAAC"}
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../lib/middlewares/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC3B,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kCAAkC;IAClC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAsBD,eAAO,MAAM,IAAI,4CAsChB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"cors.js","sourceRoot":"","sources":["../../lib/middlewares/cors.ts"],"names":[],"mappings":"AASA,MAAM,uBAAuB,GAAG;IAC/B,YAAY;IACZ,kBAAkB;IAElB,iBAAiB;IACjB,kBAAkB;IAClB,qBAAqB;IACrB,iBAAiB;CACjB,CAAC;AAEF,MAAM,uBAAuB,GAAG;IAC/B,cAAc;IAEd,eAAe;IACf,MAAM;IAEN,yBAAyB;IACzB,eAAe;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,UAAuB,EAAE,EAAmB,EAAE;IAClE,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAChC,IAAI,GAAG,CAAC,CAAC,GAAG,uBAAuB,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CACrG,CAAC,IAAI,EAAE,CAAC;IAET,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAChC,IAAI,GAAG,CAAC,CAAC,GAAG,uBAAuB,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CACrG;SACC,IAAI,EAAE;SACN,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;QAEpD,4BAA4B;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YAEnD,IAAI,cAAc,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;YAC7D,CAAC;YAED,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QAErC,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/E,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;QAC5D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,QAAQ,CAAC;IACjB,CAAC,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"cors.js","sourceRoot":"","sources":["../../lib/middlewares/cors.ts"],"names":[],"mappings":"AASA,MAAM,uBAAuB,GAAG;IAC/B,YAAY;IACZ,kBAAkB;IAElB,iBAAiB;IACjB,kBAAkB;IAClB,qBAAqB;IACrB,iBAAiB;CACjB,CAAC;AAEF,MAAM,uBAAuB,GAAG;IAC/B,cAAc;IAEd,eAAe;IACf,MAAM;IAEN,yBAAyB;IACzB,eAAe;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,GAAgB,EAAE,EAAmB,EAAE,CAAC;IACnE,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAChC,IAAI,GAAG,CAAC,CAAC,GAAG,uBAAuB,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CACrG,CAAC,IAAI,EAAE,CAAC;IAET,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAChC,IAAI,GAAG,CAAC,CAAC,GAAG,uBAAuB,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CACrG;SACC,IAAI,EAAE;SACN,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;QAEpD,4BAA4B;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YAEnD,IAAI,cAAc,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;YAC7D,CAAC;YAED,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QAErC,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/E,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;QAC5D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,QAAQ,CAAC;IAAA,CAChB,CAAC;AAAA,CACF,CAAC"}
package/lib/auth/jwt.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as v from '@badrap/valita';
2
2
 
3
+ import type { Did, Nsid } from '@atcute/lexicons';
3
4
  import { isDid, isNsid } from '@atcute/lexicons/syntax';
4
5
  import { fromBase64Url } from '@atcute/multibase';
5
6
  import { decodeUtf8From, encodeUtf8 } from '@atcute/uint8array';
@@ -13,14 +14,26 @@ const nsidString = v.string().assert(isNsid, `must be an nsid`);
13
14
 
14
15
  const integer = v.number().assert((input) => input >= 0 && Number.isSafeInteger(input), `must be an integer`);
15
16
 
16
- const jwtHeader = v.object({
17
+ export interface JwtHeader {
18
+ typ?: string;
19
+ alg: string;
20
+ }
21
+
22
+ const jwtHeader: v.Type<JwtHeader> = v.object({
17
23
  typ: v.string().optional(),
18
24
  alg: v.string(),
19
25
  });
20
26
 
21
- export interface JwtHeader extends v.Infer<typeof jwtHeader> {}
27
+ export interface JwtPayload {
28
+ iss: Did;
29
+ aud: Did;
30
+ exp: number;
31
+ iat?: number;
32
+ lxm?: Nsid;
33
+ jti?: string;
34
+ }
22
35
 
23
- const jwtPayload = v
36
+ const jwtPayload: v.Type<JwtPayload> = v
24
37
  .object({
25
38
  /** issuer */
26
39
  iss: didString,
@@ -40,8 +53,6 @@ const jwtPayload = v
40
53
  path: ['exp'],
41
54
  });
42
55
 
43
- export interface JwtPayload extends v.Infer<typeof jwtPayload> {}
44
-
45
56
  export interface ParsedJwt {
46
57
  header: JwtHeader;
47
58
  payload: JwtPayload;
package/lib/main/index.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  export * from './response.js';
2
+ export * from './xrpc-handler.js';
2
3
  export * from './router.js';
3
4
  export * from './xrpc-error.js';
5
+
6
+ export * from './types/websocket.js';
@@ -1,14 +1,27 @@
1
- import { safeParse, type XRPCProcedureMetadata, type XRPCQueryMetadata } from '@atcute/lexicons/validations';
1
+ import {
2
+ safeParse,
3
+ type XRPCProcedureMetadata,
4
+ type XRPCQueryMetadata,
5
+ type XRPCSubscriptionMetadata,
6
+ } from '@atcute/lexicons/validations';
2
7
 
3
8
  import type { Literal, Promisable } from '../types/misc.js';
4
9
 
5
- import type { ProcedureConfig, QueryConfig, UnknownOperationContext } from './types/operation.js';
10
+ import type {
11
+ ProcedureConfig,
12
+ QueryConfig,
13
+ SubscriptionConfig,
14
+ UnknownOperationContext,
15
+ UnknownSubscriptionContext,
16
+ } from './types/operation.js';
17
+ import type { WebSocketAdapter } from './types/websocket.js';
18
+ import { encodeErrorFrame, encodeMessageFrame, extractMessageType, omitMessageType } from './utils/frames.js';
6
19
  import { createAsyncMiddlewareRunner, type Middleware } from './utils/middlewares.js';
20
+ import { unwrapLxm, type Namespaced } from './utils/namespaced.js';
7
21
  import { constructMimeValidator } from './utils/request-input.js';
8
22
  import { constructParamsHandler } from './utils/request-params.js';
9
23
  import { invalidRequest, validationError } from './utils/response.js';
10
-
11
- import { XRPCError } from './xrpc-error.js';
24
+ import { XRPCError, XRPCSubscriptionError } from './xrpc-error.js';
12
25
 
13
26
  type InternalRequestContext = {
14
27
  url: URL;
@@ -26,6 +39,7 @@ export type FetchMiddleware = Middleware<[request: Request], Promise<Response>>;
26
39
 
27
40
  export type NotFoundHandler = (request: Request) => Promisable<Response>;
28
41
  export type ExceptionHandler = (error: unknown, request: Request) => Promisable<Response>;
42
+ export type SubscriptionExceptionHandler = (error: unknown, request: Request) => void;
29
43
 
30
44
  export const defaultExceptionHandler: ExceptionHandler = (error: unknown) => {
31
45
  if (error instanceof XRPCError) {
@@ -46,16 +60,24 @@ export const defaultNotFoundHandler: NotFoundHandler = () => {
46
60
  return new Response('Not Found', { status: 404 });
47
61
  };
48
62
 
63
+ export const defaultSubscriptionExceptionHandler: SubscriptionExceptionHandler = (error: unknown) => {
64
+ throw error;
65
+ };
66
+
49
67
  export interface XRPCRouterOptions {
50
68
  middlewares?: FetchMiddleware[];
51
69
  handleNotFound?: NotFoundHandler;
52
70
  handleException?: ExceptionHandler;
71
+ handleSubscriptionException?: SubscriptionExceptionHandler;
72
+ websocket?: WebSocketAdapter;
53
73
  }
54
74
 
55
75
  export class XRPCRouter {
56
76
  #handlers: Record<string, InternalRouteData> = {};
57
77
  #handleNotFound: NotFoundHandler;
58
78
  #handleException: ExceptionHandler;
79
+ #handleSubscriptionException: SubscriptionExceptionHandler;
80
+ #websocket?: WebSocketAdapter;
59
81
 
60
82
  fetch: (request: Request) => Promise<Response>;
61
83
 
@@ -63,12 +85,16 @@ export class XRPCRouter {
63
85
  middlewares = [],
64
86
  handleException = defaultExceptionHandler,
65
87
  handleNotFound = defaultNotFoundHandler,
88
+ handleSubscriptionException = defaultSubscriptionExceptionHandler,
89
+ websocket,
66
90
  }: XRPCRouterOptions = {}) {
67
91
  const runner = createAsyncMiddlewareRunner([...middlewares, (request) => this.#dispatch(request)]);
68
92
 
69
93
  this.fetch = (request) => runner(request);
70
94
  this.#handleException = handleException;
71
95
  this.#handleNotFound = handleNotFound;
96
+ this.#handleSubscriptionException = handleSubscriptionException;
97
+ this.#websocket = websocket;
72
98
  }
73
99
 
74
100
  async #dispatch(request: Request): Promise<Response> {
@@ -80,8 +106,8 @@ export class XRPCRouter {
80
106
  }
81
107
 
82
108
  const nsid = pathname.slice('/xrpc/'.length);
83
- const route = this.#handlers[nsid];
84
109
 
110
+ const route = this.#handlers[nsid];
85
111
  if (route === undefined) {
86
112
  return this.#handleNotFound(request);
87
113
  }
@@ -105,28 +131,41 @@ export class XRPCRouter {
105
131
  }
106
132
  }
107
133
 
108
- add<TQuery extends XRPCQueryMetadata>(query: TQuery, config: QueryConfig<TQuery>): void;
134
+ /** @deprecated use `addQuery` and `addProcedure` instead */
135
+ add<TQuery extends XRPCQueryMetadata>(query: TQuery | Namespaced<TQuery>, config: QueryConfig<TQuery>): void;
109
136
  add<TProcedure extends XRPCProcedureMetadata>(
110
- procedure: TProcedure,
137
+ procedure: TProcedure | Namespaced<TProcedure>,
111
138
  config: ProcedureConfig<TProcedure>,
112
139
  ): void;
113
- add(operation: XRPCQueryMetadata | XRPCProcedureMetadata, config: any): void {
114
- switch (operation.type) {
140
+ add(
141
+ operation:
142
+ | XRPCQueryMetadata
143
+ | XRPCProcedureMetadata
144
+ | Namespaced<XRPCQueryMetadata | XRPCProcedureMetadata>,
145
+ config: any,
146
+ ): void {
147
+ const schema = unwrapLxm(operation);
148
+
149
+ switch (schema.type) {
115
150
  case 'xrpc_query': {
116
- return this.#addQuery(operation, config);
151
+ return this.addQuery(schema, config);
117
152
  }
118
153
  case 'xrpc_procedure': {
119
- return this.#addProcedure(operation, config);
154
+ return this.addProcedure(schema, config);
120
155
  }
121
156
  }
122
157
  }
123
158
 
124
- #addQuery<TQuery extends XRPCQueryMetadata>(query: TQuery, config: QueryConfig<TQuery>): void {
125
- const handleParams = query.params ? constructParamsHandler(query.params) : null;
159
+ addQuery<TQuery extends XRPCQueryMetadata, TConfig extends QueryConfig<TQuery>>(
160
+ query: TQuery | Namespaced<TQuery>,
161
+ config: TConfig,
162
+ ): void {
163
+ const querySchema = unwrapLxm(query);
164
+ const handleParams = querySchema.params ? constructParamsHandler(querySchema.params) : null;
126
165
 
127
166
  const handler = config.handler;
128
167
 
129
- this.#handlers[query.nsid] = {
168
+ this.#handlers[querySchema.nsid] = {
130
169
  method: 'GET',
131
170
  handler: async ({ request, url }) => {
132
171
  let params: Record<string, Literal | Literal[]>;
@@ -158,19 +197,20 @@ export class XRPCRouter {
158
197
  };
159
198
  }
160
199
 
161
- #addProcedure<TProcedure extends XRPCProcedureMetadata>(
162
- procedure: TProcedure,
163
- config: ProcedureConfig<TProcedure>,
200
+ addProcedure<TProcedure extends XRPCProcedureMetadata, TConfig extends ProcedureConfig<TProcedure>>(
201
+ procedure: TProcedure | Namespaced<TProcedure>,
202
+ config: TConfig,
164
203
  ): void {
165
- const handleParams = procedure.params ? constructParamsHandler(procedure.params) : null;
166
- const validateInputType = procedure.input ? constructMimeValidator(procedure.input) : null;
204
+ const procedureSchema = unwrapLxm(procedure);
205
+ const handleParams = procedureSchema.params ? constructParamsHandler(procedureSchema.params) : null;
206
+ const validateInputType = procedureSchema.input ? constructMimeValidator(procedureSchema.input) : null;
167
207
 
168
- const requiresInput = procedure.input !== null;
169
- const inputSchema = procedure.input?.type === 'lex' ? procedure.input.schema : null;
208
+ const requiresInput = procedureSchema.input !== null;
209
+ const inputSchema = procedureSchema.input?.type === 'lex' ? procedureSchema.input.schema : null;
170
210
 
171
211
  const handler = config.handler;
172
212
 
173
- this.#handlers[procedure.nsid] = {
213
+ this.#handlers[procedureSchema.nsid] = {
174
214
  method: 'POST',
175
215
  handler: async ({ request, url }) => {
176
216
  let params: Record<string, Literal | Literal[]>;
@@ -203,7 +243,7 @@ export class XRPCRouter {
203
243
  let raw: any;
204
244
  try {
205
245
  raw = await request.json();
206
- } catch (err) {
246
+ } catch {
207
247
  return invalidRequest(`invalid request body (failed to parse json)`);
208
248
  }
209
249
 
@@ -236,4 +276,99 @@ export class XRPCRouter {
236
276
  },
237
277
  };
238
278
  }
279
+
280
+ addSubscription<
281
+ TSubscription extends XRPCSubscriptionMetadata,
282
+ TConfig extends SubscriptionConfig<TSubscription>,
283
+ >(subscription: TSubscription | Namespaced<TSubscription>, config: TConfig): void {
284
+ const websocket = this.#websocket;
285
+ if (websocket === undefined) {
286
+ throw new Error(`WebSocket adapter not configured`);
287
+ }
288
+
289
+ const subscriptionSchema = unwrapLxm(subscription);
290
+ const nsid = subscriptionSchema.nsid;
291
+
292
+ const handleParams = subscriptionSchema.params
293
+ ? constructParamsHandler(subscriptionSchema.params)
294
+ : null;
295
+ const handler = config.handler;
296
+
297
+ this.#handlers[nsid] = {
298
+ method: 'GET',
299
+ handler: async ({ request, url }) => {
300
+ {
301
+ const con = request.headers.get('connection');
302
+ const req = request.headers.get('upgrade');
303
+ if (
304
+ con === null ||
305
+ req === null ||
306
+ con.toLowerCase() !== 'upgrade' ||
307
+ req.toLowerCase() !== 'websocket'
308
+ ) {
309
+ return invalidRequest(`invalid WebSocket upgrade`);
310
+ }
311
+ }
312
+
313
+ let params: Record<string, Literal | Literal[]>;
314
+
315
+ if (handleParams !== null) {
316
+ const result = handleParams(url.searchParams);
317
+ if (!result.ok) {
318
+ return validationError('params', result);
319
+ }
320
+
321
+ params = result.value;
322
+ } else {
323
+ params = {};
324
+ }
325
+
326
+ const upgrade = await websocket.upgrade(request, async (ws) => {
327
+ const signal = ws.signal;
328
+
329
+ const context: UnknownSubscriptionContext = {
330
+ request: request,
331
+ params: params,
332
+ signal: signal,
333
+ };
334
+
335
+ try {
336
+ for await (const message of handler(context)) {
337
+ if (signal.aborted) {
338
+ break;
339
+ }
340
+
341
+ const type = extractMessageType(message, nsid);
342
+ const body = omitMessageType(message);
343
+
344
+ const frame = encodeMessageFrame(body, type);
345
+ await ws.send(frame);
346
+ }
347
+
348
+ ws.close(1000);
349
+ } catch (err) {
350
+ if (err instanceof XRPCSubscriptionError) {
351
+ const frame = encodeErrorFrame(err.error, err.description);
352
+
353
+ try {
354
+ await ws.send(frame);
355
+ } catch {}
356
+
357
+ ws.close(err.closeCode, err.error);
358
+ return;
359
+ }
360
+
361
+ ws.close(1011, `internal server error`);
362
+ this.#handleSubscriptionException(err, request);
363
+ }
364
+ });
365
+
366
+ if (upgrade !== undefined) {
367
+ return upgrade;
368
+ }
369
+
370
+ return invalidRequest(`WebSocket upgrade failed`);
371
+ },
372
+ };
373
+ }
239
374
  }
@@ -1,10 +1,12 @@
1
1
  import type {
2
2
  InferOutput,
3
3
  ObjectSchema,
4
+ VariantSchema,
4
5
  XRPCBlobBodyParam,
5
6
  XRPCLexBodyParam,
6
7
  XRPCProcedureMetadata,
7
8
  XRPCQueryMetadata,
9
+ XRPCSubscriptionMetadata,
8
10
  } from '@atcute/lexicons/validations';
9
11
 
10
12
  import type { Literal, Promisable } from '../../types/misc.js';
@@ -85,3 +87,34 @@ export type ProcedureHandler<TProcedure extends XRPCProcedureMetadata> = (
85
87
  export type ProcedureConfig<TProcedure extends XRPCProcedureMetadata = XRPCProcedureMetadata> = {
86
88
  handler: ProcedureHandler<TProcedure>;
87
89
  };
90
+
91
+ // #region Subscription
92
+
93
+ export interface UnknownSubscriptionContext {
94
+ request: Request;
95
+ signal: AbortSignal;
96
+ params: Record<string, Literal | Literal[]>;
97
+ }
98
+
99
+ export type SubscriptionContext<TSubscription extends XRPCSubscriptionMetadata> = {
100
+ request: Request;
101
+ signal: AbortSignal;
102
+ } & (TSubscription['params'] extends ObjectSchema
103
+ ? {
104
+ params: InferOutput<TSubscription['params']>;
105
+ }
106
+ : {
107
+ // params
108
+ });
109
+
110
+ export type SubscriptionHandler<TSubscription extends XRPCSubscriptionMetadata> = (
111
+ context: SubscriptionContext<TSubscription>,
112
+ ) => AsyncIterable<
113
+ TSubscription['message'] extends ObjectSchema | VariantSchema<any>
114
+ ? InferOutput<TSubscription['message']>
115
+ : never
116
+ >;
117
+
118
+ export type SubscriptionConfig<TSubscription extends XRPCSubscriptionMetadata = XRPCSubscriptionMetadata> = {
119
+ handler: SubscriptionHandler<TSubscription>;
120
+ };
@@ -0,0 +1,14 @@
1
+ import type { Promisable } from '../../types/misc.js';
2
+
3
+ export interface WebSocketConnection {
4
+ signal: AbortSignal;
5
+ send(data: Uint8Array): void | Promise<void>;
6
+ close(code?: number, reason?: string): void;
7
+ }
8
+
9
+ export interface WebSocketAdapter {
10
+ upgrade(
11
+ request: Request,
12
+ handler: (ws: WebSocketConnection) => Promisable<void>,
13
+ ): Promisable<Response | undefined>;
14
+ }