diff --git a/fern/apis/fdr/definition/docsCache.yml b/fern/apis/fdr/definition/docsCache.yml new file mode 100644 index 0000000000..e09230fdf7 --- /dev/null +++ b/fern/apis/fdr/definition/docsCache.yml @@ -0,0 +1,15 @@ +imports: + commons: commons.yml + +service: + base-path: /docs-cache + auth: true + endpoints: + invalidate: + method: POST + path: /invalidate + request: + name: InvalidateCachedDocsRequest + body: + properties: + url: string diff --git a/packages/fdr-sdk/src/client/generated/Client.ts b/packages/fdr-sdk/src/client/generated/Client.ts index 91547c78d3..92db2ee8d2 100644 --- a/packages/fdr-sdk/src/client/generated/Client.ts +++ b/packages/fdr-sdk/src/client/generated/Client.ts @@ -7,6 +7,7 @@ import * as core from "./core"; import { Api } from "./api/resources/api/client/Client"; import { Docs } from "./api/resources/docs/client/Client"; import { Diff } from "./api/resources/diff/client/Client"; +import { DocsCache } from "./api/resources/docsCache/client/Client"; import { SnippetsFactory } from "./api/resources/snippetsFactory/client/Client"; import { Snippets } from "./api/resources/snippets/client/Client"; import { Templates } from "./api/resources/templates/client/Client"; @@ -44,6 +45,12 @@ export class FernRegistryClient { return (this._diff ??= new Diff(this._options)); } + protected _docsCache: DocsCache | undefined; + + public get docsCache(): DocsCache { + return (this._docsCache ??= new DocsCache(this._options)); + } + protected _snippetsFactory: SnippetsFactory | undefined; public get snippetsFactory(): SnippetsFactory { diff --git a/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/Client.ts b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/Client.ts new file mode 100644 index 0000000000..24a42b538f --- /dev/null +++ b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/Client.ts @@ -0,0 +1,67 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as environments from "../../../../environments"; +import * as core from "../../../../core"; +import * as FernRegistry from "../../.."; +import urlJoin from "url-join"; + +export declare namespace DocsCache { + interface Options { + environment?: core.Supplier; + token?: core.Supplier; + } + + interface RequestOptions { + timeoutInSeconds?: number; + maxRetries?: number; + } +} + +export class DocsCache { + constructor(protected readonly _options: DocsCache.Options = {}) {} + + public async invalidate( + request: FernRegistry.InvalidateCachedDocsRequest, + requestOptions?: DocsCache.RequestOptions + ): Promise> { + const _response = await core.fetcher({ + url: urlJoin( + (await core.Supplier.get(this._options.environment)) ?? environments.FernRegistryEnvironment.Dev, + "/docs-cache/invalidate" + ), + method: "POST", + headers: { + Authorization: await this._getAuthorizationHeader(), + "X-Fern-Language": "JavaScript", + "X-Fern-Runtime": core.RUNTIME.type, + "X-Fern-Runtime-Version": core.RUNTIME.version, + }, + contentType: "application/json", + body: request, + timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : undefined, + maxRetries: requestOptions?.maxRetries, + }); + if (_response.ok) { + return { + ok: true, + body: undefined, + }; + } + + return { + ok: false, + error: FernRegistry.docsCache.invalidate.Error._unknown(_response.error), + }; + } + + protected async _getAuthorizationHeader() { + const bearer = await core.Supplier.get(this._options.token); + if (bearer != null) { + return `Bearer ${bearer}`; + } + + return undefined; + } +} diff --git a/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/index.ts b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/index.ts new file mode 100644 index 0000000000..be97ba4d54 --- /dev/null +++ b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/index.ts @@ -0,0 +1,2 @@ +export * from "./requests"; +export * as invalidate from "./invalidate"; diff --git a/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/invalidate.ts b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/invalidate.ts new file mode 100644 index 0000000000..2c6789fd55 --- /dev/null +++ b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/invalidate.ts @@ -0,0 +1,38 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as FernRegistry from "../../.."; +import * as core from "../../../../core"; + +export type Error = FernRegistry.docsCache.invalidate.Error._Unknown; + +export declare namespace Error { + interface _Unknown { + error: void; + content: core.Fetcher.Error; + } + + interface _Visitor<_Result> { + _other: (value: core.Fetcher.Error) => _Result; + } +} + +export const Error = { + _unknown: (fetcherError: core.Fetcher.Error): FernRegistry.docsCache.invalidate.Error._Unknown => { + return { + error: undefined, + content: fetcherError, + }; + }, + + _visit: <_Result>( + value: FernRegistry.docsCache.invalidate.Error, + visitor: FernRegistry.docsCache.invalidate.Error._Visitor<_Result> + ): _Result => { + switch (value.error) { + default: + return visitor._other(value as any); + } + }, +} as const; diff --git a/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/requests/InvalidateCachedDocsRequest.ts b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/requests/InvalidateCachedDocsRequest.ts new file mode 100644 index 0000000000..b916a9ac01 --- /dev/null +++ b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/requests/InvalidateCachedDocsRequest.ts @@ -0,0 +1,7 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +export interface InvalidateCachedDocsRequest { + url: string; +} diff --git a/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/requests/index.ts b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/requests/index.ts new file mode 100644 index 0000000000..2860c062b0 --- /dev/null +++ b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/client/requests/index.ts @@ -0,0 +1 @@ +export { InvalidateCachedDocsRequest } from "./InvalidateCachedDocsRequest"; diff --git a/packages/fdr-sdk/src/client/generated/api/resources/docsCache/index.ts b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/index.ts new file mode 100644 index 0000000000..5ec76921e1 --- /dev/null +++ b/packages/fdr-sdk/src/client/generated/api/resources/docsCache/index.ts @@ -0,0 +1 @@ +export * from "./client"; diff --git a/packages/fdr-sdk/src/client/generated/api/resources/index.ts b/packages/fdr-sdk/src/client/generated/api/resources/index.ts index 3f7b41ba8e..9e44aab683 100644 --- a/packages/fdr-sdk/src/client/generated/api/resources/index.ts +++ b/packages/fdr-sdk/src/client/generated/api/resources/index.ts @@ -10,7 +10,9 @@ export * as snippets from "./snippets"; export * from "./snippets/types"; export * as templates from "./templates"; export * from "./templates/types"; +export * as docsCache from "./docsCache"; export * from "./diff/client/requests"; +export * from "./docsCache/client/requests"; export * from "./snippetsFactory/client/requests"; export * from "./snippets/client/requests"; export * from "./templates/client/requests"; diff --git a/servers/fdr/src/__test__/local/services/docsCache.test.ts b/servers/fdr/src/__test__/local/services/docsCache.test.ts new file mode 100644 index 0000000000..e4c2dee1bc --- /dev/null +++ b/servers/fdr/src/__test__/local/services/docsCache.test.ts @@ -0,0 +1,35 @@ +import { DocsV1Write } from "@fern-api/fdr-sdk"; +import { inject } from "vitest"; +import { getAPIResponse, getClient } from "../util"; + +export const WRITE_DOCS_REGISTER_DEFINITION: DocsV1Write.DocsDefinition = { + pages: {}, + config: { + navigation: { + items: [], + }, + }, +}; + +it("docs invalidate cache", async () => { + const fdr = getClient({ authed: true, url: inject("url") }); + const domain = `docs-${Math.random()}.fern.com`; + + // register docs + const startDocsRegisterResponse = getAPIResponse( + await fdr.docs.v1.write.startDocsRegister({ + orgId: "fern", + domain, + filepaths: ["logo.png", "guides/guide.mdx"], + }), + ); + await fdr.docs.v1.write.finishDocsRegister(startDocsRegisterResponse.docsRegistrationId, { + docsDefinition: WRITE_DOCS_REGISTER_DEFINITION, + }); + + const response = await fdr.docsCache.invalidate({ + url: `https://${domain}`, + }); + + expect(response.ok).toEqual(true); +}); diff --git a/servers/fdr/src/__test__/local/setupMockFdr.ts b/servers/fdr/src/__test__/local/setupMockFdr.ts index c714b60d0a..436e50fd6d 100644 --- a/servers/fdr/src/__test__/local/setupMockFdr.ts +++ b/servers/fdr/src/__test__/local/setupMockFdr.ts @@ -8,6 +8,7 @@ import { FdrApplication, FdrConfig } from "../../app"; import { getReadApiService } from "../../controllers/api/getApiReadService"; import { getRegisterApiService } from "../../controllers/api/getRegisterApiService"; import { getApiDiffService } from "../../controllers/diff/getApiDiffService"; +import { getDocsCacheService } from "../../controllers/docs-cache/getDocsCacheService"; import { getDocsReadService } from "../../controllers/docs/v1/getDocsReadService"; import { getDocsWriteService } from "../../controllers/docs/v1/getDocsWriteService"; import { getDocsReadV2Service } from "../../controllers/docs/v2/getDocsReadV2Service"; @@ -100,6 +101,7 @@ async function runMockFdr(port: number): Promise { snippetsFactory: getSnippetsFactoryService(fdrApplication), templates: getTemplatesService(fdrApplication), diff: getApiDiffService(fdrApplication), + docsCache: getDocsCacheService(fdrApplication), }); const server = app.listen(port); console.log(`Mock FDR server running on http://localhost:${port}/`); diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/index.d.ts b/servers/fdr/src/api/generated/api/resources/docsCache/index.d.ts new file mode 100644 index 0000000000..6261f89636 --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/index.d.ts @@ -0,0 +1 @@ +export * from "./service"; diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/index.js b/servers/fdr/src/api/generated/api/resources/docsCache/index.js new file mode 100644 index 0000000000..6261f89636 --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/index.js @@ -0,0 +1 @@ +export * from "./service"; diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/service/DocsCacheService.d.ts b/servers/fdr/src/api/generated/api/resources/docsCache/service/DocsCacheService.d.ts new file mode 100644 index 0000000000..b98bc941b9 --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/service/DocsCacheService.d.ts @@ -0,0 +1,19 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +import * as FernRegistry from "../../.."; +import express from "express"; +export interface DocsCacheServiceMethods { + invalidate(req: express.Request, res: { + send: () => Promise; + cookie: (cookie: string, value: string, options?: express.CookieOptions) => void; + locals: any; + }): void | Promise; +} +export declare class DocsCacheService { + private readonly methods; + private router; + constructor(methods: DocsCacheServiceMethods, middleware?: express.RequestHandler[]); + addMiddleware(handler: express.RequestHandler): this; + toRouter(): express.Router; +} diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/service/DocsCacheService.js b/servers/fdr/src/api/generated/api/resources/docsCache/service/DocsCacheService.js new file mode 100644 index 0000000000..eca50f9b0e --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/service/DocsCacheService.js @@ -0,0 +1,54 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import express from "express"; +import * as errors from "../../../../errors"; +export class DocsCacheService { + constructor(methods, middleware = []) { + this.methods = methods; + this.router = express.Router({ mergeParams: true }).use(express.json({ + strict: false, + }), ...middleware); + } + addMiddleware(handler) { + this.router.use(handler); + return this; + } + toRouter() { + this.router.post("/invalidate", (req, res, next) => __awaiter(this, void 0, void 0, function* () { + try { + yield this.methods.invalidate(req, { + send: () => __awaiter(this, void 0, void 0, function* () { + res.sendStatus(204); + }), + cookie: res.cookie.bind(res), + locals: res.locals, + }); + next(); + } + catch (error) { + console.error(error); + if (error instanceof errors.FernRegistryError) { + console.warn(`Endpoint 'invalidate' unexpectedly threw ${error.constructor.name}.` + + ` If this was intentional, please add ${error.constructor.name} to` + + " the endpoint's errors list in your Fern Definition."); + yield error.send(res); + } + else { + res.status(500).json("Internal Server Error"); + } + next(error); + } + })); + return this.router; + } +} diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/service/index.d.ts b/servers/fdr/src/api/generated/api/resources/docsCache/service/index.d.ts new file mode 100644 index 0000000000..415726b7fe --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/service/index.d.ts @@ -0,0 +1 @@ +export * from "./requests"; diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/service/index.js b/servers/fdr/src/api/generated/api/resources/docsCache/service/index.js new file mode 100644 index 0000000000..415726b7fe --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/service/index.js @@ -0,0 +1 @@ +export * from "./requests"; diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/InvalidateCachedDocsRequest.d.ts b/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/InvalidateCachedDocsRequest.d.ts new file mode 100644 index 0000000000..5207218a6d --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/InvalidateCachedDocsRequest.d.ts @@ -0,0 +1,6 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +export interface InvalidateCachedDocsRequest { + url: string; +} diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/InvalidateCachedDocsRequest.js b/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/InvalidateCachedDocsRequest.js new file mode 100644 index 0000000000..0b46289f5b --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/InvalidateCachedDocsRequest.js @@ -0,0 +1,4 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +export {}; diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/index.d.ts b/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/index.d.ts new file mode 100644 index 0000000000..2860c062b0 --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/index.d.ts @@ -0,0 +1 @@ +export { InvalidateCachedDocsRequest } from "./InvalidateCachedDocsRequest"; diff --git a/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/index.js b/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/index.js new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/servers/fdr/src/api/generated/api/resources/docsCache/service/requests/index.js @@ -0,0 +1 @@ +export {}; diff --git a/servers/fdr/src/api/generated/api/resources/index.d.ts b/servers/fdr/src/api/generated/api/resources/index.d.ts index 1fcb565aa2..ff520caf79 100644 --- a/servers/fdr/src/api/generated/api/resources/index.d.ts +++ b/servers/fdr/src/api/generated/api/resources/index.d.ts @@ -10,6 +10,8 @@ export * as snippets from "./snippets"; export * from "./snippets/types"; export * as templates from "./templates"; export * from "./templates/types"; +export * as docsCache from "./docsCache"; +export * from "./docsCache/service/requests"; export * from "./snippetsFactory/service/requests"; export * from "./snippets/service/requests"; export * from "./templates/service/requests"; diff --git a/servers/fdr/src/api/generated/api/resources/index.js b/servers/fdr/src/api/generated/api/resources/index.js index 1fcb565aa2..ff520caf79 100644 --- a/servers/fdr/src/api/generated/api/resources/index.js +++ b/servers/fdr/src/api/generated/api/resources/index.js @@ -10,6 +10,8 @@ export * as snippets from "./snippets"; export * from "./snippets/types"; export * as templates from "./templates"; export * from "./templates/types"; +export * as docsCache from "./docsCache"; +export * from "./docsCache/service/requests"; export * from "./snippetsFactory/service/requests"; export * from "./snippets/service/requests"; export * from "./templates/service/requests"; diff --git a/servers/fdr/src/api/generated/register.d.ts b/servers/fdr/src/api/generated/register.d.ts index a49142d28a..ad1725e8db 100644 --- a/servers/fdr/src/api/generated/register.d.ts +++ b/servers/fdr/src/api/generated/register.d.ts @@ -3,6 +3,7 @@ */ import express from "express"; import { DiffService } from "./api/resources/diff/service/DiffService"; +import { DocsCacheService } from "./api/resources/docsCache/service/DocsCacheService"; import { SnippetsFactoryService } from "./api/resources/snippetsFactory/service/SnippetsFactoryService"; import { SnippetsService } from "./api/resources/snippets/service/SnippetsService"; import { TemplatesService } from "./api/resources/templates/service/TemplatesService"; @@ -14,6 +15,7 @@ import { ReadService as docs_v2_read_RootService } from "./api/resources/docs/re import { WriteService as docs_v2_write_RootService } from "./api/resources/docs/resources/v2/resources/write/service/WriteService"; export declare function register(expressApp: express.Express | express.Router, services: { diff: DiffService; + docsCache: DocsCacheService; snippetsFactory: SnippetsFactoryService; snippets: SnippetsService; templates: TemplatesService; diff --git a/servers/fdr/src/api/generated/register.js b/servers/fdr/src/api/generated/register.js index e6d9a3e3da..906ddca97a 100644 --- a/servers/fdr/src/api/generated/register.js +++ b/servers/fdr/src/api/generated/register.js @@ -9,6 +9,7 @@ export function register(expressApp, services) { expressApp.use("/v2/registry/docs", services.docs.v2.read._root.toRouter()); expressApp.use("/v2/registry/docs", services.docs.v2.write._root.toRouter()); expressApp.use("/registry", services.diff.toRouter()); + expressApp.use("/docs-cache", services.docsCache.toRouter()); expressApp.use("/snippets", services.snippetsFactory.toRouter()); expressApp.use("/snippets", services.snippets.toRouter()); expressApp.use("/snippet-template", services.templates.toRouter()); diff --git a/servers/fdr/src/controllers/docs-cache/getDocsCacheService.ts b/servers/fdr/src/controllers/docs-cache/getDocsCacheService.ts new file mode 100644 index 0000000000..0f68132f19 --- /dev/null +++ b/servers/fdr/src/controllers/docs-cache/getDocsCacheService.ts @@ -0,0 +1,12 @@ +import { DocsCacheService } from "../../api/generated/api/resources/docsCache/service/DocsCacheService"; +import { type FdrApplication } from "../../app"; +import { ParsedBaseUrl } from "../../util/ParsedBaseUrl"; + +export function getDocsCacheService(app: FdrApplication): DocsCacheService { + return new DocsCacheService({ + invalidate: async (req, res) => { + await app.docsDefinitionCache.invalidateCache(ParsedBaseUrl.parse(req.body.url).toURL()); + return res.send(); + }, + }); +} diff --git a/servers/fdr/src/server.ts b/servers/fdr/src/server.ts index 4afeab902f..a246ff7a0f 100644 --- a/servers/fdr/src/server.ts +++ b/servers/fdr/src/server.ts @@ -9,6 +9,7 @@ import { registerBackgroundTasks } from "./background"; import { getReadApiService } from "./controllers/api/getApiReadService"; import { getRegisterApiService } from "./controllers/api/getRegisterApiService"; import { getApiDiffService } from "./controllers/diff/getApiDiffService"; +import { getDocsCacheService } from "./controllers/docs-cache/getDocsCacheService"; import { getDocsReadService } from "./controllers/docs/v1/getDocsReadService"; import { getDocsWriteService } from "./controllers/docs/v1/getDocsWriteService"; import { getDocsReadV2Service } from "./controllers/docs/v2/getDocsReadV2Service"; @@ -109,6 +110,7 @@ async function startServer(): Promise { snippetsFactory: getSnippetsFactoryService(app), templates: getTemplatesService(app), diff: getApiDiffService(app), + docsCache: getDocsCacheService(app), }); registerBackgroundTasks(app); app.logger.info(`Listening for requests on port ${PORT}`); diff --git a/servers/fdr/src/services/docs-cache/DocsDefinitionCache.ts b/servers/fdr/src/services/docs-cache/DocsDefinitionCache.ts index 6903436f2e..2e87701925 100644 --- a/servers/fdr/src/services/docs-cache/DocsDefinitionCache.ts +++ b/servers/fdr/src/services/docs-cache/DocsDefinitionCache.ts @@ -29,6 +29,8 @@ export interface DocsDefinitionCache { initialize(): Promise; isInitialized(): boolean; + + invalidateCache(url: URL): Promise; } /** @@ -81,6 +83,13 @@ export class DocsDefinitionCacheImpl implements DocsDefinitionCache { return monitor; } + public async invalidateCache(url: URL): Promise { + if (this.redisDocsCache) { + await this.redisDocsCache.delete({ url }); + } + this.localDocsCache.delete({ url }); + } + public async getDocsForUrl({ url, authorization, diff --git a/servers/fdr/src/services/docs-cache/LocalDocsDefinitionStore.ts b/servers/fdr/src/services/docs-cache/LocalDocsDefinitionStore.ts index 633be4991d..0df6bd53a5 100644 --- a/servers/fdr/src/services/docs-cache/LocalDocsDefinitionStore.ts +++ b/servers/fdr/src/services/docs-cache/LocalDocsDefinitionStore.ts @@ -14,4 +14,9 @@ export default class LocalDocsDefinitionStore { set({ url, value }: { url: URL; value: CachedDocsResponse }): void { this.localCache[(url.hostname, JSON.stringify(value))]; } + + delete({ url }: { url: URL }): void { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this.localCache[url.hostname]; + } } diff --git a/servers/fdr/src/services/docs-cache/RedisDocsDefinitionStore.ts b/servers/fdr/src/services/docs-cache/RedisDocsDefinitionStore.ts index 334e1ee49f..ed0ce392b5 100644 --- a/servers/fdr/src/services/docs-cache/RedisDocsDefinitionStore.ts +++ b/servers/fdr/src/services/docs-cache/RedisDocsDefinitionStore.ts @@ -43,4 +43,8 @@ export default class RedisDocsDefinitionStore { public async set({ url, value }: { url: URL; value: CachedDocsResponse }): Promise { await this.client.set(url.hostname, JSON.stringify(value)); } + + public async delete({ url }: { url: URL }): Promise { + await this.client.del(url.hostname); + } }