Loading CHANGES.md +10 −1 Original line number Diff line number Diff line Loading @@ -61,6 +61,11 @@ To be released. - Added `CreateFederationOptions.tracerProvider` option. - Added `@fedify/fedify/x/sveltekit` module for integrating with [SvelteKit] hook. [[#171], [#183] by Jiyu Park] - Added `fedifyHook()` function. - The scaffold project generated by `fedify init` command now enables tracing data into log messages. Loading @@ -68,10 +73,14 @@ To be released. [[#173], [#186] by PGD] [SvelteKit]: https://kit.svelte.dev/ [#162]: https://github.com/dahlia/fedify/issues/162 [#171]: https://github.com/dahlia/fedify/issues/171 [#173]: https://github.com/dahlia/fedify/issues/173 [#183]: https://github.com/dahlia/fedify/pull/183 [#186]: https://github.com/dahlia/fedify/pull/186 Version 1.2.8 ------------- Loading Loading @@ -2556,4 +2565,4 @@ Version 0.1.0 Initial release. Released on March 8, 2024. <!-- cSpell: ignore Dogeon Fabien Wressell Emelia Hana Heesun Kyunghee --> <!-- cSpell: ignore Dogeon Fabien Wressell Emelia Hana Heesun Kyunghee Jiyu --> docs/manual/integration.md +26 −0 Original line number Diff line number Diff line Loading @@ -191,6 +191,32 @@ export const handler = integrateHandler( [Fresh]: https://fresh.deno.dev/ SvelteKit --------- *This API is available since Fedify 1.3.0.* [SvelteKit] is a framework for building web applications with [Svelte]. Fedify has the `@fedify/fedify/x/sveltekit` module that provides a hook handler to integrate Fedify with SvelteKit. Put the following code in your *hooks.server.ts* file: ~~~~ typescript import { createFederation } from "@fedify/fedify"; import { fedifyHook } from "@fedify/fedify/x/sveltekit"; const federation = createFederation<string>({ // Omitted for brevity; see the related section for details. }); // This is the entry point to the Fedify hook from the SvelteKit framework: export const handle = fedifyHook(federation, (req) => "context data"); ~~~~ [SvelteKit]: https://kit.svelte.dev/ [Svelte]: https://svelte.dev/ Custom middleware ----------------- Loading src/deno.json +3 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,8 @@ "./webfinger": "./webfinger/mod.ts", "./x/denokv": "./x/denokv.ts", "./x/fresh": "./x/fresh.ts", "./x/hono": "./x/hono.ts" "./x/hono": "./x/hono.ts", "./x/sveltekit": "./x/sveltekit.ts" }, "imports": { "@cfworker/json-schema": "npm:@cfworker/json-schema@^2.0.1", Loading @@ -28,6 +29,7 @@ "@fedify/fedify/x/denokv": "./x/denokv.ts", "@fedify/fedify/x/fresh": "./x/fresh.ts", "@fedify/fedify/x/hono": "./x/hono.ts", "@fedify/fedify/x/sveltekit": "./x/sveltekit.ts", "@hongminhee/aitertools": "jsr:@hongminhee/aitertools@^0.6.0", "@hugoalh/http-header-link": "jsr:@hugoalh/http-header-link@^1.0.2", "@logtape/logtape": "jsr:@logtape/logtape@^0.8.0", Loading src/x/sveltekit.ts 0 → 100644 +87 −0 Original line number Diff line number Diff line /** * Fedify with SvelteKit * ===================== * * This module provides a [SvelteKit] hook to integrate with the Fedify. * * [SvelteKit]: https://kit.svelte.dev/ * * @module * @since 1.3.0 */ import type { Federation, FederationFetchOptions, } from "../federation/federation.ts"; type RequestEvent = { request: Request; }; type HookParams = { event: RequestEvent; resolve: (event: RequestEvent) => Promise<Response>; }; /** * Create a SvelteKit hook handler to integrate with the {@link Federation} * object. * * @example hooks.server.ts * ``` typescript * import { federation } from "./federation"; // Import the `Federation` object * * export const handle = fedifyHook(federation, () => undefined); * ``` * * @typeParam TContextData A type of the context data for the {@link Federation} * object. * @param federation A {@link Federation} object to integrate with SvelteKit. * @param createContextData A function to create a context data for the * {@link Federation} object. * @returns A SvelteKit hook handler. * @since 1.3.0 */ export function fedifyHook<TContextData>( federation: Federation<TContextData>, createContextData: ( event: RequestEvent, ) => TContextData | Promise<TContextData>, ): (params: HookParams) => Promise<Response> { return async ({ event, resolve }: HookParams) => { return await federation.fetch(event.request, { contextData: await createContextData(event), ...integrateFetchOptions({ event, resolve }), }); }; } function integrateFetchOptions( { event, resolve }: HookParams, ): Omit<FederationFetchOptions<void>, "contextData"> { return { async onNotFound(): Promise<Response> { return await resolve(event); }, // 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 `resolve` // provided by the SvelteKit 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 SvelteKit to share the same routes // and they do content negotiation depending on `Accept` header: async onNotAcceptable(): Promise<Response> { const res = await resolve(event); if (res.status !== 404) return res; return new Response("Not acceptable", { status: 406, headers: { "Content-Type": "text/plain", Vary: "Accept", }, }); }, }; } Loading
CHANGES.md +10 −1 Original line number Diff line number Diff line Loading @@ -61,6 +61,11 @@ To be released. - Added `CreateFederationOptions.tracerProvider` option. - Added `@fedify/fedify/x/sveltekit` module for integrating with [SvelteKit] hook. [[#171], [#183] by Jiyu Park] - Added `fedifyHook()` function. - The scaffold project generated by `fedify init` command now enables tracing data into log messages. Loading @@ -68,10 +73,14 @@ To be released. [[#173], [#186] by PGD] [SvelteKit]: https://kit.svelte.dev/ [#162]: https://github.com/dahlia/fedify/issues/162 [#171]: https://github.com/dahlia/fedify/issues/171 [#173]: https://github.com/dahlia/fedify/issues/173 [#183]: https://github.com/dahlia/fedify/pull/183 [#186]: https://github.com/dahlia/fedify/pull/186 Version 1.2.8 ------------- Loading Loading @@ -2556,4 +2565,4 @@ Version 0.1.0 Initial release. Released on March 8, 2024. <!-- cSpell: ignore Dogeon Fabien Wressell Emelia Hana Heesun Kyunghee --> <!-- cSpell: ignore Dogeon Fabien Wressell Emelia Hana Heesun Kyunghee Jiyu -->
docs/manual/integration.md +26 −0 Original line number Diff line number Diff line Loading @@ -191,6 +191,32 @@ export const handler = integrateHandler( [Fresh]: https://fresh.deno.dev/ SvelteKit --------- *This API is available since Fedify 1.3.0.* [SvelteKit] is a framework for building web applications with [Svelte]. Fedify has the `@fedify/fedify/x/sveltekit` module that provides a hook handler to integrate Fedify with SvelteKit. Put the following code in your *hooks.server.ts* file: ~~~~ typescript import { createFederation } from "@fedify/fedify"; import { fedifyHook } from "@fedify/fedify/x/sveltekit"; const federation = createFederation<string>({ // Omitted for brevity; see the related section for details. }); // This is the entry point to the Fedify hook from the SvelteKit framework: export const handle = fedifyHook(federation, (req) => "context data"); ~~~~ [SvelteKit]: https://kit.svelte.dev/ [Svelte]: https://svelte.dev/ Custom middleware ----------------- Loading
src/deno.json +3 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,8 @@ "./webfinger": "./webfinger/mod.ts", "./x/denokv": "./x/denokv.ts", "./x/fresh": "./x/fresh.ts", "./x/hono": "./x/hono.ts" "./x/hono": "./x/hono.ts", "./x/sveltekit": "./x/sveltekit.ts" }, "imports": { "@cfworker/json-schema": "npm:@cfworker/json-schema@^2.0.1", Loading @@ -28,6 +29,7 @@ "@fedify/fedify/x/denokv": "./x/denokv.ts", "@fedify/fedify/x/fresh": "./x/fresh.ts", "@fedify/fedify/x/hono": "./x/hono.ts", "@fedify/fedify/x/sveltekit": "./x/sveltekit.ts", "@hongminhee/aitertools": "jsr:@hongminhee/aitertools@^0.6.0", "@hugoalh/http-header-link": "jsr:@hugoalh/http-header-link@^1.0.2", "@logtape/logtape": "jsr:@logtape/logtape@^0.8.0", Loading
src/x/sveltekit.ts 0 → 100644 +87 −0 Original line number Diff line number Diff line /** * Fedify with SvelteKit * ===================== * * This module provides a [SvelteKit] hook to integrate with the Fedify. * * [SvelteKit]: https://kit.svelte.dev/ * * @module * @since 1.3.0 */ import type { Federation, FederationFetchOptions, } from "../federation/federation.ts"; type RequestEvent = { request: Request; }; type HookParams = { event: RequestEvent; resolve: (event: RequestEvent) => Promise<Response>; }; /** * Create a SvelteKit hook handler to integrate with the {@link Federation} * object. * * @example hooks.server.ts * ``` typescript * import { federation } from "./federation"; // Import the `Federation` object * * export const handle = fedifyHook(federation, () => undefined); * ``` * * @typeParam TContextData A type of the context data for the {@link Federation} * object. * @param federation A {@link Federation} object to integrate with SvelteKit. * @param createContextData A function to create a context data for the * {@link Federation} object. * @returns A SvelteKit hook handler. * @since 1.3.0 */ export function fedifyHook<TContextData>( federation: Federation<TContextData>, createContextData: ( event: RequestEvent, ) => TContextData | Promise<TContextData>, ): (params: HookParams) => Promise<Response> { return async ({ event, resolve }: HookParams) => { return await federation.fetch(event.request, { contextData: await createContextData(event), ...integrateFetchOptions({ event, resolve }), }); }; } function integrateFetchOptions( { event, resolve }: HookParams, ): Omit<FederationFetchOptions<void>, "contextData"> { return { async onNotFound(): Promise<Response> { return await resolve(event); }, // 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 `resolve` // provided by the SvelteKit 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 SvelteKit to share the same routes // and they do content negotiation depending on `Accept` header: async onNotAcceptable(): Promise<Response> { const res = await resolve(event); if (res.status !== 404) return res; return new Response("Not acceptable", { status: 406, headers: { "Content-Type": "text/plain", Vary: "Accept", }, }); }, }; }