@synnaxlabs/freighter 0.1.0 → 0.4.1

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 (89) hide show
  1. package/.eslintrc.cjs +18 -0
  2. package/LICENSE +4 -21
  3. package/dist/alamos.d.ts +3 -0
  4. package/{build/module/lib → dist}/errors.d.ts +17 -12
  5. package/dist/freighter.cjs.js +11828 -0
  6. package/dist/freighter.cjs.js.map +1 -0
  7. package/dist/freighter.es.js +11828 -0
  8. package/dist/freighter.es.js.map +1 -0
  9. package/dist/http.d.ts +20 -0
  10. package/dist/index.d.ts +8 -0
  11. package/dist/middleware.d.ts +48 -0
  12. package/{build/module/lib → dist}/stream.d.ts +12 -11
  13. package/dist/transport.d.ts +13 -0
  14. package/dist/unary.d.ts +16 -0
  15. package/dist/websocket.d.ts +24 -0
  16. package/package.json +30 -97
  17. package/src/alamos.ts +40 -0
  18. package/src/errors.spec.ts +94 -0
  19. package/src/errors.ts +205 -0
  20. package/src/http.spec.ts +67 -0
  21. package/src/http.ts +115 -0
  22. package/src/index.ts +26 -0
  23. package/src/middleware.ts +77 -0
  24. package/src/stream.ts +97 -0
  25. package/src/transport.ts +23 -0
  26. package/src/unary.ts +44 -0
  27. package/src/websocket.spec.ts +119 -0
  28. package/src/websocket.ts +203 -0
  29. package/tsconfig.json +10 -0
  30. package/tsconfig.vite.json +4 -0
  31. package/vite.config.ts +16 -0
  32. package/build/main/index.d.ts +0 -7
  33. package/build/main/index.js +0 -27
  34. package/build/main/lib/caseconv.d.ts +0 -2
  35. package/build/main/lib/caseconv.js +0 -14
  36. package/build/main/lib/encoder.d.ts +0 -60
  37. package/build/main/lib/encoder.js +0 -61
  38. package/build/main/lib/encoder.spec.js +0 -26
  39. package/build/main/lib/errors.d.ts +0 -77
  40. package/build/main/lib/errors.js +0 -171
  41. package/build/main/lib/errors.spec.js +0 -76
  42. package/build/main/lib/http.d.ts +0 -46
  43. package/build/main/lib/http.js +0 -99
  44. package/build/main/lib/http.spec.js +0 -49
  45. package/build/main/lib/runtime.d.ts +0 -5
  46. package/build/main/lib/runtime.js +0 -22
  47. package/build/main/lib/stream.d.ts +0 -75
  48. package/build/main/lib/stream.js +0 -3
  49. package/build/main/lib/unary.d.ts +0 -14
  50. package/build/main/lib/unary.js +0 -3
  51. package/build/main/lib/url.d.ts +0 -37
  52. package/build/main/lib/url.js +0 -57
  53. package/build/main/lib/url.spec.d.ts +0 -1
  54. package/build/main/lib/url.spec.js +0 -36
  55. package/build/main/lib/websocket.d.ts +0 -21
  56. package/build/main/lib/websocket.js +0 -154
  57. package/build/main/lib/ws.spec.d.ts +0 -1
  58. package/build/main/lib/ws.spec.js +0 -73
  59. package/build/module/index.d.ts +0 -7
  60. package/build/module/index.js +0 -6
  61. package/build/module/lib/caseconv.d.ts +0 -2
  62. package/build/module/lib/caseconv.js +0 -9
  63. package/build/module/lib/encoder.d.ts +0 -60
  64. package/build/module/lib/encoder.js +0 -51
  65. package/build/module/lib/encoder.spec.d.ts +0 -1
  66. package/build/module/lib/encoder.spec.js +0 -21
  67. package/build/module/lib/errors.js +0 -160
  68. package/build/module/lib/errors.spec.d.ts +0 -1
  69. package/build/module/lib/errors.spec.js +0 -71
  70. package/build/module/lib/http.d.ts +0 -46
  71. package/build/module/lib/http.js +0 -94
  72. package/build/module/lib/http.spec.d.ts +0 -1
  73. package/build/module/lib/http.spec.js +0 -44
  74. package/build/module/lib/runtime.d.ts +0 -5
  75. package/build/module/lib/runtime.js +0 -19
  76. package/build/module/lib/stream.js +0 -2
  77. package/build/module/lib/unary.d.ts +0 -14
  78. package/build/module/lib/unary.js +0 -2
  79. package/build/module/lib/url.d.ts +0 -37
  80. package/build/module/lib/url.js +0 -61
  81. package/build/module/lib/url.spec.d.ts +0 -1
  82. package/build/module/lib/url.spec.js +0 -31
  83. package/build/module/lib/websocket.d.ts +0 -21
  84. package/build/module/lib/websocket.js +0 -160
  85. package/build/module/lib/ws.spec.d.ts +0 -1
  86. package/build/module/lib/ws.spec.js +0 -69
  87. /package/{build/main/lib → dist}/errors.spec.d.ts +0 -0
  88. /package/{build/main/lib → dist}/http.spec.d.ts +0 -0
  89. /package/{build/main/lib/encoder.spec.d.ts → dist/websocket.spec.d.ts} +0 -0
