Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | 1x 1x 1x 1x 1x 1x 1x 9x 9x 9x 9x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import { Api, Endpoint, SimpleMeta, Duplex, ApiTypeOf } from "estuary-rpc";
import { ApiContext, RestEndpoints, ServerOpts, WsEndpoints } from "./types";
import { methodId } from "./middleware";
import { createRestHandler, restEndpoint } from "./rest";
import { createServer, Server } from "http";
import { createWsServer, wsEndpoint } from "./ws";
function flattenApi<T extends Api<unknown, Meta>, Meta extends SimpleMeta>(
api: ApiTypeOf<ApiContext, unknown, T>,
apiMeta: ApiTypeOf<unknown, Meta, T>,
serverOpts: ServerOpts<Meta>
): [RestEndpoints, WsEndpoints] {
const restEndpoints: RestEndpoints = {};
const wsEndpoints: WsEndpoints = {};
Object.keys(apiMeta).forEach((apiName: string) => {
if (typeof apiMeta[apiName] === "function") {
const meta = apiMeta[apiName] as Meta;
Iif (meta.method === "WS") {
wsEndpoints[methodId(meta)] = wsEndpoint(
api[apiName] as Endpoint<
Duplex<unknown, unknown>,
void,
ApiContext,
unknown
>,
meta,
serverOpts
);
} else {
restEndpoints[methodId(meta)] = restEndpoint(
api[apiName] as Endpoint<unknown, unknown, ApiContext, unknown>,
meta,
serverOpts
);
}
} else E{
const [childRest, childWs] = flattenApi(
api[apiName] as any,
apiMeta[apiName] as any,
serverOpts
);
Object.assign(restEndpoints, childRest);
Object.assign(wsEndpoints, childWs);
}
});
return [restEndpoints, wsEndpoints];
}
/**
* createApiServer is the primary method through which your server code will interact with estuary-rpc.
* Calling it will set up an 'http' server (or serve on {@link ServerOpts.server}, an `https` one say), listening on
* {@link ServerOpts.port} if given, and return it. It answers HTTP and WS connections and appropriately
* forwards data to your endpoint implementations, taking into account underlying transport encodeings,
* authentication tokens, and the wonkiness of dealing with WebSockets
* @param api Your API definition, the collection of all the endpoint implementations
* @param description Your API Metadata definition, defined in common code with your client
* @param serverOpts options for configuring the server
* * @example
* ```ts
* // Common Code
* export interface ExampleApi<Closure, Meta> extends Api<Closure, Meta> {
* foo: FooService<Closure, Meta>;
* fileUpload: Endpoint<void, void, Closure, Meta>;
* }
*
* export interface FooService<Closure, Meta> extends Api<Closure, Meta> {
* emptyPost: Endpoint<void, void, Closure, Meta>;
* simpleGet: Endpoint<number, number, Closure, Meta>;
* simpleStream: StreamDesc<string, boolean, Closure, Meta>;
* }
*
* export const exampleApiMeta: ExampleApi<never, ExampleMeta> = {
* foo: {
* emptyPost: post("foo/emptyPost"),
* simpleGet: get("foo/simpleGet", { authentication: "bearer", token: "" }),
* simpleStream: ws("foo/simpleStream"),
* },
* fileUpload: post("fileUpload", { uploads: ["someFile.txt"] }),
* };
*
* // Server Code
* const server: ExampleApi<ApiContext, unknown> = {
* foo: {
* emptyPost: async () => {
* console.log("got post");
* },
* simpleGet: async (num: number) => 4,
* simpleStream: async ({ server }: Duplex<string, boolean>) => {
* server.on("message", (input: string) => {
* console.log("Got message", input);
* server.write(input === "foo");
* });
* },
* } as FooService<ApiContext, unknown>,
*
* fileUpload: (_1: void, _2: ApiContext) => {
* return null;
* },
* };
* ```
* @group Server
*/
export function createApiServer<
Meta extends SimpleMeta,
T extends Api<unknown, Meta>
>(
api: ApiTypeOf<ApiContext, unknown, T>,
apiMeta: ApiTypeOf<unknown, Meta, T>,
serverOpts: ServerOpts<Meta>
): Server {
const [restEndpoints, wsEndpoints] = flattenApi(api, apiMeta, serverOpts);
const server = serverOpts.server ?? createServer();
server.on("request", createRestHandler(restEndpoints, serverOpts));
createWsServer(server, wsEndpoints, serverOpts);
Iif (serverOpts.port !== undefined) {
server.listen(serverOpts.port);
}
return server;
}
export * from "estuary-rpc";
export * from "./authentication";
export * from "./errors";
export * from "./middleware";
export * from "./multipart";
export * from "./rest";
export * from "./types";
export * from "./ws";
|