@synnaxlabs/freighter 0.2.0 → 0.6.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/.eslintrc.cjs +18 -0
- package/LICENSE +4 -21
- package/dist/alamos.d.ts +3 -0
- package/{build/module/lib → dist}/errors.d.ts +35 -40
- package/dist/freighter.cjs.js +2 -0
- package/dist/freighter.cjs.js.map +1 -0
- package/dist/freighter.es.js +8460 -0
- package/dist/freighter.es.js.map +1 -0
- package/dist/http.d.ts +20 -0
- package/dist/index.d.ts +8 -0
- package/{build/module/lib → dist}/middleware.d.ts +11 -8
- package/{build/main/lib → dist}/stream.d.ts +11 -11
- package/{build/main/lib → dist}/transport.d.ts +2 -2
- package/dist/unary.d.ts +16 -0
- package/dist/websocket.d.ts +24 -0
- package/package.json +31 -99
- package/src/alamos.ts +40 -0
- package/src/errors.spec.ts +94 -0
- package/src/errors.ts +205 -0
- package/src/http.spec.ts +67 -0
- package/src/http.ts +115 -0
- package/src/index.ts +21 -20
- package/src/{lib/middleware.ts → middleware.ts} +29 -19
- package/src/{lib/stream.ts → stream.ts} +23 -14
- package/src/transport.ts +23 -0
- package/src/unary.ts +44 -0
- package/src/websocket.spec.ts +119 -0
- package/src/websocket.ts +203 -0
- package/tsconfig.json +5 -42
- package/tsconfig.vite.json +4 -0
- package/vite.config.ts +16 -0
- package/.editorconfig +0 -15
- package/.eslintrc.json +0 -33
- package/.gitignore +0 -9
- package/.nyc_output/3238f10e-9572-49ec-ab9d-28cbcaa6152a.json +0 -1
- package/.nyc_output/4e78a5c9-c0ca-4664-aa04-f478522608eb.json +0 -1
- package/.nyc_output/6a2244f2-5aea-45c7-8eeb-e14b454f0096.json +0 -1
- package/.nyc_output/dd1075a0-827b-4154-a75e-9bc90a4e16d0.json +0 -1
- package/.nyc_output/f829ad27-9bcd-4604-ae57-aae8c6f28d51.json +0 -1
- package/.nyc_output/fabc60f1-8fc5-4a1e-bea0-dc1fbcc31c9c.json +0 -1
- package/.nyc_output/processinfo/3238f10e-9572-49ec-ab9d-28cbcaa6152a.json +0 -1
- package/.nyc_output/processinfo/4e78a5c9-c0ca-4664-aa04-f478522608eb.json +0 -1
- package/.nyc_output/processinfo/6a2244f2-5aea-45c7-8eeb-e14b454f0096.json +0 -1
- package/.nyc_output/processinfo/dd1075a0-827b-4154-a75e-9bc90a4e16d0.json +0 -1
- package/.nyc_output/processinfo/f829ad27-9bcd-4604-ae57-aae8c6f28d51.json +0 -1
- package/.nyc_output/processinfo/fabc60f1-8fc5-4a1e-bea0-dc1fbcc31c9c.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/.prettierignore +0 -2
- package/.prettierrc +0 -3
- package/.vscode/settings.json +0 -4
- package/build/main/index.d.ts +0 -9
- package/build/main/index.js +0 -29
- package/build/main/lib/caseconv.d.ts +0 -2
- package/build/main/lib/caseconv.js +0 -14
- package/build/main/lib/encoder.d.ts +0 -59
- package/build/main/lib/encoder.js +0 -57
- package/build/main/lib/encoder.spec.d.ts +0 -1
- package/build/main/lib/encoder.spec.js +0 -26
- package/build/main/lib/errors.d.ts +0 -87
- package/build/main/lib/errors.js +0 -189
- package/build/main/lib/errors.spec.js +0 -88
- package/build/main/lib/http.d.ts +0 -50
- package/build/main/lib/http.js +0 -114
- package/build/main/lib/http.spec.js +0 -59
- package/build/main/lib/middleware.d.ts +0 -45
- package/build/main/lib/middleware.js +0 -38
- package/build/main/lib/runtime.d.ts +0 -5
- package/build/main/lib/runtime.js +0 -24
- package/build/main/lib/stream.js +0 -3
- package/build/main/lib/transport.js +0 -3
- package/build/main/lib/unary.d.ts +0 -15
- package/build/main/lib/unary.js +0 -3
- package/build/main/lib/url.d.ts +0 -38
- package/build/main/lib/url.js +0 -65
- package/build/main/lib/url.spec.d.ts +0 -1
- package/build/main/lib/url.spec.js +0 -41
- package/build/main/lib/util/log.d.ts +0 -2
- package/build/main/lib/util/log.js +0 -15
- package/build/main/lib/websocket.d.ts +0 -25
- package/build/main/lib/websocket.js +0 -172
- package/build/main/lib/websocket.spec.js +0 -86
- package/build/main/lib/ws.spec.d.ts +0 -1
- package/build/main/lib/ws.spec.js +0 -115
- package/build/module/index.d.ts +0 -9
- package/build/module/index.js +0 -7
- package/build/module/lib/caseconv.d.ts +0 -2
- package/build/module/lib/caseconv.js +0 -12
- package/build/module/lib/encoder.d.ts +0 -59
- package/build/module/lib/encoder.js +0 -47
- package/build/module/lib/encoder.spec.d.ts +0 -1
- package/build/module/lib/encoder.spec.js +0 -21
- package/build/module/lib/errors.js +0 -164
- package/build/module/lib/errors.spec.d.ts +0 -1
- package/build/module/lib/errors.spec.js +0 -85
- package/build/module/lib/http.d.ts +0 -50
- package/build/module/lib/http.js +0 -108
- package/build/module/lib/http.spec.d.ts +0 -1
- package/build/module/lib/http.spec.js +0 -54
- package/build/module/lib/middleware.js +0 -32
- package/build/module/lib/runtime.d.ts +0 -5
- package/build/module/lib/runtime.js +0 -21
- package/build/module/lib/stream.d.ts +0 -76
- package/build/module/lib/stream.js +0 -2
- package/build/module/lib/transport.d.ts +0 -13
- package/build/module/lib/transport.js +0 -2
- package/build/module/lib/unary.d.ts +0 -15
- package/build/module/lib/unary.js +0 -2
- package/build/module/lib/url.d.ts +0 -38
- package/build/module/lib/url.js +0 -65
- package/build/module/lib/url.spec.d.ts +0 -1
- package/build/module/lib/url.spec.js +0 -34
- package/build/module/lib/util/log.d.ts +0 -2
- package/build/module/lib/util/log.js +0 -11
- package/build/module/lib/websocket.d.ts +0 -25
- package/build/module/lib/websocket.js +0 -181
- package/build/module/lib/websocket.spec.d.ts +0 -1
- package/build/module/lib/websocket.spec.js +0 -82
- package/build/module/lib/ws.spec.d.ts +0 -1
- package/build/module/lib/ws.spec.js +0 -94
- package/build/tsconfig.module.tsbuildinfo +0 -1
- package/build/tsconfig.tsbuildinfo +0 -1
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/caseconv.ts.html +0 -124
- package/coverage/encoder.ts.html +0 -403
- package/coverage/errors.ts.html +0 -727
- package/coverage/favicon.png +0 -0
- package/coverage/http.ts.html +0 -532
- package/coverage/index.html +0 -221
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/caseconv.ts.html +0 -124
- package/coverage/lcov-report/encoder.ts.html +0 -403
- package/coverage/lcov-report/errors.ts.html +0 -727
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/http.ts.html +0 -532
- package/coverage/lcov-report/index.html +0 -221
- package/coverage/lcov-report/middleware.ts.html +0 -286
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/runtime.ts.html +0 -154
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov-report/url.ts.html +0 -322
- package/coverage/lcov-report/websocket.ts.html +0 -760
- package/coverage/lcov.info +0 -552
- package/coverage/middleware.ts.html +0 -286
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/runtime.ts.html +0 -154
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -196
- package/coverage/url.ts.html +0 -322
- package/coverage/websocket.ts.html +0 -760
- package/src/lib/caseconv.ts +0 -13
- package/src/lib/encoder.spec.ts +0 -23
- package/src/lib/encoder.ts +0 -105
- package/src/lib/errors.spec.ts +0 -98
- package/src/lib/errors.ts +0 -214
- package/src/lib/http.spec.ts +0 -85
- package/src/lib/http.ts +0 -149
- package/src/lib/runtime.ts +0 -23
- package/src/lib/transport.ts +0 -14
- package/src/lib/unary.ts +0 -21
- package/src/lib/url.spec.ts +0 -37
- package/src/lib/url.ts +0 -79
- package/src/lib/util/log.ts +0 -12
- package/src/lib/websocket.spec.ts +0 -106
- package/src/lib/websocket.ts +0 -225
- package/src/types/example.d.ts +0 -24
- package/tsconfig.module.json +0 -9
- package/yarn.lock +0 -5878
- /package/{build/main/lib → dist}/errors.spec.d.ts +0 -0
- /package/{build/main/lib → dist}/http.spec.d.ts +0 -0
- /package/{build/main/lib → 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
|
+
});
|
package/src/websocket.ts
ADDED
|
@@ -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
CHANGED
|
@@ -1,47 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "@synnaxlabs/tsconfig/base.json",
|
|
2
3
|
"compilerOptions": {
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"moduleResolution": "node",
|
|
8
|
-
"module": "commonjs",
|
|
9
|
-
"declaration": true,
|
|
10
|
-
"inlineSourceMap": true,
|
|
11
|
-
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
|
12
|
-
"resolveJsonModule": true /* Include modules imported with .json extension. */,
|
|
13
|
-
|
|
14
|
-
"strict": true /* Enable all strict type-checking options. */,
|
|
15
|
-
|
|
16
|
-
/* Strict Type-Checking Options */
|
|
17
|
-
// "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
|
|
18
|
-
// "strictNullChecks": true /* Enable strict null checks. */,
|
|
19
|
-
// "strictFunctionTypes": true /* Enable strict checking of function types. */,
|
|
20
|
-
// "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */,
|
|
21
|
-
// "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */,
|
|
22
|
-
// "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,
|
|
23
|
-
|
|
24
|
-
/* Additional Checks */
|
|
25
|
-
"noUnusedLocals": true /* Report errors on unused locals. */,
|
|
26
|
-
"noUnusedParameters": true /* Report errors on unused parameters. */,
|
|
27
|
-
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
|
|
28
|
-
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
|
|
29
|
-
|
|
30
|
-
/* Debugging Options */
|
|
31
|
-
"traceResolution": false /* Report module resolution log messages. */,
|
|
32
|
-
"listEmittedFiles": false /* Print names of generated files part of the compilation. */,
|
|
33
|
-
"listFiles": false /* Print names of files part of the compilation. */,
|
|
34
|
-
"pretty": true /* Stylize errors and messages using color and context. */,
|
|
35
|
-
|
|
36
|
-
/* Experimental Options */
|
|
37
|
-
// "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
|
|
38
|
-
// "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,
|
|
39
|
-
|
|
40
|
-
"lib": ["es2017", "dom"],
|
|
41
|
-
"types": ["node"],
|
|
42
|
-
"typeRoots": ["node_modules/@types", "src/types"]
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"paths": {
|
|
6
|
+
"@/*": ["src/*"]
|
|
7
|
+
}
|
|
43
8
|
},
|
|
44
9
|
"include": ["src/**/*.ts"],
|
|
45
|
-
"exclude": ["node_modules/**"],
|
|
46
|
-
"compileOnSave": false
|
|
47
10
|
}
|
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
|
+
});
|
package/.editorconfig
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# http://editorconfig.org
|
|
2
|
-
root = true
|
|
3
|
-
|
|
4
|
-
[*]
|
|
5
|
-
charset = utf-8
|
|
6
|
-
end_of_line = lf
|
|
7
|
-
indent_size = 2
|
|
8
|
-
indent_style = space
|
|
9
|
-
insert_final_newline = true
|
|
10
|
-
max_line_length = 80
|
|
11
|
-
trim_trailing_whitespace = true
|
|
12
|
-
|
|
13
|
-
[*.md]
|
|
14
|
-
max_line_length = 0
|
|
15
|
-
trim_trailing_whitespace = false
|
package/.eslintrc.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"root": true,
|
|
3
|
-
"parser": "@typescript-eslint/parser",
|
|
4
|
-
"parserOptions": { "project": "./tsconfig.json" },
|
|
5
|
-
"env": { "es6": true },
|
|
6
|
-
"ignorePatterns": ["node_modules", "build", "coverage"],
|
|
7
|
-
"plugins": ["import", "eslint-comments"],
|
|
8
|
-
"extends": [
|
|
9
|
-
"eslint:recommended",
|
|
10
|
-
"plugin:eslint-comments/recommended",
|
|
11
|
-
"plugin:@typescript-eslint/recommended",
|
|
12
|
-
"plugin:import/typescript",
|
|
13
|
-
"prettier",
|
|
14
|
-
"prettier/@typescript-eslint"
|
|
15
|
-
],
|
|
16
|
-
"globals": { "BigInt": true, "console": true, "WebAssembly": true },
|
|
17
|
-
"rules": {
|
|
18
|
-
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
19
|
-
"eslint-comments/disable-enable-pair": [
|
|
20
|
-
"error",
|
|
21
|
-
{ "allowWholeFile": true }
|
|
22
|
-
],
|
|
23
|
-
"eslint-comments/no-unused-disable": "error",
|
|
24
|
-
"import/order": [
|
|
25
|
-
"error",
|
|
26
|
-
{ "newlines-between": "always", "alphabetize": { "order": "asc" } }
|
|
27
|
-
],
|
|
28
|
-
"sort-imports": [
|
|
29
|
-
"error",
|
|
30
|
-
{ "ignoreDeclarationSort": true, "ignoreCase": true }
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
}
|
package/.gitignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"/Users/emilianobonilla/Desktop/synnax/freighter/ts/build/main/lib/encoder.js":{"path":"/Users/emilianobonilla/Desktop/synnax/freighter/ts/build/main/lib/encoder.js","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":62}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":149}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":38}},"3":{"start":{"line":5,"column":19},"end":{"line":5,"column":40}},"4":{"start":{"line":9,"column":8},"end":{"line":9,"column":49}},"5":{"start":{"line":12,"column":8},"end":{"line":12,"column":72}},"6":{"start":{"line":15,"column":8},"end":{"line":15,"column":101}},"7":{"start":{"line":18,"column":8},"end":{"line":18,"column":74}},"8":{"start":{"line":21,"column":0},"end":{"line":21,"column":54}},"9":{"start":{"line":25,"column":8},"end":{"line":25,"column":46}},"10":{"start":{"line":28,"column":21},"end":{"line":32,"column":10}},"11":{"start":{"line":29,"column":12},"end":{"line":30,"column":37}},"12":{"start":{"line":30,"column":16},"end":{"line":30,"column":37}},"13":{"start":{"line":31,"column":12},"end":{"line":31,"column":21}},"14":{"start":{"line":33,"column":8},"end":{"line":33,"column":46}},"15":{"start":{"line":36,"column":8},"end":{"line":36,"column":99}},"16":{"start":{"line":39,"column":8},"end":{"line":39,"column":15}},"17":{"start":{"line":42,"column":0},"end":{"line":42,"column":48}},"18":{"start":{"line":43,"column":0},"end":{"line":46,"column":2}},"19":{"start":{"line":47,"column":0},"end":{"line":50,"column":2}},"20":{"start":{"line":51,"column":34},"end":{"line":55,"column":1}},"21":{"start":{"line":52,"column":4},"end":{"line":54,"column":7}},"22":{"start":{"line":53,"column":8},"end":{"line":53,"column":49}},"23":{"start":{"line":56,"column":0},"end":{"line":56,"column":62}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":8,"column":4},"end":{"line":8,"column":5}},"loc":{"start":{"line":8,"column":18},"end":{"line":10,"column":5}},"line":8},"1":{"name":"(anonymous_1)","decl":{"start":{"line":11,"column":4},"end":{"line":11,"column":5}},"loc":{"start":{"line":11,"column":20},"end":{"line":13,"column":5}},"line":11},"2":{"name":"(anonymous_2)","decl":{"start":{"line":14,"column":4},"end":{"line":14,"column":5}},"loc":{"start":{"line":14,"column":25},"end":{"line":16,"column":5}},"line":14},"3":{"name":"(anonymous_3)","decl":{"start":{"line":17,"column":4},"end":{"line":17,"column":5}},"loc":{"start":{"line":17,"column":39},"end":{"line":19,"column":5}},"line":17},"4":{"name":"(anonymous_4)","decl":{"start":{"line":24,"column":4},"end":{"line":24,"column":5}},"loc":{"start":{"line":24,"column":18},"end":{"line":26,"column":5}},"line":24},"5":{"name":"(anonymous_5)","decl":{"start":{"line":27,"column":4},"end":{"line":27,"column":5}},"loc":{"start":{"line":27,"column":20},"end":{"line":34,"column":5}},"line":27},"6":{"name":"(anonymous_6)","decl":{"start":{"line":28,"column":72},"end":{"line":28,"column":73}},"loc":{"start":{"line":28,"column":82},"end":{"line":32,"column":9}},"line":28},"7":{"name":"(anonymous_7)","decl":{"start":{"line":35,"column":4},"end":{"line":35,"column":5}},"loc":{"start":{"line":35,"column":25},"end":{"line":37,"column":5}},"line":35},"8":{"name":"(anonymous_8)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":32},"end":{"line":40,"column":5}},"line":38},"9":{"name":"(anonymous_9)","decl":{"start":{"line":51,"column":34},"end":{"line":51,"column":35}},"loc":{"start":{"line":51,"column":47},"end":{"line":55,"column":1}},"line":51},"10":{"name":"(anonymous_10)","decl":{"start":{"line":52,"column":36},"end":{"line":52,"column":37}},"loc":{"start":{"line":52,"column":54},"end":{"line":54,"column":5}},"line":52}},"branchMap":{"0":{"loc":{"start":{"line":29,"column":12},"end":{"line":30,"column":37}},"type":"if","locations":[{"start":{"line":29,"column":12},"end":{"line":30,"column":37}},{"start":{"line":29,"column":12},"end":{"line":30,"column":37}}],"line":29}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":2,"11":10,"12":1,"13":9,"14":2,"15":2,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":2,"23":1},"f":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":2,"6":10,"7":2,"8":1,"9":1,"10":2},"b":{"0":[1,9]},"inputSourceMap":{"version":3,"file":"encoder.js","sourceRoot":"","sources":["../../../src/lib/encoder.ts"],"names":[],"mappings":";;;AAAA,uCAAsD;AAGtD,yCAAkD;AAiDlD,2EAA2E;AAC3E,MAAa,qBAAqB;IAAlC;QACE,gBAAW,GAAG,qBAAqB,CAAC;IAatC,CAAC;IAXC,MAAM,CAAC,OAAgB;QACrB,OAAO,IAAA,eAAI,EAAC,IAAA,oBAAS,EAAC,OAAO,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,CAAI,IAAgB,EAAE,MAAoB;QAC9C,OAAO,MAAM,CAAC,KAAK,CAAC,IAAA,oBAAS,EAAC,IAAA,iBAAM,EAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,CAAC,kBAAkB,CAAC,OAA0B;QAClD,IAAA,uBAAY,kBAAG,IAAI,EAAE,CAAC,IAAK,OAAO,EAAG,CAAC;IACxC,CAAC;CACF;AAdD,sDAcC;AAED,qEAAqE;AACrE,MAAa,kBAAkB;IAA/B;QACE,gBAAW,GAAG,kBAAkB,CAAC;IAiBnC,CAAC;IAfC,MAAM,CAAC,OAAgB;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,oBAAS,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvD,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAAe,CAAC,CAAC;YAC9D,OAAO,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,CAAI,IAAgB,EAAE,MAAoB;QAC9C,OAAO,MAAM,CAAC,KAAK,CAAC,IAAA,oBAAS,EAAC,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,CAAC,kBAAkB;QACvB,OAAO;IACT,CAAC;CACF;AAlBD,gDAkBC;AAEY,QAAA,QAAQ,GAAqB;IACxC,IAAI,qBAAqB,EAAE;IAC3B,IAAI,kBAAkB,EAAE;CACzB,CAAC;AAEW,QAAA,eAAe,GAA2B;IACrD,qBAAqB;IACrB,kBAAkB;CACnB,CAAC;AAEK,MAAM,yBAAyB,GAAG,CAAC,OAA0B,EAAQ,EAAE;IAC5E,uBAAe,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE;QACvC,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAJW,QAAA,yBAAyB,6BAIpC"},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"ae8eff2b8e1b622511f9b48080fc41cb60189873"},"/Users/emilianobonilla/Desktop/synnax/freighter/ts/build/main/lib/caseconv.js":{"path":"/Users/emilianobonilla/Desktop/synnax/freighter/ts/build/main/lib/caseconv.js","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":62}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":47}},"2":{"start":{"line":4,"column":26},"end":{"line":4,"column":52}},"3":{"start":{"line":5,"column":16},"end":{"line":9,"column":1}},"4":{"start":{"line":10,"column":18},"end":{"line":10,"column":79}},"5":{"start":{"line":10,"column":30},"end":{"line":10,"column":79}},"6":{"start":{"line":11,"column":0},"end":{"line":11,"column":30}},"7":{"start":{"line":12,"column":18},"end":{"line":12,"column":79}},"8":{"start":{"line":12,"column":30},"end":{"line":12,"column":79}},"9":{"start":{"line":13,"column":0},"end":{"line":13,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":10,"column":18},"end":{"line":10,"column":19}},"loc":{"start":{"line":10,"column":30},"end":{"line":10,"column":79}},"line":10},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":18},"end":{"line":12,"column":19}},"loc":{"start":{"line":12,"column":30},"end":{"line":12,"column":79}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":3,"6":1,"7":1,"8":3,"9":1},"f":{"0":3,"1":3},"b":{},"inputSourceMap":{"version":3,"file":"caseconv.js","sourceRoot":"","sources":["../../../src/lib/caseconv.ts"],"names":[],"mappings":";;;AAAA,qDAGyB;AAEzB,MAAM,OAAO,GAAG;IACd,SAAS,EAAE,IAAI;IACf,gBAAgB,EAAE,IAAI;IACtB,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC;CACnD,CAAC;AAEK,MAAM,SAAS,GAAG,CAAC,MAAe,EAAE,EAAE,CAAC,IAAA,2BAAU,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAA7D,QAAA,SAAS,aAAoD;AACnE,MAAM,SAAS,GAAG,CAAC,MAAe,EAAE,EAAE,CAAC,IAAA,2BAAU,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAA7D,QAAA,SAAS,aAAoD"},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2c0a4e9b289b3ee0df70f50953bef6ea9ed44794"}}
|