@@ -0,0 +1,119 @@
1
+ // Copyright 2023 Synnax Labs, Inc.
2
+ //
3
+ // Use of this software is governed by the Business Source License included in the file
4
+ // licenses/BSL.txt.
5
+ //
6
+ // As of the Change Date specified in that file, in accordance with the Business Source
7
+ // License, use of this software will be governed by the Apache License, Version 2.0,
8
+ // included in the file licenses/APL.txt.
9
+
10
+ import { URL, binary } from "@synnaxlabs/x";
11
+ import { describe, expect, test } from "vitest";
12
+ import { z } from "zod";
13
+
14
+ import {
15
+ BaseTypedError,
16
+ EOF,
17
+ type TypedError,
18
+ registerError,
19
+ type ErrorPayload,
20
+ } from "@/errors";
21
+ import { type Context } from "@/middleware";
22
+ import { WebSocketClient } from "@/websocket";
23
+
24
+ const url = new URL({
25
+ host: "127.0.0.1",
26
+ port: 8080,
27
+ });
28
+
29
+ const MessageSchema = z.object({
30
+ id: z.number().optional(),
31
+ message: z.string().optional(),
32
+ });
33
+
34
+ const client = new WebSocketClient(url, new binary.JSONEncoderDecoder());
35
+
36
+ class MyCustomError extends BaseTypedError {
37
+ code: number;
38
+
39
+ constructor(message: string, code: number) {
40
+ super(message, "integration.error");
41
+ this.code = code;
42
+ }
43
+ }
44
+
45
+ const encodeTestError = (err: TypedError): ErrorPayload => {
46
+ if (!(err instanceof MyCustomError)) {
47
+ throw new Error("Unexpected error type");
48
+ }
49
+ return { type: "integration.error", data: `${err.code},${err.message}` };
50
+ };
51
+
52
+ const decodeTestError = (encoded: ErrorPayload): TypedError | null => {
53
+ if (encoded.type !== "integration.error") return null;
54
+ const [code, message] = encoded.data.split(",");
55
+ return new MyCustomError(message, parseInt(code, 10));
56
+ };
57
+
58
+ registerError({
59
+ encode: encodeTestError,
60
+ decode: decodeTestError,
61
+ });
62
+
63
+ describe("websocket", () => {
64
+ test("basic exchange", async () => {
65
+ const stream = await client.stream("stream/echo", MessageSchema, MessageSchema);
66
+ for (let i = 0; i < 10; i++) {
67
+ stream.send({ id: i, message: "hello" });
68
+ const [response, error] = await stream.receive();
69
+ expect(error).toBeNull();
70
+ expect(response?.id).toEqual(i + 1);
71
+ expect(response?.message).toEqual("hello");
72
+ }
73
+ stream.closeSend();
74
+ const [response, error] = await stream.receive();
75
+ expect(error).toEqual(new EOF());
76
+ expect(response).toBeNull();
77
+ });
78
+
79
+ test("receive message after close", async () => {
80
+ const stream = await client.stream(
81
+ "stream/sendMessageAfterClientClose",
82
+ MessageSchema,
83
+ MessageSchema,
84
+ );
85
+ stream.closeSend();
86
+ let [response, error] = await stream.receive();
87
+ expect(error).toBeNull();
88
+ expect(response?.id).toEqual(0);
89
+ expect(response?.message).toEqual("Close Acknowledged");
90
+ [, error] = await stream.receive();
91
+ expect(error).toEqual(new EOF());
92
+ });
93
+
94
+ test("receive error", async () => {
95
+ const stream = await client.stream(
96
+ "stream/receiveAndExitWithErr",
97
+ MessageSchema,
98
+ MessageSchema,
99
+ );
100
+ stream.send({ id: 0, message: "hello" });
101
+ const [response, error] = await stream.receive();
102
+ expect(error).toEqual(new MyCustomError("unexpected error", 1));
103
+ expect(response).toBeNull();
104
+ });
105
+
106
+ test("middleware", async () => {
107
+ const myClient = new WebSocketClient(url, new binary.JSONEncoderDecoder());
108
+ let c = 0;
109
+ myClient.use(async (md, next): Promise<[Context, Error | null]> => {
110
+ if (md.params !== undefined) {
111
+ c++;
112
+ md.params.Test = "test";
113
+ }
114
+ return await next(md);
115
+ });
116
+ await myClient.stream("stream/middlewareCheck", MessageSchema, MessageSchema);
117
+ expect(c).toEqual(1);
118
+ });
119
+ });
@@ -0,0 +1,203 @@
1
+ // Copyright 2023 Synnax Labs, Inc.
2
+ //
3
+ // Use of this software is governed by the Business Source License included in the file
4
+ // licenses/BSL.txt.
5
+ //
6
+ // As of the Change Date specified in that file, in accordance with the Business Source
7
+ // License, use of this software will be governed by the Apache License, Version 2.0,
8
+ // included in the file licenses/APL.txt.
9
+
10
+ import { runtime, type URL, buildQueryString, type binary } from "@synnaxlabs/x";
11
+ import { z } from "zod";
12
+
13
+ import { EOF, errorZ, StreamClosed, decodeError } from "@/errors";
14
+ import { CONTENT_TYPE_HEADER_KEY } from "@/http";
15
+ import { MiddlewareCollector, type Context } from "@/middleware";
16
+ import type { Stream, StreamClient } from "@/stream";
17
+
18
+ const resolveWebSocketConstructor = (): ((target: string) => WebSocket) => {
19
+ if (runtime.RUNTIME !== "node") return (t) => new WebSocket(t);
20
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
21
+ return (t) => new (require("ws").WebSocket)(t, { rejectUnauthorized: false });
22
+ };
23
+
24
+ const MessageSchema = z.object({
25
+ type: z.union([z.literal("data"), z.literal("close")]),
26
+ payload: z.unknown().optional(),
27
+ error: z.optional(errorZ),
28
+ });
29
+
30
+ type Message = z.infer<typeof MessageSchema>;
31
+
32
+ type ReceiveCallbacksQueue = Array<{
33
+ resolve: (msg: Message) => void;
34
+ reject: (reason: unknown) => void;
35
+ }>;
36
+
37
+ /** WebSocketStream is an implementation of Stream that is backed by a websocket. */
38
+ class WebSocketStream<RQ extends z.ZodTypeAny, RS extends z.ZodTypeAny = RQ>
39
+ implements Stream<RQ, RS>
40
+ {
41
+ private readonly encoder: binary.EncoderDecoder;
42
+ private readonly reqSchema: RQ;
43
+ private readonly resSchema: RS;
44
+ private readonly ws: WebSocket;
45
+ private serverClosed: Error | null;
46
+ private sendClosed: boolean;
47
+ private readonly receiveDataQueue: Message[] = [];
48
+ private readonly receiveCallbacksQueue: ReceiveCallbacksQueue = [];
49
+
50
+ constructor(
51
+ ws: WebSocket,
52
+ encoder: binary.EncoderDecoder,
53
+ reqSchema: RQ,
54
+ resSchema: RS,
55
+ ) {
56
+ this.encoder = encoder;
57
+ this.reqSchema = reqSchema;
58
+ this.resSchema = resSchema;
59
+ this.ws = ws;
60
+ this.sendClosed = false;
61
+ this.serverClosed = null;
62
+ this.listenForMessages();
63
+ }
64
+
65
+ /** Implements the Stream protocol */
66
+ send(req: z.input<RQ>): Error | null {
67
+ if (this.serverClosed != null) return new EOF();
68
+ if (this.sendClosed) throw new StreamClosed();
69
+ this.ws.send(this.encoder.encode({ type: "data", payload: req }));
70
+ return null;
71
+ }
72
+
73
+ /** Implements the Stream protocol */
74
+ async receive(): Promise<[z.output<RS> | null, Error | null]> {
75
+ if (this.serverClosed != null) return [null, this.serverClosed];
76
+ const msg = await this.receiveMsg();
77
+ if (msg.type === "close") {
78
+ if (msg.error == null) throw new Error("Message error must be defined");
79
+ this.serverClosed = decodeError(msg.error);
80
+ return [null, this.serverClosed];
81
+ }
82
+ return [this.resSchema.parse(msg.payload), null];
83
+ }
84
+
85
+ /** Implements the Stream protocol */
86
+ received(): boolean {
87
+ return this.receiveDataQueue.length !== 0;
88
+ }
89
+
90
+ /** Implements the Stream protocol */
91
+ closeSend(): void {
92
+ if (this.sendClosed || this.serverClosed != null) return undefined;
93
+ const msg: Message = { type: "close" };
94
+ try {
95
+ this.ws.send(this.encoder.encode(msg));
96
+ } finally {
97
+ this.sendClosed = true;
98
+ }
99
+ return undefined;
100
+ }
101
+
102
+ private async receiveMsg(): Promise<Message> {
103
+ const msg = this.receiveDataQueue.shift();
104
+ if (msg != null) return msg;
105
+ return await new Promise((resolve, reject) =>
106
+ this.receiveCallbacksQueue.push({ resolve, reject }),
107
+ );
108
+ }
109
+
110
+ private listenForMessages(): void {
111
+ this.ws.onmessage = (ev: MessageEvent<Uint8Array>) => {
112
+ const msg = this.encoder.decode(ev.data, MessageSchema);
113
+ const callback = this.receiveCallbacksQueue.shift();
114
+ if (callback != null) callback.resolve(msg);
115
+ else this.receiveDataQueue.push(msg);
116
+ };
117
+
118
+ this.ws.onclose = (ev: CloseEvent) => {
119
+ this.serverClosed = isNormalClosure(ev) ? new EOF() : new StreamClosed();
120
+ };
121
+ }
122
+ }
123
+
124
+ export const FREIGHTER_METADATA_PREFIX = "freighterctx";
125
+
126
+ const CloseNormal = 1000;
127
+ const CloseGoingAway = 1001;
128
+ const NormalClosures = [CloseNormal, CloseGoingAway];
129
+
130
+ const isNormalClosure = (ev: CloseEvent): boolean => NormalClosures.includes(ev.code);
131
+
132
+ /**
133
+ * WebSocketClient is an implementation of StreamClient that is backed by
134
+ * websockets.
135
+ */
136
+ export class WebSocketClient extends MiddlewareCollector implements StreamClient {
137
+ baseUrl: URL;
138
+ encoder: binary.EncoderDecoder;
139
+
140
+ static readonly MESSAGE_TYPE = "arraybuffer";
141
+
142
+ /**
143
+ * @param encoder - The encoder to use for encoding messages and decoding
144
+ * responses.
145
+ * @param baseEndpoint - A base url to use as a prefix for all requests.
146
+ */
147
+ constructor(baseEndpoint: URL, encoder: binary.EncoderDecoder, secure = false) {
148
+ super();
149
+ this.baseUrl = baseEndpoint.replace({ protocol: secure ? "wss" : "ws" });
150
+ this.encoder = encoder;
151
+ }
152
+
153
+ /** Implements the StreamClient interface. */
154
+ async stream<RQ extends z.ZodTypeAny, RS extends z.ZodTypeAny = RQ>(
155
+ target: string,
156
+ reqSchema: RQ,
157
+ resSchema: RS,
158
+ ): Promise<Stream<RQ, RS>> {
159
+ const SocketConstructor = resolveWebSocketConstructor();
160
+ let stream: Stream<RQ, RS> | undefined;
161
+ const [, error] = await this.executeMiddleware(
162
+ { target, protocol: "websocket", params: {}, role: "client" },
163
+ async (ctx: Context): Promise<[Context, Error | null]> => {
164
+ const ws = SocketConstructor(this.buildURL(target, ctx));
165
+ const outCtx: Context = { ...ctx, params: {} };
166
+ ws.binaryType = WebSocketClient.MESSAGE_TYPE;
167
+ const streamOrErr = await this.wrapSocket(ws, reqSchema, resSchema);
168
+ if (streamOrErr instanceof Error) return [outCtx, streamOrErr];
169
+ stream = streamOrErr;
170
+ return [outCtx, null];
171
+ },
172
+ );
173
+ if (error != null) throw error;
174
+ return stream as Stream<RQ, RS>;
175
+ }
176
+
177
+ private buildURL(target: string, ctx: Context): string {
178
+ const qs = buildQueryString(
179
+ {
180
+ [CONTENT_TYPE_HEADER_KEY]: this.encoder.contentType,
181
+ ...ctx.params,
182
+ },
183
+ FREIGHTER_METADATA_PREFIX,
184
+ );
185
+ return this.baseUrl.child(target).toString() + qs;
186
+ }
187
+
188
+ private async wrapSocket<RQ extends z.ZodTypeAny, RS extends z.ZodTypeAny = RQ>(
189
+ ws: WebSocket,
190
+ reqSchema: RQ,
191
+ resSchema: RS,
192
+ ): Promise<WebSocketStream<RQ, RS> | Error> {
193
+ return await new Promise((resolve) => {
194
+ ws.onopen = () => {
195
+ resolve(new WebSocketStream<RQ, RS>(ws, this.encoder, reqSchema, resSchema));
196
+ };
197
+ ws.onerror = (ev: Event) => {
198
+ const ev_ = ev as ErrorEvent;
199
+ resolve(new Error(ev_.message));
200
+ };
201
+ });
202
+ }
203
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "@synnaxlabs/tsconfig/base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": ".",
5
+ "paths": {
6
+ "@/*": ["src/*"]
7
+ }
8
+ },
9
+ "include": ["src/**/*.ts"],
10
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "@synnaxlabs/tsconfig/vite.json",
3
+ "include": ["vite.config.ts"]
4
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,16 @@
1
+ // Copyright 2023 Synnax Labs, Inc.
2
+ //
3
+ // Use of this software is governed by the Business Source License included in the file
4
+ // licenses/BSL.txt.
5
+ //
6
+ // As of the Change Date specified in that file, in accordance with the Business Source
7
+ // License, use of this software will be governed by the Apache License, Version 2.0,
8
+ // included in the file licenses/APL.txt.
9
+
10
+ import { defineConfig } from "vite";
11
+
12
+ import { lib } from "@synnaxlabs/vite-plugin";
13
+
14
+ export default defineConfig({
15
+ plugins: [lib({ name: "freighter" })],
16
+ });
@@ -1,7 +0,0 @@
1
- export { WebSocketClient } from './lib/websocket';
2
- export { MsgpackEncoderDecoder, JSONEncoderDecoder, registerCustomTypeEncoder, ENCODERS, } from './lib/encoder';
3
- export { StreamClient, Stream } from './lib/stream';
4
- export { UnaryClient } from './lib/unary';
5
- export { HTTPClientFactory } from './lib/http';
6
- export { default as URL } from './lib/url';
7
- export { encodeError, decodeError, registerError, BaseTypedError, TypedError, ErrorPayload, ErrorPayloadSchema, EOF, StreamClosed, Unreachable, } from './lib/errors';
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Unreachable = exports.StreamClosed = exports.EOF = exports.ErrorPayloadSchema = exports.BaseTypedError = exports.registerError = exports.decodeError = exports.encodeError = exports.URL = exports.HTTPClientFactory = exports.ENCODERS = exports.registerCustomTypeEncoder = exports.JSONEncoderDecoder = exports.MsgpackEncoderDecoder = exports.WebSocketClient = void 0;
7
- var websocket_1 = require("./lib/websocket");
8
- Object.defineProperty(exports, "WebSocketClient", { enumerable: true, get: function () { return websocket_1.WebSocketClient; } });
9
- var encoder_1 = require("./lib/encoder");
10
- Object.defineProperty(exports, "MsgpackEncoderDecoder", { enumerable: true, get: function () { return encoder_1.MsgpackEncoderDecoder; } });
11
- Object.defineProperty(exports, "JSONEncoderDecoder", { enumerable: true, get: function () { return encoder_1.JSONEncoderDecoder; } });
12
- Object.defineProperty(exports, "registerCustomTypeEncoder", { enumerable: true, get: function () { return encoder_1.registerCustomTypeEncoder; } });
13
- Object.defineProperty(exports, "ENCODERS", { enumerable: true, get: function () { return encoder_1.ENCODERS; } });
14
- var http_1 = require("./lib/http");
15
- Object.defineProperty(exports, "HTTPClientFactory", { enumerable: true, get: function () { return http_1.HTTPClientFactory; } });
16
- var url_1 = require("./lib/url");
17
- Object.defineProperty(exports, "URL", { enumerable: true, get: function () { return __importDefault(url_1).default; } });
18
- var errors_1 = require("./lib/errors");
19
- Object.defineProperty(exports, "encodeError", { enumerable: true, get: function () { return errors_1.encodeError; } });
20
- Object.defineProperty(exports, "decodeError", { enumerable: true, get: function () { return errors_1.decodeError; } });
21
- Object.defineProperty(exports, "registerError", { enumerable: true, get: function () { return errors_1.registerError; } });
22
- Object.defineProperty(exports, "BaseTypedError", { enumerable: true, get: function () { return errors_1.BaseTypedError; } });
23
- Object.defineProperty(exports, "ErrorPayloadSchema", { enumerable: true, get: function () { return errors_1.ErrorPayloadSchema; } });
24
- Object.defineProperty(exports, "EOF", { enumerable: true, get: function () { return errors_1.EOF; } });
25
- Object.defineProperty(exports, "StreamClosed", { enumerable: true, get: function () { return errors_1.StreamClosed; } });
26
- Object.defineProperty(exports, "Unreachable", { enumerable: true, get: function () { return errors_1.Unreachable; } });
27
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNkNBQWtEO0FBQXpDLDRHQUFBLGVBQWUsT0FBQTtBQUN4Qix5Q0FLdUI7QUFKckIsZ0hBQUEscUJBQXFCLE9BQUE7QUFDckIsNkdBQUEsa0JBQWtCLE9BQUE7QUFDbEIsb0hBQUEseUJBQXlCLE9BQUE7QUFDekIsbUdBQUEsUUFBUSxPQUFBO0FBSVYsbUNBQStDO0FBQXRDLHlHQUFBLGlCQUFpQixPQUFBO0FBQzFCLGlDQUEyQztBQUFsQywyR0FBQSxPQUFPLE9BQU87QUFDdkIsdUNBV3NCO0FBVnBCLHFHQUFBLFdBQVcsT0FBQTtBQUNYLHFHQUFBLFdBQVcsT0FBQTtBQUNYLHVHQUFBLGFBQWEsT0FBQTtBQUNiLHdHQUFBLGNBQWMsT0FBQTtBQUdkLDRHQUFBLGtCQUFrQixPQUFBO0FBQ2xCLDZGQUFBLEdBQUcsT0FBQTtBQUNILHNHQUFBLFlBQVksT0FBQTtBQUNaLHFHQUFBLFdBQVcsT0FBQSJ9
@@ -1,2 +0,0 @@
1
- export declare const snakeKeys: (entity: unknown) => object | null;
2
- export declare const camelKeys: (entity: unknown) => object | null;
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.camelKeys = exports.snakeKeys = void 0;
4
- const js_convert_case_1 = require("js-convert-case");
5
- const options = {
6
- recursive: true,
7
- recursiveInArray: true,
8
- keepTypesOnRecursion: [Number, String, Uint8Array],
9
- };
10
- const snakeKeys = (entity) => (0, js_convert_case_1.snakeKeys)(entity, options);
11
- exports.snakeKeys = snakeKeys;
12
- const camelKeys = (entity) => (0, js_convert_case_1.camelKeys)(entity, options);
13
- exports.camelKeys = camelKeys;
14
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FzZWNvbnYuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2Nhc2Vjb252LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFEQUd5QjtBQUV6QixNQUFNLE9BQU8sR0FBRztJQUNkLFNBQVMsRUFBRSxJQUFJO0lBQ2YsZ0JBQWdCLEVBQUUsSUFBSTtJQUN0QixvQkFBb0IsRUFBRSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsVUFBVSxDQUFDO0NBQ25ELENBQUM7QUFFSyxNQUFNLFNBQVMsR0FBRyxDQUFDLE1BQWUsRUFBRSxFQUFFLENBQUMsSUFBQSwyQkFBVSxFQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztBQUE3RCxRQUFBLFNBQVMsYUFBb0Q7QUFDbkUsTUFBTSxTQUFTLEdBQUcsQ0FBQyxNQUFlLEVBQUUsRUFBRSxDQUFDLElBQUEsMkJBQVUsRUFBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7QUFBN0QsUUFBQSxTQUFTLGFBQW9EIn0=
@@ -1,60 +0,0 @@
1
- import { ZodSchema } from 'zod';
2
- /**
3
- * CustomTypeEncoder is an interface for a class that needs to transform its
4
- * value before encoding.
5
- */
6
- interface CustomTypeEncoder {
7
- /** The Class the custom encoder is set for */
8
- Class: Function;
9
- /**
10
- * The function that transforms the value before encoding;
11
- * @param instance - The instance of the class to transform.
12
- * @returns The transformed value.
13
- */
14
- write<P>(instance: P): unknown;
15
- }
16
- /**
17
- * EncoderDecoder is an entity that encodes and decodes messages to and from
18
- * a binary format.
19
- */
20
- export interface EncoderDecoder {
21
- /** The HTTP content type of the encoder */
22
- contentType: string;
23
- /**
24
- * Encodes the given payload into a binary representation.
25
- * @param payload - The payload to encode.
26
- * @returns an ArrayBuffer containing the encoded payload.
27
- */
28
- encode(payload: unknown): ArrayBuffer;
29
- /**
30
- * Decodes the given binary representation into a type checked payload.
31
- * @param data - The data to decode.
32
- * @param schema - The schema to decode the data with.
33
- */
34
- decode<P>(data: Uint8Array | ArrayBuffer, schema: ZodSchema<P>): P;
35
- }
36
- interface StaticEncoderDecoder {
37
- registerCustomType(encoder: CustomTypeEncoder): void;
38
- }
39
- /***
40
- * MsgpackEncoderDecoder is a msgpack implementation of EncoderDecoder.
41
- */
42
- export declare class MsgpackEncoderDecoder implements EncoderDecoder {
43
- contentType: string;
44
- encode(payload: unknown): ArrayBuffer;
45
- decode<P>(data: Uint8Array, schema: ZodSchema<P>): P;
46
- static registerCustomType(encoder: CustomTypeEncoder): void;
47
- }
48
- /**
49
- * JSONEncoderDecoder is a JSON implementation of EncoderDecoder.
50
- */
51
- export declare class JSONEncoderDecoder implements EncoderDecoder {
52
- contentType: string;
53
- encode(payload: unknown): ArrayBuffer;
54
- decode<P>(data: Uint8Array, schema: ZodSchema<P>): P;
55
- static registerCustomType(): void;
56
- }
57
- export declare const ENCODERS: EncoderDecoder[];
58
- export declare const ENCODER_CLASSES: StaticEncoderDecoder[];
59
- export declare const registerCustomTypeEncoder: (encoder: CustomTypeEncoder) => void;
60
- export {};
@@ -1,61 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerCustomTypeEncoder = exports.ENCODER_CLASSES = exports.ENCODERS = exports.JSONEncoderDecoder = exports.MsgpackEncoderDecoder = void 0;
4
- const msgpackr_1 = require("msgpackr");
5
- const caseconv_1 = require("./caseconv");
6
- /***
7
- * MsgpackEncoderDecoder is a msgpack implementation of EncoderDecoder.
8
- */
9
- class MsgpackEncoderDecoder {
10
- constructor() {
11
- this.contentType = 'application/msgpack';
12
- }
13
- encode(payload) {
14
- return (0, msgpackr_1.pack)((0, caseconv_1.snakeKeys)(payload));
15
- }
16
- decode(data, schema) {
17
- return schema.parse((0, caseconv_1.camelKeys)((0, msgpackr_1.unpack)(new Uint8Array(data))));
18
- }
19
- static registerCustomType(encoder) {
20
- (0, msgpackr_1.addExtension)(Object.assign({ type: 0 }, encoder));
21
- }
22
- }
23
- exports.MsgpackEncoderDecoder = MsgpackEncoderDecoder;
24
- /**
25
- * JSONEncoderDecoder is a JSON implementation of EncoderDecoder.
26
- */
27
- class JSONEncoderDecoder {
28
- constructor() {
29
- this.contentType = 'application/json';
30
- }
31
- encode(payload) {
32
- const json = JSON.stringify((0, caseconv_1.snakeKeys)(payload), (_, v) => {
33
- if (ArrayBuffer.isView(v))
34
- return Array.from(v);
35
- return v;
36
- });
37
- return new TextEncoder().encode(json);
38
- }
39
- decode(data, schema) {
40
- return schema.parse((0, caseconv_1.camelKeys)(JSON.parse(new TextDecoder().decode(data))));
41
- }
42
- static registerCustomType() {
43
- return;
44
- }
45
- }
46
- exports.JSONEncoderDecoder = JSONEncoderDecoder;
47
- exports.ENCODERS = [
48
- new MsgpackEncoderDecoder(),
49
- new JSONEncoderDecoder(),
50
- ];
51
- exports.ENCODER_CLASSES = [
52
- MsgpackEncoderDecoder,
53
- JSONEncoderDecoder,
54
- ];
55
- const registerCustomTypeEncoder = (encoder) => {
56
- exports.ENCODER_CLASSES.forEach((encoderClass) => {
57
- encoderClass.registerCustomType(encoder);
58
- });
59
- };
60
- exports.registerCustomTypeEncoder = registerCustomTypeEncoder;
61
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5jb2Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvZW5jb2Rlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSx1Q0FBc0Q7QUFHdEQseUNBQWtEO0FBOENsRDs7R0FFRztBQUNILE1BQWEscUJBQXFCO0lBQWxDO1FBQ0UsZ0JBQVcsR0FBRyxxQkFBcUIsQ0FBQztJQWF0QyxDQUFDO0lBWEMsTUFBTSxDQUFDLE9BQWdCO1FBQ3JCLE9BQU8sSUFBQSxlQUFJLEVBQUMsSUFBQSxvQkFBUyxFQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVELE1BQU0sQ0FBSSxJQUFnQixFQUFFLE1BQW9CO1FBQzlDLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFBLG9CQUFTLEVBQUMsSUFBQSxpQkFBTSxFQUFDLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFRCxNQUFNLENBQUMsa0JBQWtCLENBQUMsT0FBMEI7UUFDbEQsSUFBQSx1QkFBWSxrQkFBRyxJQUFJLEVBQUUsQ0FBQyxJQUFLLE9BQU8sRUFBRyxDQUFDO0lBQ3hDLENBQUM7Q0FDRjtBQWRELHNEQWNDO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLGtCQUFrQjtJQUEvQjtRQUNFLGdCQUFXLEdBQUcsa0JBQWtCLENBQUM7SUFpQm5DLENBQUM7SUFmQyxNQUFNLENBQUMsT0FBZ0I7UUFDckIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFBLG9CQUFTLEVBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDdkQsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztnQkFBRSxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBZSxDQUFDLENBQUM7WUFDOUQsT0FBTyxDQUFDLENBQUM7UUFDWCxDQUFDLENBQUMsQ0FBQztRQUNILE9BQU8sSUFBSSxXQUFXLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDeEMsQ0FBQztJQUVELE1BQU0sQ0FBSSxJQUFnQixFQUFFLE1BQW9CO1FBQzlDLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFBLG9CQUFTLEVBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLFdBQVcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3RSxDQUFDO0lBRUQsTUFBTSxDQUFDLGtCQUFrQjtRQUN2QixPQUFPO0lBQ1QsQ0FBQztDQUNGO0FBbEJELGdEQWtCQztBQUVZLFFBQUEsUUFBUSxHQUFxQjtJQUN4QyxJQUFJLHFCQUFxQixFQUFFO0lBQzNCLElBQUksa0JBQWtCLEVBQUU7Q0FDekIsQ0FBQztBQUVXLFFBQUEsZUFBZSxHQUEyQjtJQUNyRCxxQkFBcUI7SUFDckIsa0JBQWtCO0NBQ25CLENBQUM7QUFFSyxNQUFNLHlCQUF5QixHQUFHLENBQUMsT0FBMEIsRUFBUSxFQUFFO0lBQzVFLHVCQUFlLENBQUMsT0FBTyxDQUFDLENBQUMsWUFBWSxFQUFFLEVBQUU7UUFDdkMsWUFBWSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzNDLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDO0FBSlcsUUFBQSx5QkFBeUIsNkJBSXBDIn0=
@@ -1,26 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const ava_1 = __importDefault(require("ava"));
7
- const zod_1 = require("zod");
8
- const encoder_1 = require("./encoder");
9
- const SampleSchema = zod_1.z.object({
10
- channelKey: zod_1.z.string(),
11
- timeStamp: zod_1.z.number(),
12
- value: zod_1.z.unknown(),
13
- });
14
- encoder_1.ENCODERS.forEach((encoder) => {
15
- (0, ava_1.default)(`encoder ${encoder.contentType}`, (t) => {
16
- const sample = {
17
- channelKey: 'test',
18
- timeStamp: 123,
19
- value: new Uint8Array([1, 2, 3]),
20
- };
21
- const encoded = encoder.encode(sample);
22
- const decoded = encoder.decode(encoded, SampleSchema);
23
- t.deepEqual(decoded, decoded);
24
- });
25
- });
26
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5jb2Rlci5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9lbmNvZGVyLnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSw4Q0FBdUI7QUFDdkIsNkJBQXdCO0FBRXhCLHVDQUFxQztBQUVyQyxNQUFNLFlBQVksR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQzVCLFVBQVUsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFO0lBQ3RCLFNBQVMsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFO0lBQ3JCLEtBQUssRUFBRSxPQUFDLENBQUMsT0FBTyxFQUFFO0NBQ25CLENBQUMsQ0FBQztBQUVILGtCQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7SUFDM0IsSUFBQSxhQUFJLEVBQUMsV0FBVyxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRTtRQUMzQyxNQUFNLE1BQU0sR0FBRztZQUNiLFVBQVUsRUFBRSxNQUFNO1lBQ2xCLFNBQVMsRUFBRSxHQUFHO1lBQ2QsS0FBSyxFQUFFLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztTQUNqQyxDQUFDO1FBQ0YsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN2QyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQztRQUN0RCxDQUFDLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNoQyxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIn0=
@@ -1,77 +0,0 @@
1
- import { z } from 'zod';
2
- export interface TypedError extends Error {
3
- discriminator: 'FreighterError';
4
- /**
5
- * @description Returns a unique type identifier for the error. Freighter uses this to
6
- * determine the correct decoder to use on the other end of the freighter.
7
- */
8
- type: string;
9
- }
10
- export declare class BaseTypedError extends Error implements TypedError {
11
- discriminator: 'FreighterError';
12
- type: string;
13
- constructor(message: string, type: string);
14
- }
15
- declare type ErrorDecoder = (encoded: string) => Error | undefined;
16
- declare type ErrorEncoder = (error: TypedError) => string;
17
- export declare const isTypedError: (error: unknown) => error is TypedError;
18
- export declare const assertErrorType: <T>(type: string, error?: Error) => T;
19
- export declare const UNKNOWN = "unknown";
20
- export declare const NONE = "nil";
21
- export declare const FREIGHTER = "freighter";
22
- export declare const ErrorPayloadSchema: z.ZodObject<{
23
- type: z.ZodString;
24
- data: z.ZodString;
25
- }, "strip", z.ZodTypeAny, {
26
- type: string;
27
- data: string;
28
- }, {
29
- type: string;
30
- data: string;
31
- }>;
32
- export declare type ErrorPayload = z.infer<typeof ErrorPayloadSchema>;
33
- /**
34
- * Registers a custom error type with the error registry, which allows it to be
35
- * encoded/decoded and sent over the network.
36
- *
37
- * @param type - A unique string identifier for the error type.
38
- * @param encode - A function that encodes the error into a string.
39
- * @param decode - A function that decodes the error from a string.
40
- */
41
- export declare const registerError: ({ type, encode, decode, }: {
42
- type: string;
43
- encode: ErrorEncoder;
44
- decode: ErrorDecoder;
45
- }) => void;
46
- /**
47
- * Encodes an error into a payload that can be sent between a freighter server
48
- * and client.
49
- * @param error - The error to encode.
50
- * @returns The encoded error.
51
- */
52
- export declare const encodeError: (error: unknown) => ErrorPayload;
53
- /**
54
- * Decodes an error payload into an exception. If a custom decoder can be found
55
- * for the error type, it will be used. Otherwise, a generic Error containing
56
- * the error data is returned.
57
- *
58
- * @param payload - The encoded error payload.
59
- * @returns The decoded error.
60
- */
61
- export declare const decodeError: (payload: ErrorPayload) => Error | undefined;
62
- export declare class UnknownError extends BaseTypedError implements TypedError {
63
- constructor(message: string);
64
- }
65
- /** Thrown/returned when a stream closed normally. */
66
- export declare class EOF extends BaseTypedError implements TypedError {
67
- constructor();
68
- }
69
- /** Thrown/returned when a stream is closed abnormally. */
70
- export declare class StreamClosed extends BaseTypedError implements TypedError {
71
- constructor();
72
- }
73
- /** Thrown when a target is unreachable. */
74
- export declare class Unreachable extends BaseTypedError implements TypedError {
75
- constructor();
76
- }
77
- export {};