Loading .vscode/settings.json +1 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ "activitypub", "aitertools", "apidoc", "astro", "bccs", "btos", "callouts", Loading CHANGES.md +9 −0 Original line number Diff line number Diff line Loading @@ -96,17 +96,26 @@ To be released. loader that throws an error when the given URL is not an HTTP or HTTPS URL or refers to a private network address. - Added `@fedify/fedify/x/astro` module for integrating with [Astro] middleware. [[#50]] - Added `createMiddleware()` function. - Added `createFetchOptions()` function. - Added `ContextDataFactory` type. - Added more log messages using the [LogTape] library. Currently the below logger categories are used: - `["fedify", "federation", "queue"]` [#50]: https://github.com/dahlia/fedify/issues/50 [#53]: https://github.com/dahlia/fedify/issues/53 [#66]: https://github.com/dahlia/fedify/issues/66 [#70]: https://github.com/dahlia/fedify/issues/70 [#81]: https://github.com/dahlia/fedify/issues/81 [#85]: https://github.com/dahlia/fedify/issues/85 [#92]: https://github.com/dahlia/fedify/pull/92 [Astro]: https://astro.build/ Version 0.11.2 Loading deno.json +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ "./sig": "./sig/mod.ts", "./vocab": "./vocab/mod.ts", "./webfinger": "./webfinger/mod.ts", "./x/astro": "./x/astro.ts", "./x/denokv": "./x/denokv.ts", "./x/fresh": "./x/fresh.ts", "./x/hono": "./x/hono.ts" Loading x/astro.ts 0 → 100644 +140 −0 Original line number Diff line number Diff line /** * Fedify with Astro * ================= * * This module contains some utilities for integrating Fedify with * the [Astro] framework. * * [Astro]: https://astro.build/ * * @module * @since 0.12.0 */ import type { Federation, FederationFetchOptions, } from "../federation/middleware.ts"; interface AstroContext { request: Request; } type RewritePayload = string | URL | Request; type MiddlewareNext = ( rewritePayload?: RewritePayload, ) => Promise<Response>; type MiddlewareHandler<TAstroContext extends AstroContext> = ( context: TAstroContext, next: MiddlewareNext, ) => Promise<Response> | Response | Promise<void> | void; /** * Create options for the {@link Federation.fetch} method to integrate with * Astro. * * @example src/middleware.ts * ``` typescript * import { defineMiddleware } from "astro:middleware"; * import { federation } from "./federation"; // Import the `Federation` object * * export const onRequest = defineMiddleware((context, next) => { * return federation.fetch(context.request, { * contextData: undefined, * ...createFetchOptions(context, next), * }); * }); * ``` * * @typeParam TAstroContext A type of the Astro context. * @param context An Astro context. * @param next A function to call the next middleware. * @returns Options for the {@link Federation.fetch} method. * @since 0.12.0 */ export function createFetchOptions<TAstroContext extends AstroContext>( _context: TAstroContext, next: MiddlewareNext, ): Omit<FederationFetchOptions<void>, "contextData"> { return { // If the `federation` object finds a request not responsible for it // (i.e., not a federation-related request), it will call the `next` // provided by the Astro framework to continue the request handling // by Astro: onNotFound: next, // Similar to `onNotFound`, but slightly more tricky one. // When the `federation` object finds a request not acceptable type-wise // (i.e., a user-agent doesn't want JSON-LD), it will call the `next` // provided by the Astro framework so that it renders HTML if there's some // page. Otherwise, it will simply return a 406 Not Acceptable response. // This kind of trick enables the Fedify and Astro to share the same routes // and they do content negotiation depending on `Accept` header: async onNotAcceptable(_request: Request) { const response = await next(); if (response.status !== 404) return response; return new Response("Not acceptable", { status: 406, headers: { "Content-Type": "text/plain", Vary: "Accept", }, }); }, }; } /** * The factory function to create a context data for * the {@link Federation.fetch}. * * @typeParam TContextData A type of the context data. * @typeParam TAstroContext A type of the Astro context. * @param context An Astro context. * @returns The context data for the {@link Federation.fetch}. * @since 0.12.0 */ export type ContextDataFactory< TContextData, TAstroContext extends AstroContext, > = ( context: TAstroContext, ) => TContextData | Promise<TContextData>; /** * Create an Astro middleware handler to integrate with the {@link Federation} * object. * * @example src/middleware.ts * ``` typescript * import type { MiddlewareHandler } from "astro"; * import { federation } from "./federation"; // Import the `Federation` object * * export const onRequest: MiddlewareHandler = createMiddleware( * federation, * (astroContext) => "context data", * ); * ``` * * @typeParam TContextData A type of the context data for the {@link Federation} * object. * @typeParam TAstroContext A type of the Astro context. * @param federation A {@link Federation} object to integrate with Astro. * @param contextDataFactory A factory function to create a context data for the * {@link Federation} object. * @returns An Astro middleware handler. * @since 0.12.0 */ export function createMiddleware< TContextData, TAstroContext extends AstroContext, >( federation: Federation<TContextData>, contextDataFactory: ContextDataFactory<TContextData, TAstroContext>, ): MiddlewareHandler<TAstroContext> { return async (context, next) => { const contextData = await contextDataFactory(context); return await federation.fetch(context.request, { contextData, ...createFetchOptions(context, next), }); }; } x/fresh.ts +4 −3 Original line number Diff line number Diff line Loading @@ -20,7 +20,8 @@ interface FreshContext { } /** * Create options for the `federation` object to integrate with Fresh. * Create options for the {@link Federation.fetch} method to integrate with * Fresh. * * @example _middleware.ts * ``` typescript Loading Loading @@ -88,6 +89,7 @@ export function integrateFetchOptions( * @param createContextData A function to create a context data for the * {@link Federation} object. * @returns A Fresh middleware handler. * @since 0.4.0 */ export function integrateHandler< TContextData, Loading @@ -103,8 +105,7 @@ export function integrateHandler< request: Request, context: TFreshContext, ): Promise<Response> => { let contextData = createContextData(request, context); if (contextData instanceof Promise) contextData = await contextData; const contextData = await createContextData(request, context); return await federation.fetch(request, { contextData, ...integrateFetchOptions(context), Loading Loading
.vscode/settings.json +1 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ "activitypub", "aitertools", "apidoc", "astro", "bccs", "btos", "callouts", Loading
CHANGES.md +9 −0 Original line number Diff line number Diff line Loading @@ -96,17 +96,26 @@ To be released. loader that throws an error when the given URL is not an HTTP or HTTPS URL or refers to a private network address. - Added `@fedify/fedify/x/astro` module for integrating with [Astro] middleware. [[#50]] - Added `createMiddleware()` function. - Added `createFetchOptions()` function. - Added `ContextDataFactory` type. - Added more log messages using the [LogTape] library. Currently the below logger categories are used: - `["fedify", "federation", "queue"]` [#50]: https://github.com/dahlia/fedify/issues/50 [#53]: https://github.com/dahlia/fedify/issues/53 [#66]: https://github.com/dahlia/fedify/issues/66 [#70]: https://github.com/dahlia/fedify/issues/70 [#81]: https://github.com/dahlia/fedify/issues/81 [#85]: https://github.com/dahlia/fedify/issues/85 [#92]: https://github.com/dahlia/fedify/pull/92 [Astro]: https://astro.build/ Version 0.11.2 Loading
deno.json +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ "./sig": "./sig/mod.ts", "./vocab": "./vocab/mod.ts", "./webfinger": "./webfinger/mod.ts", "./x/astro": "./x/astro.ts", "./x/denokv": "./x/denokv.ts", "./x/fresh": "./x/fresh.ts", "./x/hono": "./x/hono.ts" Loading
x/astro.ts 0 → 100644 +140 −0 Original line number Diff line number Diff line /** * Fedify with Astro * ================= * * This module contains some utilities for integrating Fedify with * the [Astro] framework. * * [Astro]: https://astro.build/ * * @module * @since 0.12.0 */ import type { Federation, FederationFetchOptions, } from "../federation/middleware.ts"; interface AstroContext { request: Request; } type RewritePayload = string | URL | Request; type MiddlewareNext = ( rewritePayload?: RewritePayload, ) => Promise<Response>; type MiddlewareHandler<TAstroContext extends AstroContext> = ( context: TAstroContext, next: MiddlewareNext, ) => Promise<Response> | Response | Promise<void> | void; /** * Create options for the {@link Federation.fetch} method to integrate with * Astro. * * @example src/middleware.ts * ``` typescript * import { defineMiddleware } from "astro:middleware"; * import { federation } from "./federation"; // Import the `Federation` object * * export const onRequest = defineMiddleware((context, next) => { * return federation.fetch(context.request, { * contextData: undefined, * ...createFetchOptions(context, next), * }); * }); * ``` * * @typeParam TAstroContext A type of the Astro context. * @param context An Astro context. * @param next A function to call the next middleware. * @returns Options for the {@link Federation.fetch} method. * @since 0.12.0 */ export function createFetchOptions<TAstroContext extends AstroContext>( _context: TAstroContext, next: MiddlewareNext, ): Omit<FederationFetchOptions<void>, "contextData"> { return { // If the `federation` object finds a request not responsible for it // (i.e., not a federation-related request), it will call the `next` // provided by the Astro framework to continue the request handling // by Astro: onNotFound: next, // Similar to `onNotFound`, but slightly more tricky one. // When the `federation` object finds a request not acceptable type-wise // (i.e., a user-agent doesn't want JSON-LD), it will call the `next` // provided by the Astro framework so that it renders HTML if there's some // page. Otherwise, it will simply return a 406 Not Acceptable response. // This kind of trick enables the Fedify and Astro to share the same routes // and they do content negotiation depending on `Accept` header: async onNotAcceptable(_request: Request) { const response = await next(); if (response.status !== 404) return response; return new Response("Not acceptable", { status: 406, headers: { "Content-Type": "text/plain", Vary: "Accept", }, }); }, }; } /** * The factory function to create a context data for * the {@link Federation.fetch}. * * @typeParam TContextData A type of the context data. * @typeParam TAstroContext A type of the Astro context. * @param context An Astro context. * @returns The context data for the {@link Federation.fetch}. * @since 0.12.0 */ export type ContextDataFactory< TContextData, TAstroContext extends AstroContext, > = ( context: TAstroContext, ) => TContextData | Promise<TContextData>; /** * Create an Astro middleware handler to integrate with the {@link Federation} * object. * * @example src/middleware.ts * ``` typescript * import type { MiddlewareHandler } from "astro"; * import { federation } from "./federation"; // Import the `Federation` object * * export const onRequest: MiddlewareHandler = createMiddleware( * federation, * (astroContext) => "context data", * ); * ``` * * @typeParam TContextData A type of the context data for the {@link Federation} * object. * @typeParam TAstroContext A type of the Astro context. * @param federation A {@link Federation} object to integrate with Astro. * @param contextDataFactory A factory function to create a context data for the * {@link Federation} object. * @returns An Astro middleware handler. * @since 0.12.0 */ export function createMiddleware< TContextData, TAstroContext extends AstroContext, >( federation: Federation<TContextData>, contextDataFactory: ContextDataFactory<TContextData, TAstroContext>, ): MiddlewareHandler<TAstroContext> { return async (context, next) => { const contextData = await contextDataFactory(context); return await federation.fetch(context.request, { contextData, ...createFetchOptions(context, next), }); }; }
x/fresh.ts +4 −3 Original line number Diff line number Diff line Loading @@ -20,7 +20,8 @@ interface FreshContext { } /** * Create options for the `federation` object to integrate with Fresh. * Create options for the {@link Federation.fetch} method to integrate with * Fresh. * * @example _middleware.ts * ``` typescript Loading Loading @@ -88,6 +89,7 @@ export function integrateFetchOptions( * @param createContextData A function to create a context data for the * {@link Federation} object. * @returns A Fresh middleware handler. * @since 0.4.0 */ export function integrateHandler< TContextData, Loading @@ -103,8 +105,7 @@ export function integrateHandler< request: Request, context: TFreshContext, ): Promise<Response> => { let contextData = createContextData(request, context); if (contextData instanceof Promise) contextData = await contextData; const contextData = await createContextData(request, context); return await federation.fetch(request, { contextData, ...integrateFetchOptions(context), Loading