Template
1
0

feat: add rest support

This commit is contained in:
2025-04-25 18:41:23 +00:00
parent 1701a07a6c
commit becae62e2a
11 changed files with 980 additions and 143 deletions

View File

@@ -1,7 +1,9 @@
import z, { ZodType } from "zod";
import type { RelayAdapter } from "./adapter.ts";
import { Procedure, type Procedures } from "./procedure.ts";
import type { RelayAdapter, RelayRESTInput } from "./adapter.ts";
import { Procedure } from "./procedure.ts";
import type { Relays } from "./relay.ts";
import { Route } from "./route.ts";
/**
* Make a new relay client instance.
@@ -9,8 +11,8 @@ import { Procedure, type Procedures } from "./procedure.ts";
* @param config - Client configuration.
* @param procedures - Map of procedures to make available to the client.
*/
export function makeRelayClient<TProcedures extends Procedures>(config: RelayClientConfig, procedures: TProcedures): RelayClient<TProcedures> {
return mapProcedures(procedures, config.adapter);
export function makeRelayClient<TRelays extends Relays>(config: RelayClientConfig, relays: TRelays): RelayClient<TRelays> {
return mapRelays(relays, config.adapter);
}
/*
@@ -19,23 +21,59 @@ export function makeRelayClient<TProcedures extends Procedures>(config: RelayCli
|--------------------------------------------------------------------------------
*/
function mapProcedures<TProcedures extends Procedures>(procedures: TProcedures, adapter: RelayAdapter): RelayClient<TProcedures> {
function mapRelays<TRelays extends Relays>(relays: TRelays, adapter: RelayAdapter): RelayClient<TRelays> {
const client: any = {};
for (const key in procedures) {
const entry = procedures[key];
if (entry instanceof Procedure) {
for (const key in relays) {
const relay = relays[key];
if (relay instanceof Procedure) {
client[key] = async (params: unknown) => {
const response = await adapter.send({ method: entry.method, params });
const response = await adapter.send({ method: relay.method, params });
if ("error" in response) {
throw new Error(response.error.message);
}
if ("result" in response && entry.state.result !== undefined) {
return entry.state.result.parseAsync(response.result);
if ("result" in response && relay.state.result !== undefined) {
return relay.state.result.parseAsync(response.result);
}
return response.result;
};
} else if (relay instanceof Route) {
client[key] = async (...args: any[]) => {
const input: RelayRESTInput = { method: relay.state.method, url: `${adapter.url}${relay.state.path}`, query: "" };
let index = 0; // argument incrementor
if (relay.state.params !== undefined) {
const params = args[index++] as { [key: string]: string };
for (const key in params) {
input.url = input.url.replace(`:${key}`, params[key]);
}
}
if (relay.state.query !== undefined) {
const query = args[index++] as { [key: string]: string };
const pieces: string[] = [];
for (const key in query) {
pieces.push(`${key}=${query[key]}`);
}
if (pieces.length > 0) {
input.query = `?${pieces.join("&")}`;
}
}
if (relay.state.body !== undefined) {
input.body = JSON.stringify(args[index++]);
}
// ### Fetch
const data = await adapter.fetch(input);
if (relay.state.output !== undefined) {
return relay.state.output.parse(data);
}
return data;
};
} else {
client[key] = mapProcedures(entry, adapter);
client[key] = mapRelays(relay, adapter);
}
}
return client;
@@ -47,16 +85,20 @@ function mapProcedures<TProcedures extends Procedures>(procedures: TProcedures,
|--------------------------------------------------------------------------------
*/
export type RelayClient<TProcedures extends Procedures> = {
[TKey in keyof TProcedures]: TProcedures[TKey] extends Procedure<infer TState>
export type RelayClient<TRelays extends Relays> = {
[TKey in keyof TRelays]: TRelays[TKey] extends Procedure<infer TState>
? TState["params"] extends ZodType
? (params: z.infer<TState["params"]>) => Promise<TState["result"] extends ZodType ? z.infer<TState["result"]> : void>
: () => Promise<TState["result"] extends ZodType ? z.infer<TState["result"]> : void>
: TProcedures[TKey] extends Procedures
? RelayClient<TProcedures[TKey]>
: never;
: TRelays[TKey] extends Route
? (...args: TRelays[TKey]["args"]) => Promise<RelayRouteResponse<TRelays[TKey]>>
: TRelays[TKey] extends Relays
? RelayClient<TRelays[TKey]>
: never;
};
type RelayRouteResponse<TRoute extends Route> = TRoute["state"]["output"] extends ZodType ? z.infer<TRoute["state"]["output"]> : void;
export type RelayClientConfig = {
adapter: RelayAdapter;
};