mirror of
https://github.com/versia-pub/api.git
synced 2025-12-06 08:28:19 +01:00
refactor(federation): ♻️ Refactor FederationRequester to be simpler
This commit is contained in:
parent
db92a51412
commit
39f27cd87f
21
client/LICENSE
Normal file
21
client/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Lysand
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
21
federation/LICENSE
Normal file
21
federation/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Lysand
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { beforeEach, describe, expect, jest, test } from "bun:test";
|
import { beforeEach, describe, expect, jest, test } from "bun:test";
|
||||||
import { RequestParserHandler } from "../http/index.ts";
|
import { RequestParserHandler } from "./http.ts";
|
||||||
import { EntityValidator } from "../validator/index.ts";
|
import { EntityValidator } from "./validator.ts";
|
||||||
|
|
||||||
// Pulled from social.lysand.org
|
// Pulled from social.lysand.org
|
||||||
const validUser = {
|
const validUser = {
|
||||||
|
|
@ -10,8 +10,8 @@ import type {
|
||||||
ServerMetadata,
|
ServerMetadata,
|
||||||
Undo,
|
Undo,
|
||||||
User,
|
User,
|
||||||
} from "../schemas";
|
} from "./schemas";
|
||||||
import type { EntityValidator } from "../validator/index";
|
import type { EntityValidator } from "./validator";
|
||||||
|
|
||||||
type MaybePromise<T> = T | Promise<T>;
|
type MaybePromise<T> = T | Promise<T>;
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {
|
||||||
type Output,
|
type Output,
|
||||||
ResponseError,
|
ResponseError,
|
||||||
} from "./requester/index";
|
} from "./requester/index";
|
||||||
import { EntityValidator } from "./validator/index";
|
import { EntityValidator } from "./validator";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
EntityValidator,
|
EntityValidator,
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,10 @@ export class ResponseError<
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to handle requests to a remote server.
|
* Class to handle requests to a remote server.
|
||||||
* @param serverUrl The URL of the server to send requests to.
|
|
||||||
* @param signatureConstructor The constructor to sign requests with.
|
* @param signatureConstructor The constructor to sign requests with.
|
||||||
* @param globalCatch A function to call when a request fails.
|
* @param globalCatch A function to call when a request fails.
|
||||||
* @example
|
* @example
|
||||||
* const requester = new FederationRequester(
|
* const requester = new FederationRequester(
|
||||||
* new URL("https://example.com"),
|
|
||||||
* new SignatureConstructor(privateKey, keyId),
|
* new SignatureConstructor(privateKey, keyId),
|
||||||
* );
|
* );
|
||||||
*
|
*
|
||||||
|
|
@ -58,17 +56,12 @@ export class ResponseError<
|
||||||
*/
|
*/
|
||||||
export class FederationRequester {
|
export class FederationRequester {
|
||||||
constructor(
|
constructor(
|
||||||
private serverUrl: URL,
|
|
||||||
private signatureConstructor?: SignatureConstructor,
|
private signatureConstructor?: SignatureConstructor,
|
||||||
public globalCatch: (error: ResponseError) => void = () => {
|
public globalCatch: (error: ResponseError) => void = () => {
|
||||||
// Do nothing by default
|
// Do nothing by default
|
||||||
},
|
},
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
get url(): URL {
|
|
||||||
return this.serverUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the user's profile link from their username.
|
* Get the user's profile link from their username.
|
||||||
* @param username The username to get the profile link for.
|
* @param username The username to get the profile link for.
|
||||||
|
|
@ -84,7 +77,7 @@ export class FederationRequester {
|
||||||
*/
|
*/
|
||||||
public async webFinger(
|
public async webFinger(
|
||||||
username: string,
|
username: string,
|
||||||
hostname = this.serverUrl.hostname,
|
hostname: string,
|
||||||
contentType = "application/json",
|
contentType = "application/json",
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const result = await this.get<User>(
|
const result = await this.get<User>(
|
||||||
|
|
@ -185,7 +178,7 @@ export class FederationRequester {
|
||||||
|
|
||||||
headers.set("Accept", "application/json");
|
headers.set("Accept", "application/json");
|
||||||
|
|
||||||
const request = new Request(new URL(path, this.serverUrl).toString(), {
|
const request = new Request(path, {
|
||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
body: body
|
body: body
|
||||||
|
|
@ -201,6 +194,12 @@ export class FederationRequester {
|
||||||
: request;
|
: request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a GET request to a URL.
|
||||||
|
* @param path The path to make the request to.
|
||||||
|
* @param extra Any extra options to pass to the fetch function.
|
||||||
|
* @returns The data returned by the request.
|
||||||
|
*/
|
||||||
public async get<ReturnType>(
|
public async get<ReturnType>(
|
||||||
path: string,
|
path: string,
|
||||||
extra?: RequestInit,
|
extra?: RequestInit,
|
||||||
|
|
@ -213,19 +212,13 @@ export class FederationRequester {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static get<ReturnType>(
|
/**
|
||||||
url: string | URL,
|
* Make a POST request to a URL.
|
||||||
extra?: RequestInit,
|
* @param path The path to make the request to.
|
||||||
): Promise<Output<ReturnType>> {
|
* @param body The body of the request.
|
||||||
const urlUrl = new URL(url);
|
* @param extra Any extra options to pass to the fetch function.
|
||||||
const requester = new FederationRequester(urlUrl);
|
* @returns The data returned by the request.
|
||||||
|
*/
|
||||||
return requester.get<ReturnType>(
|
|
||||||
urlUrl.pathname + urlUrl.search,
|
|
||||||
extra,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async post<ReturnType>(
|
public async post<ReturnType>(
|
||||||
path: string,
|
path: string,
|
||||||
body: object,
|
body: object,
|
||||||
|
|
@ -238,19 +231,4 @@ export class FederationRequester {
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static post<ReturnType>(
|
|
||||||
url: string,
|
|
||||||
body: object,
|
|
||||||
extra?: RequestInit,
|
|
||||||
): Promise<Output<ReturnType>> {
|
|
||||||
const urlUrl = new URL(url);
|
|
||||||
const requester = new FederationRequester(urlUrl);
|
|
||||||
|
|
||||||
return requester.post<ReturnType>(
|
|
||||||
urlUrl.pathname + urlUrl.search,
|
|
||||||
body,
|
|
||||||
extra,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
/**
|
||||||
|
* @file TypeScript type definitions
|
||||||
|
* @module federation/types
|
||||||
|
*/
|
||||||
|
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import type {
|
import type {
|
||||||
ActionSchema,
|
ActionSchema,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import {
|
||||||
UserSchema,
|
UserSchema,
|
||||||
VanityExtensionSchema,
|
VanityExtensionSchema,
|
||||||
VisibilitySchema,
|
VisibilitySchema,
|
||||||
} from "../schemas/base";
|
} from "./schemas/base";
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: Used only as a base type
|
// biome-ignore lint/suspicious/noExplicitAny: Used only as a base type
|
||||||
type AnyZod = z.ZodType<any, any, any>;
|
type AnyZod = z.ZodType<any, any, any>;
|
||||||
Loading…
Reference in a new issue