@sonordev/site-kit 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +376 -0
- package/dist/SetupWizard-Cki06kB0.d.mts +12 -0
- package/dist/SetupWizard-Cki06kB0.d.ts +12 -0
- package/dist/analytics/index.d.mts +93 -0
- package/dist/analytics/index.d.ts +93 -0
- package/dist/analytics/index.js +89 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/index.mjs +71 -0
- package/dist/analytics/index.mjs.map +1 -0
- package/dist/api-CWtoFJCO.d.mts +137 -0
- package/dist/api-CWtoFJCO.d.ts +137 -0
- package/dist/blog/index.d.mts +305 -0
- package/dist/blog/index.d.ts +305 -0
- package/dist/blog/index.js +1578 -0
- package/dist/blog/index.js.map +1 -0
- package/dist/blog/index.mjs +1562 -0
- package/dist/blog/index.mjs.map +1 -0
- package/dist/blog/server.d.mts +229 -0
- package/dist/blog/server.d.ts +229 -0
- package/dist/blog/server.js +692 -0
- package/dist/blog/server.js.map +1 -0
- package/dist/blog/server.mjs +666 -0
- package/dist/blog/server.mjs.map +1 -0
- package/dist/chunk-24277A3Q.mjs +968 -0
- package/dist/chunk-24277A3Q.mjs.map +1 -0
- package/dist/chunk-373TK6TZ.js +321 -0
- package/dist/chunk-373TK6TZ.js.map +1 -0
- package/dist/chunk-3MYZS6PD.js +30 -0
- package/dist/chunk-3MYZS6PD.js.map +1 -0
- package/dist/chunk-43GBM4SX.js +283 -0
- package/dist/chunk-43GBM4SX.js.map +1 -0
- package/dist/chunk-4XPGGLVP.mjs +53 -0
- package/dist/chunk-4XPGGLVP.mjs.map +1 -0
- package/dist/chunk-622GAQP5.js +2008 -0
- package/dist/chunk-622GAQP5.js.map +1 -0
- package/dist/chunk-6BIPAKL4.mjs +28 -0
- package/dist/chunk-6BIPAKL4.mjs.map +1 -0
- package/dist/chunk-6ZCISNAB.mjs +343 -0
- package/dist/chunk-6ZCISNAB.mjs.map +1 -0
- package/dist/chunk-72MQFHYJ.js +1429 -0
- package/dist/chunk-72MQFHYJ.js.map +1 -0
- package/dist/chunk-7557OTHW.js +62 -0
- package/dist/chunk-7557OTHW.js.map +1 -0
- package/dist/chunk-7FUV73JZ.js +981 -0
- package/dist/chunk-7FUV73JZ.js.map +1 -0
- package/dist/chunk-7RF6PVHA.mjs +324 -0
- package/dist/chunk-7RF6PVHA.mjs.map +1 -0
- package/dist/chunk-7RYCHO6D.mjs +134 -0
- package/dist/chunk-7RYCHO6D.mjs.map +1 -0
- package/dist/chunk-7UKPRW25.mjs +1999 -0
- package/dist/chunk-7UKPRW25.mjs.map +1 -0
- package/dist/chunk-7URAOG2M.js +14864 -0
- package/dist/chunk-7URAOG2M.js.map +1 -0
- package/dist/chunk-AFAO3TGS.mjs +810 -0
- package/dist/chunk-AFAO3TGS.mjs.map +1 -0
- package/dist/chunk-BYLIU6XG.js +343 -0
- package/dist/chunk-BYLIU6XG.js.map +1 -0
- package/dist/chunk-D63MUKZ6.mjs +4423 -0
- package/dist/chunk-D63MUKZ6.mjs.map +1 -0
- package/dist/chunk-DDKW2FNA.js +390 -0
- package/dist/chunk-DDKW2FNA.js.map +1 -0
- package/dist/chunk-DQYMKR27.mjs +341 -0
- package/dist/chunk-DQYMKR27.mjs.map +1 -0
- package/dist/chunk-DW5UJKHH.js +221 -0
- package/dist/chunk-DW5UJKHH.js.map +1 -0
- package/dist/chunk-EEZCR6E6.js +50 -0
- package/dist/chunk-EEZCR6E6.js.map +1 -0
- package/dist/chunk-GCJXQ4AG.mjs +59 -0
- package/dist/chunk-GCJXQ4AG.mjs.map +1 -0
- package/dist/chunk-JGNQK2G6.mjs +14845 -0
- package/dist/chunk-JGNQK2G6.mjs.map +1 -0
- package/dist/chunk-JTLOJLWQ.mjs +563 -0
- package/dist/chunk-JTLOJLWQ.mjs.map +1 -0
- package/dist/chunk-K23A4G76.mjs +202 -0
- package/dist/chunk-K23A4G76.mjs.map +1 -0
- package/dist/chunk-KKU3K7RG.js +336 -0
- package/dist/chunk-KKU3K7RG.js.map +1 -0
- package/dist/chunk-KUGMH4ZF.js +571 -0
- package/dist/chunk-KUGMH4ZF.js.map +1 -0
- package/dist/chunk-LBVWVP72.js +110 -0
- package/dist/chunk-LBVWVP72.js.map +1 -0
- package/dist/chunk-LIVWLY2P.js +138 -0
- package/dist/chunk-LIVWLY2P.js.map +1 -0
- package/dist/chunk-M2T6R7BA.mjs +1003 -0
- package/dist/chunk-M2T6R7BA.mjs.map +1 -0
- package/dist/chunk-MV3QN7PW.mjs +47 -0
- package/dist/chunk-MV3QN7PW.mjs.map +1 -0
- package/dist/chunk-OB7E654K.js +72 -0
- package/dist/chunk-OB7E654K.js.map +1 -0
- package/dist/chunk-OIIKTGRL.mjs +380 -0
- package/dist/chunk-OIIKTGRL.mjs.map +1 -0
- package/dist/chunk-P3UWIUJS.mjs +1427 -0
- package/dist/chunk-P3UWIUJS.mjs.map +1 -0
- package/dist/chunk-PKN27UMH.mjs +136 -0
- package/dist/chunk-PKN27UMH.mjs.map +1 -0
- package/dist/chunk-QXV4667R.mjs +105 -0
- package/dist/chunk-QXV4667R.mjs.map +1 -0
- package/dist/chunk-S7FRYNSU.mjs +315 -0
- package/dist/chunk-S7FRYNSU.mjs.map +1 -0
- package/dist/chunk-TFLQX7K7.mjs +68 -0
- package/dist/chunk-TFLQX7K7.mjs.map +1 -0
- package/dist/chunk-UWE5PCYJ.mjs +279 -0
- package/dist/chunk-UWE5PCYJ.mjs.map +1 -0
- package/dist/chunk-UYFDNX2F.js +4469 -0
- package/dist/chunk-UYFDNX2F.js.map +1 -0
- package/dist/chunk-W4PALSGM.js +350 -0
- package/dist/chunk-W4PALSGM.js.map +1 -0
- package/dist/chunk-WECQ6KOB.js +1008 -0
- package/dist/chunk-WECQ6KOB.js.map +1 -0
- package/dist/chunk-XQQWI6WB.js +814 -0
- package/dist/chunk-XQQWI6WB.js.map +1 -0
- package/dist/chunk-XZJOZJB6.js +140 -0
- package/dist/chunk-XZJOZJB6.js.map +1 -0
- package/dist/chunk-ZSMWDLMK.js +63 -0
- package/dist/chunk-ZSMWDLMK.js.map +1 -0
- package/dist/cli/index.js +37243 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/index.mjs +37209 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/commerce/index.d.mts +170 -0
- package/dist/commerce/index.d.ts +170 -0
- package/dist/commerce/index.js +174 -0
- package/dist/commerce/index.js.map +1 -0
- package/dist/commerce/index.mjs +5 -0
- package/dist/commerce/index.mjs.map +1 -0
- package/dist/commerce/server.d.mts +107 -0
- package/dist/commerce/server.d.ts +107 -0
- package/dist/commerce/server.js +187 -0
- package/dist/commerce/server.js.map +1 -0
- package/dist/commerce/server.mjs +177 -0
- package/dist/commerce/server.mjs.map +1 -0
- package/dist/config/index.d.mts +43 -0
- package/dist/config/index.d.ts +43 -0
- package/dist/config/index.js +66 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.mjs +64 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/engage/index.d.mts +33 -0
- package/dist/engage/index.d.ts +33 -0
- package/dist/engage/index.js +22 -0
- package/dist/engage/index.js.map +1 -0
- package/dist/engage/index.mjs +5 -0
- package/dist/engage/index.mjs.map +1 -0
- package/dist/forms/index.d.mts +437 -0
- package/dist/forms/index.d.ts +437 -0
- package/dist/forms/index.js +1168 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/index.mjs +1142 -0
- package/dist/forms/index.mjs.map +1 -0
- package/dist/generators-2XKQMPKH.mjs +4 -0
- package/dist/generators-2XKQMPKH.mjs.map +1 -0
- package/dist/generators-DTMO36DV.js +33 -0
- package/dist/generators-DTMO36DV.js.map +1 -0
- package/dist/images/index.d.mts +4 -0
- package/dist/images/index.d.ts +4 -0
- package/dist/images/index.js +46 -0
- package/dist/images/index.js.map +1 -0
- package/dist/images/index.mjs +5 -0
- package/dist/images/index.mjs.map +1 -0
- package/dist/images/server.d.mts +69 -0
- package/dist/images/server.d.ts +69 -0
- package/dist/images/server.js +21 -0
- package/dist/images/server.js.map +1 -0
- package/dist/images/server.mjs +4 -0
- package/dist/images/server.mjs.map +1 -0
- package/dist/index.d.mts +846 -0
- package/dist/index.d.ts +846 -0
- package/dist/index.js +2623 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2416 -0
- package/dist/index.mjs.map +1 -0
- package/dist/layout/index.d.mts +53 -0
- package/dist/layout/index.d.ts +53 -0
- package/dist/layout/index.js +187 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/layout/index.mjs +185 -0
- package/dist/layout/index.mjs.map +1 -0
- package/dist/llms/index.d.mts +448 -0
- package/dist/llms/index.d.ts +448 -0
- package/dist/llms/index.js +581 -0
- package/dist/llms/index.js.map +1 -0
- package/dist/llms/index.mjs +529 -0
- package/dist/llms/index.mjs.map +1 -0
- package/dist/manifest/index.d.mts +62 -0
- package/dist/manifest/index.d.ts +62 -0
- package/dist/manifest/index.js +85 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/index.mjs +83 -0
- package/dist/manifest/index.mjs.map +1 -0
- package/dist/middleware/index.d.mts +63 -0
- package/dist/middleware/index.d.ts +63 -0
- package/dist/middleware/index.js +54 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/index.mjs +51 -0
- package/dist/middleware/index.mjs.map +1 -0
- package/dist/migrator-2MQHOFDQ.mjs +4 -0
- package/dist/migrator-2MQHOFDQ.mjs.map +1 -0
- package/dist/migrator-THJCF6MZ.js +37 -0
- package/dist/migrator-THJCF6MZ.js.map +1 -0
- package/dist/redirects/index.d.mts +78 -0
- package/dist/redirects/index.d.ts +78 -0
- package/dist/redirects/index.js +26 -0
- package/dist/redirects/index.js.map +1 -0
- package/dist/redirects/index.mjs +5 -0
- package/dist/redirects/index.mjs.map +1 -0
- package/dist/reputation/index.d.mts +57 -0
- package/dist/reputation/index.d.ts +57 -0
- package/dist/reputation/index.js +21 -0
- package/dist/reputation/index.js.map +1 -0
- package/dist/reputation/index.mjs +4 -0
- package/dist/reputation/index.mjs.map +1 -0
- package/dist/robots/index.d.mts +38 -0
- package/dist/robots/index.d.ts +38 -0
- package/dist/robots/index.js +52 -0
- package/dist/robots/index.js.map +1 -0
- package/dist/robots/index.mjs +50 -0
- package/dist/robots/index.mjs.map +1 -0
- package/dist/routing-B5XS-6_W.d.mts +118 -0
- package/dist/routing-DZYzyDHw.d.ts +118 -0
- package/dist/scanner-GAF5PO5F.js +53 -0
- package/dist/scanner-GAF5PO5F.js.map +1 -0
- package/dist/scanner-LKJKW7IT.mjs +4 -0
- package/dist/scanner-LKJKW7IT.mjs.map +1 -0
- package/dist/securityHeaders-nwZ6nP4g.d.mts +24 -0
- package/dist/securityHeaders-nwZ6nP4g.d.ts +24 -0
- package/dist/seo/index.d.mts +600 -0
- package/dist/seo/index.d.ts +600 -0
- package/dist/seo/index.js +883 -0
- package/dist/seo/index.js.map +1 -0
- package/dist/seo/index.mjs +773 -0
- package/dist/seo/index.mjs.map +1 -0
- package/dist/seo/register-sitemap-cli.js +151 -0
- package/dist/seo/register-sitemap-cli.js.map +1 -0
- package/dist/seo/register-sitemap-cli.mjs +144 -0
- package/dist/seo/register-sitemap-cli.mjs.map +1 -0
- package/dist/seo/server.d.mts +107 -0
- package/dist/seo/server.d.ts +107 -0
- package/dist/seo/server.js +207 -0
- package/dist/seo/server.js.map +1 -0
- package/dist/seo/server.mjs +186 -0
- package/dist/seo/server.mjs.map +1 -0
- package/dist/server-api-EWXKOQZA.mjs +4 -0
- package/dist/server-api-EWXKOQZA.mjs.map +1 -0
- package/dist/server-api-GJPNRYUP.js +81 -0
- package/dist/server-api-GJPNRYUP.js.map +1 -0
- package/dist/setup/client.d.mts +60 -0
- package/dist/setup/client.d.ts +60 -0
- package/dist/setup/client.js +31 -0
- package/dist/setup/client.js.map +1 -0
- package/dist/setup/client.mjs +6 -0
- package/dist/setup/client.mjs.map +1 -0
- package/dist/setup/index.d.mts +5 -0
- package/dist/setup/index.d.ts +5 -0
- package/dist/setup/index.js +35 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/setup/index.mjs +6 -0
- package/dist/setup/index.mjs.map +1 -0
- package/dist/setup/server.d.mts +14 -0
- package/dist/setup/server.d.ts +14 -0
- package/dist/setup/server.js +13 -0
- package/dist/setup/server.js.map +1 -0
- package/dist/setup/server.mjs +4 -0
- package/dist/setup/server.mjs.map +1 -0
- package/dist/site-config/index.d.mts +24 -0
- package/dist/site-config/index.d.ts +24 -0
- package/dist/site-config/index.js +17 -0
- package/dist/site-config/index.js.map +1 -0
- package/dist/site-config/index.mjs +4 -0
- package/dist/site-config/index.mjs.map +1 -0
- package/dist/sitemap/index.d.mts +96 -0
- package/dist/sitemap/index.d.ts +96 -0
- package/dist/sitemap/index.js +288 -0
- package/dist/sitemap/index.js.map +1 -0
- package/dist/sitemap/index.mjs +285 -0
- package/dist/sitemap/index.mjs.map +1 -0
- package/dist/socket-loader-J26QHHOB.js +16 -0
- package/dist/socket-loader-J26QHHOB.js.map +1 -0
- package/dist/socket-loader-R7S2YJ2J.mjs +14 -0
- package/dist/socket-loader-R7S2YJ2J.mjs.map +1 -0
- package/dist/types-0dmq3k20.d.mts +168 -0
- package/dist/types-0dmq3k20.d.ts +168 -0
- package/dist/types-Blb2QNkV.d.mts +263 -0
- package/dist/types-Blb2QNkV.d.ts +263 -0
- package/dist/types-BnCwwUX3.d.mts +250 -0
- package/dist/types-BnCwwUX3.d.ts +250 -0
- package/dist/types-CGlnp43R.d.mts +312 -0
- package/dist/types-CGlnp43R.d.ts +312 -0
- package/dist/types-D08004rU.d.mts +179 -0
- package/dist/types-D08004rU.d.ts +179 -0
- package/dist/types-DNSYU7qI.d.mts +127 -0
- package/dist/types-DNSYU7qI.d.ts +127 -0
- package/dist/types-KZP_VWZp.d.mts +266 -0
- package/dist/types-KZP_VWZp.d.ts +266 -0
- package/dist/useEventModal-BVTx69XE.d.mts +274 -0
- package/dist/useEventModal-Dx1dItTJ.d.ts +274 -0
- package/dist/web-vitals-444RLW3B.js +252 -0
- package/dist/web-vitals-444RLW3B.js.map +1 -0
- package/dist/web-vitals-KPICZIEF.mjs +241 -0
- package/dist/web-vitals-KPICZIEF.mjs.map +1 -0
- package/package.json +192 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/llms/handlers.ts","../../src/llms/SpeakableSchema.tsx","../../src/llms/AEOComponents.tsx"],"names":["markdown","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @sonordev/site-kit/llms - Next.js Route Handlers\n * \n * Ready-to-use route handlers for /llms.txt and /llms-full.txt\n */\n\nimport { existsSync, readFileSync } from 'fs'\nimport { join } from 'path'\nimport { generateLLMsTxt, generateLLMsFullTxt } from './generateLLMsTxt'\nimport type { GenerateLLMSTxtOptions } from './types'\n\nexport interface LLMsTxtHandlerOptions extends GenerateLLMSTxtOptions {\n /** When true, serve static public/llms.txt if it exists (default: true for build-time flow) */\n preferStatic?: boolean\n}\n\n/**\n * Create a route handler for /llms.txt\n * \n * Zero-config by default - uses NEXT_PUBLIC_UPTRADE_API_KEY from environment.\n * \n * @example\n * ```ts\n * // app/llms.txt/route.ts (zero-config)\n * import { createLLMsTxtHandler } from '@sonordev/site-kit/llms'\n * \n * export const GET = createLLMsTxtHandler()\n * ```\n * \n * @example\n * ```ts\n * // With preferStatic: serve build-time file if exists\n * export const GET = createLLMsTxtHandler({\n * preferStatic: true,\n * includeServices: false\n * })\n * ```\n */\nexport function createLLMsTxtHandler(\n options: LLMsTxtHandlerOptions = {}\n): () => Promise<Response> {\n const { preferStatic = true, ...generateOptions } = options\n\n return async function GET(): Promise<Response> {\n try {\n // Serve static file if available (build-time optimized)\n if (preferStatic) {\n const staticPath = join(process.cwd(), 'public', 'llms.txt')\n if (existsSync(staticPath)) {\n const markdown = readFileSync(staticPath, 'utf-8')\n return new Response(markdown, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': 'public, max-age=3600, s-maxage=3600',\n },\n })\n }\n }\n\n const { markdown, metadata } = await generateLLMsTxt(generateOptions)\n \n return new Response(markdown, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': 'public, max-age=3600, s-maxage=3600',\n 'X-Generated-At': metadata.generated_at,\n 'X-Sections': metadata.sections.join(','),\n },\n })\n } catch (error) {\n console.error('@sonordev/llms: Error generating llms.txt:', error)\n return new Response('# Error\\n\\nUnable to generate llms.txt content.', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n })\n }\n }\n}\n\n/**\n * Create a route handler for /llms-full.txt\n * \n * Zero-config by default - uses NEXT_PUBLIC_UPTRADE_API_KEY from environment.\n * \n * @example\n * ```ts\n * // app/llms-full.txt/route.ts (zero-config)\n * import { createLLMsFullTxtHandler } from '@sonordev/site-kit/llms'\n * \n * export const GET = createLLMsFullTxtHandler()\n * ```\n */\nexport function createLLMsFullTxtHandler(\n options: LLMsTxtHandlerOptions = {}\n): () => Promise<Response> {\n const { preferStatic = true, ...generateOptions } = options\n\n return async function GET(): Promise<Response> {\n try {\n // Serve static file if available (build-time optimized)\n if (preferStatic) {\n const staticPath = join(process.cwd(), 'public', 'llms-full.txt')\n if (existsSync(staticPath)) {\n const markdown = readFileSync(staticPath, 'utf-8')\n return new Response(markdown, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': 'public, max-age=3600, s-maxage=3600',\n },\n })\n }\n }\n\n const { markdown, metadata } = await generateLLMsFullTxt(generateOptions)\n \n return new Response(markdown, {\n status: 200,\n headers: {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Cache-Control': 'public, max-age=3600, s-maxage=3600',\n 'X-Generated-At': metadata.generated_at,\n 'X-Sections': metadata.sections.join(','),\n },\n })\n } catch (error) {\n console.error('@sonordev/llms: Error generating llms-full.txt:', error)\n return new Response('# Error\\n\\nUnable to generate llms-full.txt content.', {\n status: 500,\n headers: { 'Content-Type': 'text/plain; charset=utf-8' },\n })\n }\n }\n}\n","/**\n * @sonordev/site-kit/llms - Speakable Schema Generator\n * \n * Generates JSON-LD with SpeakableSpecification for voice assistant\n * and AI system content extraction.\n * \n * @see https://schema.org/speakable\n * @see https://developers.google.com/search/docs/appearance/structured-data/speakable\n */\n\nimport * as React from 'react'\nimport type { SpeakableSchemaProps, SpeakableConfig } from './types'\n\n/**\n * Generate a WebPage or Article schema with speakable specification\n * \n * @example\n * ```tsx\n * // In a page component\n * <SpeakableSchema\n * type=\"Article\"\n * name=\"Family Law Services in Cincinnati\"\n * url=\"https://heinrichlaw.com/family-law\"\n * speakable={{\n * cssSelectors: ['.page-summary', '.key-points', 'h1']\n * }}\n * />\n * ```\n */\nexport function SpeakableSchema({\n type,\n name,\n url,\n speakable,\n additionalProperties = {},\n}: SpeakableSchemaProps): React.ReactElement {\n const schema = createSpeakableSchema(type, name, url, speakable, additionalProperties)\n \n return (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{\n __html: JSON.stringify(schema, null, 0),\n }}\n />\n )\n}\n\n/**\n * Create speakable schema object (for manual use or testing)\n */\nexport function createSpeakableSchema(\n type: 'Article' | 'WebPage',\n name: string,\n url: string,\n speakable: SpeakableConfig,\n additionalProperties: Record<string, unknown> = {}\n): Record<string, unknown> {\n const speakableSpec: Record<string, unknown> = {\n '@type': 'SpeakableSpecification',\n }\n\n // Prefer CSS selectors, fall back to XPath\n if (speakable.cssSelectors?.length) {\n speakableSpec.cssSelector = speakable.cssSelectors\n } else if (speakable.xPaths?.length) {\n speakableSpec.xpath = speakable.xPaths\n } else {\n // Default speakable selectors for common patterns\n speakableSpec.cssSelector = [\n 'h1',\n '[data-speakable]',\n '.page-summary',\n '.key-points',\n 'meta[name=\"description\"]'\n ]\n }\n\n return {\n '@context': 'https://schema.org',\n '@type': type,\n name,\n url,\n speakable: speakableSpec,\n ...additionalProperties,\n }\n}\n\n/**\n * Default speakable CSS selectors for common page elements\n */\nexport const DEFAULT_SPEAKABLE_SELECTORS = {\n /** Standard page elements */\n page: ['h1', 'meta[name=\"description\"]', '.page-summary'],\n /** Article/blog post elements */\n article: ['h1', '.article-summary', '.article-intro', 'meta[name=\"description\"]'],\n /** Service page elements */\n service: ['h1', '.service-overview', '.key-benefits', 'meta[name=\"description\"]'],\n /** FAQ page elements */\n faq: ['h1', '.faq-intro', '.faq-item'],\n /** Contact page elements */\n contact: ['h1', '.contact-intro', '.business-hours', '.contact-info'],\n}\n\n/**\n * Get recommended speakable selectors for a page type\n */\nexport function getSpeakableSelectorsForPage(\n pageType: 'page' | 'article' | 'service' | 'faq' | 'contact'\n): string[] {\n return DEFAULT_SPEAKABLE_SELECTORS[pageType] || DEFAULT_SPEAKABLE_SELECTORS.page\n}\n\nexport default SpeakableSchema\n","/**\n * @sonordev/site-kit/llms - AEO Components\n * \n * Answer Engine Optimization (AEO) components for structuring content\n * in a way that AI systems can easily extract and cite.\n * \n * These components create semantic HTML with proper structure for:\n * - Featured snippets\n * - AI-generated answers\n * - Voice assistant responses\n * - AI retrieval and citation (Sonor AI Visibility)\n */\n\nimport * as React from 'react'\nimport type { AEOBlockProps, AEOSummaryProps, AEODefinitionProps, AEOClaimProps } from './types'\n\n/**\n * AEOBlock - Generic content block optimized for AI extraction\n * \n * Wraps content with semantic HTML and Sonor data attributes.\n * Use for any content you want AI systems to prioritize.\n * \n * @example\n * ```tsx\n * <AEOBlock type=\"answer\" question=\"What is family law?\" speakable>\n * Family law is the area of legal practice that deals with family-related \n * matters such as divorce, child custody, adoption, and domestic relations.\n * </AEOBlock>\n * ```\n */\nexport function AEOBlock({\n id,\n type,\n question,\n speakable = true,\n entityId,\n children,\n className = '',\n}: AEOBlockProps): React.ReactElement {\n const blockId = id || `aeo-${type}-${Math.random().toString(36).slice(2, 8)}`\n \n const baseClasses = `aeo-block aeo-${type}`\n const combinedClasses = className ? `${baseClasses} ${className}` : baseClasses\n\n // Common data attributes for Sonor AI\n const sonorAttrs = {\n 'data-sonor-ai': type,\n 'data-sonor-block': 'true',\n ...(entityId && { 'data-sonor-entity': entityId }),\n }\n\n // Q&A format for answer type\n if (type === 'answer' && question) {\n return (\n <section \n id={blockId}\n className={combinedClasses}\n data-speakable={speakable ? 'true' : undefined}\n data-aeo-type={type}\n {...sonorAttrs}\n itemScope\n itemType=\"https://schema.org/Question\"\n >\n <h3 itemProp=\"name\" className=\"aeo-question\">\n {question}\n </h3>\n <div \n itemScope \n itemType=\"https://schema.org/Answer\" \n itemProp=\"acceptedAnswer\"\n className=\"aeo-answer\"\n >\n <div itemProp=\"text\">\n {children}\n </div>\n </div>\n </section>\n )\n }\n\n // Definition format\n if (type === 'definition') {\n return (\n <section \n id={blockId}\n className={combinedClasses}\n data-speakable={speakable ? 'true' : undefined}\n data-aeo-type={type}\n {...sonorAttrs}\n >\n {children}\n </section>\n )\n }\n\n // Steps format (numbered list)\n if (type === 'steps') {\n return (\n <section \n id={blockId}\n className={combinedClasses}\n data-speakable={speakable ? 'true' : undefined}\n data-aeo-type={type}\n {...sonorAttrs}\n itemScope\n itemType=\"https://schema.org/HowTo\"\n >\n {children}\n </section>\n )\n }\n\n // Default wrapper\n return (\n <section \n id={blockId}\n className={combinedClasses}\n data-speakable={speakable ? 'true' : undefined}\n data-aeo-type={type}\n {...sonorAttrs}\n >\n {children}\n </section>\n )\n}\n\n/**\n * AEOSummary - Key points summary for AI extraction\n * \n * Creates a scannable list of key points that AI can easily cite.\n * Perfect for \"at a glance\" or \"key takeaways\" sections.\n * \n * @example\n * ```tsx\n * <AEOSummary \n * title=\"Key Points\" \n * points={[\n * \"Family law covers divorce, custody, and adoption\",\n * \"Ohio is an equitable distribution state\",\n * \"Child custody decisions prioritize the child's best interests\"\n * ]} \n * />\n * ```\n */\nexport function AEOSummary({\n title = 'Key Points',\n points,\n speakable = true,\n entityId,\n className = '',\n}: AEOSummaryProps): React.ReactElement {\n const baseClasses = 'aeo-summary'\n const combinedClasses = className ? `${baseClasses} ${className}` : baseClasses\n\n return (\n <div \n className={combinedClasses}\n data-speakable={speakable ? 'true' : undefined}\n data-aeo-type=\"summary\"\n data-sonor-ai=\"summary\"\n data-sonor-block=\"true\"\n {...(entityId && { 'data-sonor-entity': entityId })}\n >\n {title && <h3 className=\"aeo-summary-title\">{title}</h3>}\n <ul className=\"aeo-summary-points\">\n {points.map((point, index) => (\n <li key={index} className=\"aeo-summary-point\">\n {point}\n </li>\n ))}\n </ul>\n </div>\n )\n}\n\n/**\n * AEODefinition - Term definition optimized for featured snippets\n * \n * Creates a clear definition format that works well for\n * \"What is X?\" queries in AI search results.\n * \n * @example\n * ```tsx\n * <AEODefinition \n * term=\"Equitable Distribution\" \n * definition=\"A legal principle used in Ohio divorce cases where marital \n * property is divided fairly, though not necessarily equally, between spouses.\"\n * />\n * ```\n */\nexport function AEODefinition({\n term,\n definition,\n speakable = true,\n entityId,\n source,\n className = '',\n}: AEODefinitionProps): React.ReactElement {\n const baseClasses = 'aeo-definition'\n const combinedClasses = className ? `${baseClasses} ${className}` : baseClasses\n\n return (\n <dl \n className={combinedClasses}\n data-speakable={speakable ? 'true' : undefined}\n data-aeo-type=\"definition\"\n data-sonor-ai=\"definition\"\n data-sonor-block=\"true\"\n {...(entityId && { 'data-sonor-entity': entityId })}\n {...(source && { 'data-sonor-source': source })}\n itemScope\n itemType=\"https://schema.org/DefinedTerm\"\n >\n <dt className=\"aeo-term\" itemProp=\"name\">\n <strong>{term}</strong>\n </dt>\n <dd className=\"aeo-definition-text\" itemProp=\"description\">\n {definition}\n </dd>\n </dl>\n )\n}\n\n/**\n * AEOSteps - How-to steps for featured snippets\n * \n * Creates numbered steps with HowTo schema markup.\n * \n * @example\n * ```tsx\n * <AEOSteps title=\"How to File for Divorce in Ohio\">\n * <AEOStep number={1} name=\"Gather Documents\">\n * Collect financial records, property deeds, and marriage certificate.\n * </AEOStep>\n * <AEOStep number={2} name=\"File Petition\">\n * Submit divorce petition to the county court.\n * </AEOStep>\n * </AEOSteps>\n * ```\n */\nexport function AEOSteps({\n title,\n children,\n speakable = true,\n entityId,\n className = '',\n}: {\n title: string\n children: React.ReactNode\n speakable?: boolean\n entityId?: string\n className?: string\n}): React.ReactElement {\n const baseClasses = 'aeo-steps'\n const combinedClasses = className ? `${baseClasses} ${className}` : baseClasses\n\n return (\n <section \n className={combinedClasses}\n data-speakable={speakable ? 'true' : undefined}\n data-aeo-type=\"steps\"\n data-sonor-ai=\"steps\"\n data-sonor-block=\"true\"\n {...(entityId && { 'data-sonor-entity': entityId })}\n itemScope\n itemType=\"https://schema.org/HowTo\"\n >\n <h3 className=\"aeo-steps-title\" itemProp=\"name\">{title}</h3>\n <ol className=\"aeo-steps-list\">\n {children}\n </ol>\n </section>\n )\n}\n\n/**\n * AEOStep - Individual step within AEOSteps\n */\nexport function AEOStep({\n number,\n name,\n children,\n}: {\n number: number\n name: string\n children: React.ReactNode\n}): React.ReactElement {\n return (\n <li \n className=\"aeo-step\"\n itemScope\n itemType=\"https://schema.org/HowToStep\"\n itemProp=\"step\"\n >\n <span className=\"aeo-step-number\" itemProp=\"position\">{number}</span>\n <strong className=\"aeo-step-name\" itemProp=\"name\">{name}</strong>\n <div className=\"aeo-step-content\" itemProp=\"text\">\n {children}\n </div>\n </li>\n )\n}\n\n/**\n * AEOComparison - Comparison table for AI extraction\n * \n * Creates a structured comparison that AI can understand and cite.\n * \n * @example\n * ```tsx\n * <AEOComparison \n * title=\"Divorce vs. Dissolution in Ohio\"\n * items={[\n * { aspect: 'Agreement', optionA: 'May be contested', optionB: 'Must be agreed upon' },\n * { aspect: 'Timeline', optionA: '6-12 months', optionB: '30-90 days' },\n * ]}\n * labelA=\"Divorce\"\n * labelB=\"Dissolution\"\n * />\n * ```\n */\nexport function AEOComparison({\n title,\n items,\n labelA,\n labelB,\n speakable = true,\n entityId,\n className = '',\n}: {\n title: string\n items: Array<{ aspect: string; optionA: string; optionB: string }>\n labelA: string\n labelB: string\n speakable?: boolean\n entityId?: string\n className?: string\n}): React.ReactElement {\n const baseClasses = 'aeo-comparison'\n const combinedClasses = className ? `${baseClasses} ${className}` : baseClasses\n\n return (\n <section \n className={combinedClasses}\n data-speakable={speakable ? 'true' : undefined}\n data-aeo-type=\"comparison\"\n data-sonor-ai=\"comparison\"\n data-sonor-block=\"true\"\n {...(entityId && { 'data-sonor-entity': entityId })}\n >\n <h3 className=\"aeo-comparison-title\">{title}</h3>\n <table className=\"aeo-comparison-table\">\n <thead>\n <tr>\n <th>Aspect</th>\n <th>{labelA}</th>\n <th>{labelB}</th>\n </tr>\n </thead>\n <tbody>\n {items.map((item, index) => (\n <tr key={index}>\n <td className=\"aeo-comparison-aspect\">{item.aspect}</td>\n <td className=\"aeo-comparison-a\">{item.optionA}</td>\n <td className=\"aeo-comparison-b\">{item.optionB}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n )\n}\n\n/**\n * AEOClaim - AI-Verifiable Claim with Provenance\n * \n * Wraps factual claims with machine-readable source and confidence data.\n * LLMs prioritize verifiable facts with clear provenance.\n * \n * @example\n * ```tsx\n * <AEOClaim \n * source=\"KRS 281A.170\" \n * sourceUrl=\"https://apps.legislature.ky.gov/law/statutes/statute.aspx?id=6398\"\n * confidence={0.95}\n * claimType=\"statute\"\n * >\n * A CDL suspension is triggered at 26 MPH over the limit.\n * </AEOClaim>\n * ```\n */\nexport function AEOClaim({\n source,\n sourceUrl,\n confidence = 1.0,\n claimType = 'fact',\n retrievedAt,\n children,\n className = '',\n}: AEOClaimProps): React.ReactElement {\n const baseClasses = 'aeo-claim'\n const combinedClasses = className ? `${baseClasses} ${className}` : baseClasses\n\n return (\n <span \n className={combinedClasses}\n data-sonor-claim=\"true\"\n data-sonor-source={source}\n {...(sourceUrl && { 'data-sonor-source-url': sourceUrl })}\n data-sonor-confidence={confidence.toString()}\n data-sonor-claim-type={claimType}\n {...(retrievedAt && { 'data-sonor-retrieved': retrievedAt })}\n itemScope\n itemType=\"https://schema.org/Claim\"\n >\n <span itemProp=\"text\">{children}</span>\n {sourceUrl ? (\n <meta itemProp=\"citation\" content={sourceUrl} />\n ) : (\n <meta itemProp=\"citation\" content={source} />\n )}\n </span>\n )\n}\n\n/**\n * AEOEntity - Inline entity annotation\n * \n * Wraps entity mentions with machine-readable entity IDs for knowledge graph linking.\n * \n * @example\n * ```tsx\n * <AEOEntity entityId=\"person-123\" entityType=\"person\" name=\"Shannon Sexton\">\n * Attorney Shannon Sexton\n * </AEOEntity> handles CDL defense cases.\n * ```\n */\nexport function AEOEntity({\n entityId,\n entityType,\n name,\n url,\n children,\n className = '',\n}: {\n entityId: string\n entityType: 'organization' | 'person' | 'service' | 'product' | 'location' | 'concept' | 'credential'\n name: string\n url?: string\n children: React.ReactNode\n className?: string\n}): React.ReactElement {\n const baseClasses = 'aeo-entity'\n const combinedClasses = className ? `${baseClasses} aeo-entity-${entityType} ${className}` : `${baseClasses} aeo-entity-${entityType}`\n\n return (\n <span \n className={combinedClasses}\n data-sonor-entity={entityId}\n data-sonor-entity-type={entityType}\n data-sonor-entity-name={name}\n {...(url && { 'data-sonor-entity-url': url })}\n itemScope\n itemType={`https://schema.org/${entityType === 'organization' ? 'Organization' : entityType === 'person' ? 'Person' : entityType === 'location' ? 'Place' : 'Thing'}`}\n >\n <span itemProp=\"name\">{children}</span>\n {url && <link itemProp=\"url\" href={url} />}\n </span>\n )\n}\n\n// ============================================\n// Content Provenance Components\n// ============================================\n\n/**\n * AEOProvenanceList - Display sources/citations for content\n * \n * Shows a list of provenance sources with machine-readable attributes.\n * LLMs use this to verify claims and assess source quality.\n * \n * @example\n * ```tsx\n * <AEOProvenanceList \n * title=\"Sources\"\n * sources={[\n * { id: '1', source_type: 'legal_statute', title: 'KRS 281A.170', url: '...' },\n * { id: '2', source_type: 'news_article', title: 'CDL News', publisher: 'Transport Weekly' }\n * ]}\n * />\n * ```\n */\nexport function AEOProvenanceList({\n sources,\n title = 'Sources & References',\n className = '',\n}: {\n sources: Array<{\n id: string\n source_type: 'press_release' | 'news_article' | 'legal_statute' | 'research_paper' | 'official_document' | 'internal' | 'citation'\n title: string\n url?: string\n publisher?: string\n published_at?: string\n accessed_at?: string\n excerpt?: string\n confidence?: number\n identifier?: string\n }>\n title?: string\n className?: string\n}): React.ReactElement {\n const baseClasses = 'aeo-provenance-list'\n const combinedClasses = className ? `${baseClasses} ${className}` : baseClasses\n\n const getSchemaType = (sourceType: string): string => {\n switch (sourceType) {\n case 'legal_statute':\n return 'https://schema.org/Legislation'\n case 'research_paper':\n return 'https://schema.org/ScholarlyArticle'\n case 'news_article':\n return 'https://schema.org/NewsArticle'\n case 'press_release':\n return 'https://schema.org/NewsArticle'\n default:\n return 'https://schema.org/CreativeWork'\n }\n }\n\n return (\n <aside \n className={combinedClasses}\n data-sonor-provenance=\"list\"\n data-sonor-source-count={sources.length.toString()}\n itemScope\n itemType=\"https://schema.org/ItemList\"\n >\n <h4 className=\"aeo-provenance-title\" itemProp=\"name\">{title}</h4>\n <ol className=\"aeo-provenance-sources\">\n {sources.map((source, index) => (\n <li \n key={source.id}\n className=\"aeo-provenance-item\"\n data-sonor-source-id={source.id}\n data-sonor-source-type={source.source_type}\n {...(source.confidence && { 'data-sonor-confidence': source.confidence.toString() })}\n itemScope\n itemType={getSchemaType(source.source_type)}\n itemProp=\"itemListElement\"\n >\n <span className=\"aeo-provenance-number\">[{index + 1}]</span>\n {source.url ? (\n <a \n href={source.url} \n className=\"aeo-provenance-link\"\n itemProp=\"url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span itemProp=\"name\">{source.title}</span>\n </a>\n ) : (\n <span itemProp=\"name\">{source.title}</span>\n )}\n {source.publisher && (\n <span className=\"aeo-provenance-publisher\" itemProp=\"publisher\">\n — {source.publisher}\n </span>\n )}\n {source.published_at && (\n <time \n className=\"aeo-provenance-date\" \n itemProp=\"datePublished\"\n dateTime={source.published_at}\n >\n ({new Date(source.published_at).toLocaleDateString()})\n </time>\n )}\n {source.identifier && (\n <span className=\"aeo-provenance-identifier\" data-sonor-identifier={source.identifier}>\n {source.identifier}\n </span>\n )}\n {source.excerpt && (\n <blockquote className=\"aeo-provenance-excerpt\" itemProp=\"description\">\n {source.excerpt}\n </blockquote>\n )}\n </li>\n ))}\n </ol>\n </aside>\n )\n}\n\n/**\n * AEOCitedContent - Content with inline citations linked to sources\n * \n * Wraps content that contains numbered citations [1], [2] etc., and links them\n * to a list of provenance sources for AI verification.\n * \n * @example\n * ```tsx\n * <AEOCitedContent \n * sources={[\n * { id: '1', source_type: 'legal_statute', title: 'KRS 281A.170' },\n * { id: '2', source_type: 'news_article', title: 'FMCSA Guidelines 2024' }\n * ]}\n * showSourcesList={true}\n * >\n * <p>Kentucky law requires CDL holders to report violations within 30 days [1]. \n * Federal guidelines add additional requirements [2].</p>\n * </AEOCitedContent>\n * ```\n */\nexport function AEOCitedContent({\n children,\n sources,\n showSourcesList = true,\n className = '',\n}: {\n children: React.ReactNode\n sources: Array<{\n id: string\n source_type: 'press_release' | 'news_article' | 'legal_statute' | 'research_paper' | 'official_document' | 'internal' | 'citation'\n title: string\n url?: string\n publisher?: string\n published_at?: string\n accessed_at?: string\n excerpt?: string\n confidence?: number\n identifier?: string\n }>\n showSourcesList?: boolean\n className?: string\n}): React.ReactElement {\n const baseClasses = 'aeo-cited-content'\n const combinedClasses = className ? `${baseClasses} ${className}` : baseClasses\n\n return (\n <section \n className={combinedClasses}\n data-sonor-ai=\"cited-content\"\n data-sonor-provenance=\"inline\"\n data-sonor-source-count={sources.length.toString()}\n >\n <div className=\"aeo-cited-body\">\n {children}\n </div>\n {showSourcesList && sources.length > 0 && (\n <AEOProvenanceList sources={sources} title=\"References\" />\n )}\n </section>\n )\n}\n\nexport default AEOBlock\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/site-kit/manifest
|
|
3
|
+
*
|
|
4
|
+
* PWA manifest generator. Fetches project name, description, brand colors,
|
|
5
|
+
* and logo from Portal to generate a compliant Web App Manifest.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // app/manifest.webmanifest/route.ts
|
|
10
|
+
* import { createManifest } from '@sonordev/site-kit/manifest'
|
|
11
|
+
* export const GET = createManifest()
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @example With overrides:
|
|
15
|
+
* ```ts
|
|
16
|
+
* export const GET = createManifest({
|
|
17
|
+
* display: 'fullscreen',
|
|
18
|
+
* themeColor: '#1a1a2e',
|
|
19
|
+
* categories: ['business', 'productivity'],
|
|
20
|
+
* })
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
interface ManifestConfig {
|
|
24
|
+
/** App name. Defaults to Portal project name. */
|
|
25
|
+
name?: string;
|
|
26
|
+
/** Short name for home screen. Defaults to first word of name. */
|
|
27
|
+
shortName?: string;
|
|
28
|
+
/** App description. Defaults to Portal project description. */
|
|
29
|
+
description?: string;
|
|
30
|
+
/** Theme color for browser chrome. Defaults to Portal brand color or #4bbf39. */
|
|
31
|
+
themeColor?: string;
|
|
32
|
+
/** Background color for splash screen. Default: '#ffffff' */
|
|
33
|
+
backgroundColor?: string;
|
|
34
|
+
/** Display mode. Default: 'standalone' */
|
|
35
|
+
display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser';
|
|
36
|
+
/** Orientation preference. Default: 'any' */
|
|
37
|
+
orientation?: 'portrait-primary' | 'landscape-primary' | 'any';
|
|
38
|
+
/** Start URL. Default: '/' */
|
|
39
|
+
startUrl?: string;
|
|
40
|
+
/** Scope. Default: '/' */
|
|
41
|
+
scope?: string;
|
|
42
|
+
/** App categories */
|
|
43
|
+
categories?: string[];
|
|
44
|
+
/** Custom icons. If not provided, derived from Portal logo. */
|
|
45
|
+
icons?: Array<{
|
|
46
|
+
src: string;
|
|
47
|
+
sizes: string;
|
|
48
|
+
type: string;
|
|
49
|
+
purpose?: string;
|
|
50
|
+
}>;
|
|
51
|
+
/** Portal API key. Defaults from env. */
|
|
52
|
+
apiKey?: string;
|
|
53
|
+
/** Portal API URL. Defaults from env. */
|
|
54
|
+
apiUrl?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create a route handler that serves the PWA manifest.
|
|
58
|
+
* Fetches project data from Portal and merges with config overrides.
|
|
59
|
+
*/
|
|
60
|
+
declare function createManifest(config?: ManifestConfig): () => Promise<Response>;
|
|
61
|
+
|
|
62
|
+
export { type ManifestConfig, createManifest };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/site-kit/manifest
|
|
3
|
+
*
|
|
4
|
+
* PWA manifest generator. Fetches project name, description, brand colors,
|
|
5
|
+
* and logo from Portal to generate a compliant Web App Manifest.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // app/manifest.webmanifest/route.ts
|
|
10
|
+
* import { createManifest } from '@sonordev/site-kit/manifest'
|
|
11
|
+
* export const GET = createManifest()
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @example With overrides:
|
|
15
|
+
* ```ts
|
|
16
|
+
* export const GET = createManifest({
|
|
17
|
+
* display: 'fullscreen',
|
|
18
|
+
* themeColor: '#1a1a2e',
|
|
19
|
+
* categories: ['business', 'productivity'],
|
|
20
|
+
* })
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
interface ManifestConfig {
|
|
24
|
+
/** App name. Defaults to Portal project name. */
|
|
25
|
+
name?: string;
|
|
26
|
+
/** Short name for home screen. Defaults to first word of name. */
|
|
27
|
+
shortName?: string;
|
|
28
|
+
/** App description. Defaults to Portal project description. */
|
|
29
|
+
description?: string;
|
|
30
|
+
/** Theme color for browser chrome. Defaults to Portal brand color or #4bbf39. */
|
|
31
|
+
themeColor?: string;
|
|
32
|
+
/** Background color for splash screen. Default: '#ffffff' */
|
|
33
|
+
backgroundColor?: string;
|
|
34
|
+
/** Display mode. Default: 'standalone' */
|
|
35
|
+
display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser';
|
|
36
|
+
/** Orientation preference. Default: 'any' */
|
|
37
|
+
orientation?: 'portrait-primary' | 'landscape-primary' | 'any';
|
|
38
|
+
/** Start URL. Default: '/' */
|
|
39
|
+
startUrl?: string;
|
|
40
|
+
/** Scope. Default: '/' */
|
|
41
|
+
scope?: string;
|
|
42
|
+
/** App categories */
|
|
43
|
+
categories?: string[];
|
|
44
|
+
/** Custom icons. If not provided, derived from Portal logo. */
|
|
45
|
+
icons?: Array<{
|
|
46
|
+
src: string;
|
|
47
|
+
sizes: string;
|
|
48
|
+
type: string;
|
|
49
|
+
purpose?: string;
|
|
50
|
+
}>;
|
|
51
|
+
/** Portal API key. Defaults from env. */
|
|
52
|
+
apiKey?: string;
|
|
53
|
+
/** Portal API URL. Defaults from env. */
|
|
54
|
+
apiUrl?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create a route handler that serves the PWA manifest.
|
|
58
|
+
* Fetches project data from Portal and merges with config overrides.
|
|
59
|
+
*/
|
|
60
|
+
declare function createManifest(config?: ManifestConfig): () => Promise<Response>;
|
|
61
|
+
|
|
62
|
+
export { type ManifestConfig, createManifest };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk7557OTHW_js = require('../chunk-7557OTHW.js');
|
|
4
|
+
require('../chunk-ZSMWDLMK.js');
|
|
5
|
+
|
|
6
|
+
// src/manifest/index.ts
|
|
7
|
+
async function fetchProjectInfo(apiKey, apiUrl) {
|
|
8
|
+
try {
|
|
9
|
+
const fetchOptions = {
|
|
10
|
+
headers: {
|
|
11
|
+
"Content-Type": "application/json",
|
|
12
|
+
"x-api-key": apiKey
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
fetchOptions.next = { revalidate: 3600 };
|
|
16
|
+
const res = await fetch(
|
|
17
|
+
`${apiUrl}/api/public/seo/project-info`,
|
|
18
|
+
fetchOptions
|
|
19
|
+
);
|
|
20
|
+
if (!res.ok) return null;
|
|
21
|
+
return await res.json();
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function createManifest(config) {
|
|
27
|
+
return async function GET() {
|
|
28
|
+
const apiKey = config?.apiKey ?? process.env.UPTRADE_API_KEY ?? process.env.NEXT_PUBLIC_UPTRADE_API_KEY ?? "";
|
|
29
|
+
const apiUrl = config?.apiUrl ?? process.env.UPTRADE_API_URL ?? process.env.NEXT_PUBLIC_UPTRADE_API_URL ?? "https://api.uptrademedia.com";
|
|
30
|
+
let project = null;
|
|
31
|
+
if (apiKey) {
|
|
32
|
+
project = await fetchProjectInfo(apiKey, apiUrl);
|
|
33
|
+
}
|
|
34
|
+
apiKey ? await chunk7557OTHW_js.getSiteConfig({ apiKey, apiUrl }).catch(() => null) : null;
|
|
35
|
+
const name = config?.name ?? project?.name ?? "My Site";
|
|
36
|
+
const shortName = config?.shortName ?? name.split(/\s+/)[0] ?? name;
|
|
37
|
+
const description = config?.description ?? project?.description ?? "";
|
|
38
|
+
const themeColor = config?.themeColor ?? project?.brand_primary ?? "#4bbf39";
|
|
39
|
+
const backgroundColor = config?.backgroundColor ?? "#ffffff";
|
|
40
|
+
const startUrl = config?.startUrl ?? "/";
|
|
41
|
+
const logoUrl = project?.logo_url;
|
|
42
|
+
const icons = config?.icons ?? (logoUrl ? [
|
|
43
|
+
{
|
|
44
|
+
src: logoUrl,
|
|
45
|
+
sizes: "192x192",
|
|
46
|
+
type: "image/png"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
src: logoUrl,
|
|
50
|
+
sizes: "512x512",
|
|
51
|
+
type: "image/png"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
src: logoUrl,
|
|
55
|
+
sizes: "512x512",
|
|
56
|
+
type: "image/png",
|
|
57
|
+
purpose: "maskable"
|
|
58
|
+
}
|
|
59
|
+
] : []);
|
|
60
|
+
const manifest = {
|
|
61
|
+
name,
|
|
62
|
+
short_name: shortName,
|
|
63
|
+
description,
|
|
64
|
+
start_url: startUrl,
|
|
65
|
+
scope: config?.scope ?? "/",
|
|
66
|
+
display: config?.display ?? "standalone",
|
|
67
|
+
orientation: config?.orientation ?? "any",
|
|
68
|
+
theme_color: themeColor,
|
|
69
|
+
background_color: backgroundColor,
|
|
70
|
+
icons,
|
|
71
|
+
...config?.categories?.length ? { categories: config.categories } : {}
|
|
72
|
+
};
|
|
73
|
+
return new Response(JSON.stringify(manifest, null, 2), {
|
|
74
|
+
status: 200,
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Type": "application/manifest+json",
|
|
77
|
+
"Cache-Control": "public, max-age=86400, s-maxage=86400"
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
exports.createManifest = createManifest;
|
|
84
|
+
//# sourceMappingURL=index.js.map
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/manifest/index.ts"],"names":["getSiteConfig"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @sonordev/site-kit/manifest\n *\n * PWA manifest generator. Fetches project name, description, brand colors,\n * and logo from Portal to generate a compliant Web App Manifest.\n *\n * @example\n * ```ts\n * // app/manifest.webmanifest/route.ts\n * import { createManifest } from '@sonordev/site-kit/manifest'\n * export const GET = createManifest()\n * ```\n *\n * @example With overrides:\n * ```ts\n * export const GET = createManifest({\n * display: 'fullscreen',\n * themeColor: '#1a1a2e',\n * categories: ['business', 'productivity'],\n * })\n * ```\n */\n\nimport { getSiteConfig } from '../site-config'\n\nexport interface ManifestConfig {\n /** App name. Defaults to Portal project name. */\n name?: string\n /** Short name for home screen. Defaults to first word of name. */\n shortName?: string\n /** App description. Defaults to Portal project description. */\n description?: string\n /** Theme color for browser chrome. Defaults to Portal brand color or #4bbf39. */\n themeColor?: string\n /** Background color for splash screen. Default: '#ffffff' */\n backgroundColor?: string\n /** Display mode. Default: 'standalone' */\n display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser'\n /** Orientation preference. Default: 'any' */\n orientation?: 'portrait-primary' | 'landscape-primary' | 'any'\n /** Start URL. Default: '/' */\n startUrl?: string\n /** Scope. Default: '/' */\n scope?: string\n /** App categories */\n categories?: string[]\n /** Custom icons. If not provided, derived from Portal logo. */\n icons?: Array<{\n src: string\n sizes: string\n type: string\n purpose?: string\n }>\n /** Portal API key. Defaults from env. */\n apiKey?: string\n /** Portal API URL. Defaults from env. */\n apiUrl?: string\n}\n\ninterface ProjectInfo {\n site_url?: string\n domain?: string\n name?: string\n description?: string\n logo_url?: string\n brand_primary?: string\n}\n\nasync function fetchProjectInfo(\n apiKey: string,\n apiUrl: string,\n): Promise<ProjectInfo | null> {\n try {\n const fetchOptions: RequestInit & Record<string, unknown> = {\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n }\n // Next.js fetch extension for ISR caching\n ;(fetchOptions as any).next = { revalidate: 3600 }\n const res = await fetch(\n `${apiUrl}/api/public/seo/project-info`,\n fetchOptions,\n )\n if (!res.ok) return null\n return await res.json()\n } catch {\n return null\n }\n}\n\n/**\n * Create a route handler that serves the PWA manifest.\n * Fetches project data from Portal and merges with config overrides.\n */\nexport function createManifest(\n config?: ManifestConfig,\n): () => Promise<Response> {\n return async function GET(): Promise<Response> {\n const apiKey =\n config?.apiKey ??\n process.env.UPTRADE_API_KEY ??\n process.env.NEXT_PUBLIC_UPTRADE_API_KEY ??\n ''\n const apiUrl =\n config?.apiUrl ??\n process.env.UPTRADE_API_URL ??\n process.env.NEXT_PUBLIC_UPTRADE_API_URL ??\n 'https://api.uptrademedia.com'\n\n // Fetch project info for defaults\n let project: ProjectInfo | null = null\n if (apiKey) {\n project = await fetchProjectInfo(apiKey, apiUrl)\n }\n\n // Also try getSiteConfig for site_url\n const siteConfig = apiKey\n ? await getSiteConfig({ apiKey, apiUrl }).catch(() => null)\n : null\n\n const name = config?.name ?? project?.name ?? 'My Site'\n const shortName =\n config?.shortName ?? name.split(/\\s+/)[0] ?? name\n const description =\n config?.description ?? project?.description ?? ''\n const themeColor =\n config?.themeColor ?? project?.brand_primary ?? '#4bbf39'\n const backgroundColor = config?.backgroundColor ?? '#ffffff'\n const startUrl = config?.startUrl ?? '/'\n\n // Build icons array\n const logoUrl = project?.logo_url\n const icons =\n config?.icons ??\n (logoUrl\n ? [\n {\n src: logoUrl,\n sizes: '192x192',\n type: 'image/png',\n },\n {\n src: logoUrl,\n sizes: '512x512',\n type: 'image/png',\n },\n {\n src: logoUrl,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'maskable',\n },\n ]\n : [])\n\n const manifest = {\n name,\n short_name: shortName,\n description,\n start_url: startUrl,\n scope: config?.scope ?? '/',\n display: config?.display ?? 'standalone',\n orientation: config?.orientation ?? 'any',\n theme_color: themeColor,\n background_color: backgroundColor,\n icons,\n ...(config?.categories?.length\n ? { categories: config.categories }\n : {}),\n }\n\n return new Response(JSON.stringify(manifest, null, 2), {\n status: 200,\n headers: {\n 'Content-Type': 'application/manifest+json',\n 'Cache-Control':\n 'public, max-age=86400, s-maxage=86400',\n },\n })\n }\n}\n"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { getSiteConfig } from '../chunk-GCJXQ4AG.mjs';
|
|
2
|
+
import '../chunk-4XPGGLVP.mjs';
|
|
3
|
+
|
|
4
|
+
// src/manifest/index.ts
|
|
5
|
+
async function fetchProjectInfo(apiKey, apiUrl) {
|
|
6
|
+
try {
|
|
7
|
+
const fetchOptions = {
|
|
8
|
+
headers: {
|
|
9
|
+
"Content-Type": "application/json",
|
|
10
|
+
"x-api-key": apiKey
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
fetchOptions.next = { revalidate: 3600 };
|
|
14
|
+
const res = await fetch(
|
|
15
|
+
`${apiUrl}/api/public/seo/project-info`,
|
|
16
|
+
fetchOptions
|
|
17
|
+
);
|
|
18
|
+
if (!res.ok) return null;
|
|
19
|
+
return await res.json();
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function createManifest(config) {
|
|
25
|
+
return async function GET() {
|
|
26
|
+
const apiKey = config?.apiKey ?? process.env.UPTRADE_API_KEY ?? process.env.NEXT_PUBLIC_UPTRADE_API_KEY ?? "";
|
|
27
|
+
const apiUrl = config?.apiUrl ?? process.env.UPTRADE_API_URL ?? process.env.NEXT_PUBLIC_UPTRADE_API_URL ?? "https://api.uptrademedia.com";
|
|
28
|
+
let project = null;
|
|
29
|
+
if (apiKey) {
|
|
30
|
+
project = await fetchProjectInfo(apiKey, apiUrl);
|
|
31
|
+
}
|
|
32
|
+
apiKey ? await getSiteConfig({ apiKey, apiUrl }).catch(() => null) : null;
|
|
33
|
+
const name = config?.name ?? project?.name ?? "My Site";
|
|
34
|
+
const shortName = config?.shortName ?? name.split(/\s+/)[0] ?? name;
|
|
35
|
+
const description = config?.description ?? project?.description ?? "";
|
|
36
|
+
const themeColor = config?.themeColor ?? project?.brand_primary ?? "#4bbf39";
|
|
37
|
+
const backgroundColor = config?.backgroundColor ?? "#ffffff";
|
|
38
|
+
const startUrl = config?.startUrl ?? "/";
|
|
39
|
+
const logoUrl = project?.logo_url;
|
|
40
|
+
const icons = config?.icons ?? (logoUrl ? [
|
|
41
|
+
{
|
|
42
|
+
src: logoUrl,
|
|
43
|
+
sizes: "192x192",
|
|
44
|
+
type: "image/png"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
src: logoUrl,
|
|
48
|
+
sizes: "512x512",
|
|
49
|
+
type: "image/png"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
src: logoUrl,
|
|
53
|
+
sizes: "512x512",
|
|
54
|
+
type: "image/png",
|
|
55
|
+
purpose: "maskable"
|
|
56
|
+
}
|
|
57
|
+
] : []);
|
|
58
|
+
const manifest = {
|
|
59
|
+
name,
|
|
60
|
+
short_name: shortName,
|
|
61
|
+
description,
|
|
62
|
+
start_url: startUrl,
|
|
63
|
+
scope: config?.scope ?? "/",
|
|
64
|
+
display: config?.display ?? "standalone",
|
|
65
|
+
orientation: config?.orientation ?? "any",
|
|
66
|
+
theme_color: themeColor,
|
|
67
|
+
background_color: backgroundColor,
|
|
68
|
+
icons,
|
|
69
|
+
...config?.categories?.length ? { categories: config.categories } : {}
|
|
70
|
+
};
|
|
71
|
+
return new Response(JSON.stringify(manifest, null, 2), {
|
|
72
|
+
status: 200,
|
|
73
|
+
headers: {
|
|
74
|
+
"Content-Type": "application/manifest+json",
|
|
75
|
+
"Cache-Control": "public, max-age=86400, s-maxage=86400"
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { createManifest };
|
|
82
|
+
//# sourceMappingURL=index.mjs.map
|
|
83
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/manifest/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @sonordev/site-kit/manifest\n *\n * PWA manifest generator. Fetches project name, description, brand colors,\n * and logo from Portal to generate a compliant Web App Manifest.\n *\n * @example\n * ```ts\n * // app/manifest.webmanifest/route.ts\n * import { createManifest } from '@sonordev/site-kit/manifest'\n * export const GET = createManifest()\n * ```\n *\n * @example With overrides:\n * ```ts\n * export const GET = createManifest({\n * display: 'fullscreen',\n * themeColor: '#1a1a2e',\n * categories: ['business', 'productivity'],\n * })\n * ```\n */\n\nimport { getSiteConfig } from '../site-config'\n\nexport interface ManifestConfig {\n /** App name. Defaults to Portal project name. */\n name?: string\n /** Short name for home screen. Defaults to first word of name. */\n shortName?: string\n /** App description. Defaults to Portal project description. */\n description?: string\n /** Theme color for browser chrome. Defaults to Portal brand color or #4bbf39. */\n themeColor?: string\n /** Background color for splash screen. Default: '#ffffff' */\n backgroundColor?: string\n /** Display mode. Default: 'standalone' */\n display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser'\n /** Orientation preference. Default: 'any' */\n orientation?: 'portrait-primary' | 'landscape-primary' | 'any'\n /** Start URL. Default: '/' */\n startUrl?: string\n /** Scope. Default: '/' */\n scope?: string\n /** App categories */\n categories?: string[]\n /** Custom icons. If not provided, derived from Portal logo. */\n icons?: Array<{\n src: string\n sizes: string\n type: string\n purpose?: string\n }>\n /** Portal API key. Defaults from env. */\n apiKey?: string\n /** Portal API URL. Defaults from env. */\n apiUrl?: string\n}\n\ninterface ProjectInfo {\n site_url?: string\n domain?: string\n name?: string\n description?: string\n logo_url?: string\n brand_primary?: string\n}\n\nasync function fetchProjectInfo(\n apiKey: string,\n apiUrl: string,\n): Promise<ProjectInfo | null> {\n try {\n const fetchOptions: RequestInit & Record<string, unknown> = {\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n }\n // Next.js fetch extension for ISR caching\n ;(fetchOptions as any).next = { revalidate: 3600 }\n const res = await fetch(\n `${apiUrl}/api/public/seo/project-info`,\n fetchOptions,\n )\n if (!res.ok) return null\n return await res.json()\n } catch {\n return null\n }\n}\n\n/**\n * Create a route handler that serves the PWA manifest.\n * Fetches project data from Portal and merges with config overrides.\n */\nexport function createManifest(\n config?: ManifestConfig,\n): () => Promise<Response> {\n return async function GET(): Promise<Response> {\n const apiKey =\n config?.apiKey ??\n process.env.UPTRADE_API_KEY ??\n process.env.NEXT_PUBLIC_UPTRADE_API_KEY ??\n ''\n const apiUrl =\n config?.apiUrl ??\n process.env.UPTRADE_API_URL ??\n process.env.NEXT_PUBLIC_UPTRADE_API_URL ??\n 'https://api.uptrademedia.com'\n\n // Fetch project info for defaults\n let project: ProjectInfo | null = null\n if (apiKey) {\n project = await fetchProjectInfo(apiKey, apiUrl)\n }\n\n // Also try getSiteConfig for site_url\n const siteConfig = apiKey\n ? await getSiteConfig({ apiKey, apiUrl }).catch(() => null)\n : null\n\n const name = config?.name ?? project?.name ?? 'My Site'\n const shortName =\n config?.shortName ?? name.split(/\\s+/)[0] ?? name\n const description =\n config?.description ?? project?.description ?? ''\n const themeColor =\n config?.themeColor ?? project?.brand_primary ?? '#4bbf39'\n const backgroundColor = config?.backgroundColor ?? '#ffffff'\n const startUrl = config?.startUrl ?? '/'\n\n // Build icons array\n const logoUrl = project?.logo_url\n const icons =\n config?.icons ??\n (logoUrl\n ? [\n {\n src: logoUrl,\n sizes: '192x192',\n type: 'image/png',\n },\n {\n src: logoUrl,\n sizes: '512x512',\n type: 'image/png',\n },\n {\n src: logoUrl,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'maskable',\n },\n ]\n : [])\n\n const manifest = {\n name,\n short_name: shortName,\n description,\n start_url: startUrl,\n scope: config?.scope ?? '/',\n display: config?.display ?? 'standalone',\n orientation: config?.orientation ?? 'any',\n theme_color: themeColor,\n background_color: backgroundColor,\n icons,\n ...(config?.categories?.length\n ? { categories: config.categories }\n : {}),\n }\n\n return new Response(JSON.stringify(manifest, null, 2), {\n status: 200,\n headers: {\n 'Content-Type': 'application/manifest+json',\n 'Cache-Control':\n 'public, max-age=86400, s-maxage=86400',\n },\n })\n }\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { RedirectConfig } from '../redirects/index.mjs';
|
|
3
|
+
import { S as SecurityHeadersConfig } from '../securityHeaders-nwZ6nP4g.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @sonordev/site-kit/middleware
|
|
7
|
+
*
|
|
8
|
+
* Composable Next.js middleware factory. Handles:
|
|
9
|
+
* - Portal-managed redirects (via existing handleManagedRedirects)
|
|
10
|
+
* - Security headers (X-Frame-Options, CSP, etc.)
|
|
11
|
+
* - Optional before/after hooks for custom logic
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* // middleware.ts — entire file
|
|
16
|
+
* import { createMiddleware, siteKitMatcher } from '@sonordev/site-kit/middleware'
|
|
17
|
+
*
|
|
18
|
+
* export default createMiddleware()
|
|
19
|
+
* export const config = siteKitMatcher
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example With custom hooks:
|
|
23
|
+
* ```ts
|
|
24
|
+
* export default createMiddleware({
|
|
25
|
+
* securityHeaders: { frameOptions: 'SAMEORIGIN' },
|
|
26
|
+
* before: (req) => {
|
|
27
|
+
* // Custom auth check, etc.
|
|
28
|
+
* },
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
interface SiteKitMiddlewareConfig {
|
|
34
|
+
/** Enable Portal-managed redirects. Default: true */
|
|
35
|
+
redirects?: boolean | RedirectConfig;
|
|
36
|
+
/** Enable security headers. Default: true */
|
|
37
|
+
securityHeaders?: boolean | SecurityHeadersConfig;
|
|
38
|
+
/**
|
|
39
|
+
* Hook that runs BEFORE redirect check.
|
|
40
|
+
* Return a NextResponse to short-circuit, or undefined to continue.
|
|
41
|
+
*/
|
|
42
|
+
before?: (request: NextRequest) => NextResponse | undefined | Promise<NextResponse | undefined>;
|
|
43
|
+
/**
|
|
44
|
+
* Hook that runs AFTER all processing.
|
|
45
|
+
* Receives the response that will be sent — mutate headers, etc.
|
|
46
|
+
*/
|
|
47
|
+
after?: (request: NextRequest, response: NextResponse) => NextResponse | Promise<NextResponse>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a fully-featured Next.js middleware function.
|
|
51
|
+
*
|
|
52
|
+
* With zero config this handles redirects + security headers automatically.
|
|
53
|
+
*/
|
|
54
|
+
declare function createMiddleware(config?: SiteKitMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
55
|
+
/**
|
|
56
|
+
* Standard matcher config that excludes static assets and images.
|
|
57
|
+
* Export alongside createMiddleware in your middleware.ts.
|
|
58
|
+
*/
|
|
59
|
+
declare const siteKitMatcher: {
|
|
60
|
+
matcher: string[];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export { SecurityHeadersConfig, type SiteKitMiddlewareConfig, createMiddleware, siteKitMatcher };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { RedirectConfig } from '../redirects/index.js';
|
|
3
|
+
import { S as SecurityHeadersConfig } from '../securityHeaders-nwZ6nP4g.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @sonordev/site-kit/middleware
|
|
7
|
+
*
|
|
8
|
+
* Composable Next.js middleware factory. Handles:
|
|
9
|
+
* - Portal-managed redirects (via existing handleManagedRedirects)
|
|
10
|
+
* - Security headers (X-Frame-Options, CSP, etc.)
|
|
11
|
+
* - Optional before/after hooks for custom logic
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* // middleware.ts — entire file
|
|
16
|
+
* import { createMiddleware, siteKitMatcher } from '@sonordev/site-kit/middleware'
|
|
17
|
+
*
|
|
18
|
+
* export default createMiddleware()
|
|
19
|
+
* export const config = siteKitMatcher
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example With custom hooks:
|
|
23
|
+
* ```ts
|
|
24
|
+
* export default createMiddleware({
|
|
25
|
+
* securityHeaders: { frameOptions: 'SAMEORIGIN' },
|
|
26
|
+
* before: (req) => {
|
|
27
|
+
* // Custom auth check, etc.
|
|
28
|
+
* },
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
interface SiteKitMiddlewareConfig {
|
|
34
|
+
/** Enable Portal-managed redirects. Default: true */
|
|
35
|
+
redirects?: boolean | RedirectConfig;
|
|
36
|
+
/** Enable security headers. Default: true */
|
|
37
|
+
securityHeaders?: boolean | SecurityHeadersConfig;
|
|
38
|
+
/**
|
|
39
|
+
* Hook that runs BEFORE redirect check.
|
|
40
|
+
* Return a NextResponse to short-circuit, or undefined to continue.
|
|
41
|
+
*/
|
|
42
|
+
before?: (request: NextRequest) => NextResponse | undefined | Promise<NextResponse | undefined>;
|
|
43
|
+
/**
|
|
44
|
+
* Hook that runs AFTER all processing.
|
|
45
|
+
* Receives the response that will be sent — mutate headers, etc.
|
|
46
|
+
*/
|
|
47
|
+
after?: (request: NextRequest, response: NextResponse) => NextResponse | Promise<NextResponse>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a fully-featured Next.js middleware function.
|
|
51
|
+
*
|
|
52
|
+
* With zero config this handles redirects + security headers automatically.
|
|
53
|
+
*/
|
|
54
|
+
declare function createMiddleware(config?: SiteKitMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
55
|
+
/**
|
|
56
|
+
* Standard matcher config that excludes static assets and images.
|
|
57
|
+
* Export alongside createMiddleware in your middleware.ts.
|
|
58
|
+
*/
|
|
59
|
+
declare const siteKitMatcher: {
|
|
60
|
+
matcher: string[];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export { SecurityHeadersConfig, type SiteKitMiddlewareConfig, createMiddleware, siteKitMatcher };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk3MYZS6PD_js = require('../chunk-3MYZS6PD.js');
|
|
4
|
+
var chunkLBVWVP72_js = require('../chunk-LBVWVP72.js');
|
|
5
|
+
require('../chunk-7557OTHW.js');
|
|
6
|
+
require('../chunk-ZSMWDLMK.js');
|
|
7
|
+
var server = require('next/server');
|
|
8
|
+
|
|
9
|
+
function createMiddleware(config) {
|
|
10
|
+
const securityHeaders = chunk3MYZS6PD_js.buildSecurityHeaders(
|
|
11
|
+
config?.securityHeaders
|
|
12
|
+
);
|
|
13
|
+
return async function middleware(request) {
|
|
14
|
+
if (config?.before) {
|
|
15
|
+
const earlyResponse = await config.before(request);
|
|
16
|
+
if (earlyResponse) {
|
|
17
|
+
applyHeaders(earlyResponse, securityHeaders);
|
|
18
|
+
return earlyResponse;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (config?.redirects !== false) {
|
|
22
|
+
const redirectConfig = typeof config?.redirects === "object" ? config.redirects : {};
|
|
23
|
+
const redirect = await chunkLBVWVP72_js.handleManagedRedirects(
|
|
24
|
+
request,
|
|
25
|
+
redirectConfig
|
|
26
|
+
);
|
|
27
|
+
if (redirect) {
|
|
28
|
+
applyHeaders(redirect, securityHeaders);
|
|
29
|
+
return redirect;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
let response = server.NextResponse.next();
|
|
33
|
+
applyHeaders(response, securityHeaders);
|
|
34
|
+
if (config?.after) {
|
|
35
|
+
response = await config.after(request, response);
|
|
36
|
+
}
|
|
37
|
+
return response;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function applyHeaders(response, headers) {
|
|
41
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
42
|
+
response.headers.set(key, value);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
var siteKitMatcher = {
|
|
46
|
+
matcher: [
|
|
47
|
+
"/((?!_next/static|_next/image|favicon\\.ico|.*\\.(?:ico|png|jpg|jpeg|gif|webp|svg|woff2?)$).*)"
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
exports.createMiddleware = createMiddleware;
|
|
52
|
+
exports.siteKitMatcher = siteKitMatcher;
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/middleware/index.ts"],"names":["buildSecurityHeaders","handleManagedRedirects","NextResponse"],"mappings":";;;;;;;;AAmEO,SAAS,iBAAiB,MAAA,EAAkC;AACjE,EAAA,MAAM,eAAA,GAAkBA,qCAAA;AAAA,IACtB,MAAA,EAAQ;AAAA,GACV;AAEA,EAAA,OAAO,eAAe,WACpB,OAAA,EACuB;AAEvB,IAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,MAAA,MAAM,aAAA,GAAgB,MAAM,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AACjD,MAAA,IAAI,aAAA,EAAe;AAEjB,QAAA,YAAA,CAAa,eAAe,eAAe,CAAA;AAC3C,QAAA,OAAO,aAAA;AAAA,MACT;AAAA,IACF;AAGA,IAAA,IAAI,MAAA,EAAQ,cAAc,KAAA,EAAO;AAC/B,MAAA,MAAM,iBACJ,OAAO,MAAA,EAAQ,cAAc,QAAA,GACzB,MAAA,CAAO,YACP,EAAC;AAEP,MAAA,MAAM,WAAW,MAAMC,uCAAA;AAAA,QACrB,OAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA,IAAI,QAAA,EAAU;AAEZ,QAAA,YAAA,CAAa,UAAU,eAAe,CAAA;AACtC,QAAA,OAAO,QAAA;AAAA,MACT;AAAA,IACF;AAGA,IAAA,IAAI,QAAA,GAAWC,oBAAa,IAAA,EAAK;AAGjC,IAAA,YAAA,CAAa,UAAU,eAAe,CAAA;AAGtC,IAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,MAAA,QAAA,GAAW,MAAM,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS,QAAQ,CAAA;AAAA,IACjD;AAEA,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACF;AAEA,SAAS,YAAA,CACP,UACA,OAAA,EACM;AACN,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AAClD,IAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EACjC;AACF;AAMO,IAAM,cAAA,GAAiB;AAAA,EAC5B,OAAA,EAAS;AAAA,IACP;AAAA;AAEJ","file":"index.js","sourcesContent":["/**\n * @sonordev/site-kit/middleware\n *\n * Composable Next.js middleware factory. Handles:\n * - Portal-managed redirects (via existing handleManagedRedirects)\n * - Security headers (X-Frame-Options, CSP, etc.)\n * - Optional before/after hooks for custom logic\n *\n * @example\n * ```ts\n * // middleware.ts — entire file\n * import { createMiddleware, siteKitMatcher } from '@sonordev/site-kit/middleware'\n *\n * export default createMiddleware()\n * export const config = siteKitMatcher\n * ```\n *\n * @example With custom hooks:\n * ```ts\n * export default createMiddleware({\n * securityHeaders: { frameOptions: 'SAMEORIGIN' },\n * before: (req) => {\n * // Custom auth check, etc.\n * },\n * })\n * ```\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\nimport {\n handleManagedRedirects,\n type RedirectConfig,\n} from '../redirects'\nimport {\n buildSecurityHeaders,\n type SecurityHeadersConfig,\n} from './securityHeaders'\n\nexport type { SecurityHeadersConfig } from './securityHeaders'\n\nexport interface SiteKitMiddlewareConfig {\n /** Enable Portal-managed redirects. Default: true */\n redirects?: boolean | RedirectConfig\n /** Enable security headers. Default: true */\n securityHeaders?: boolean | SecurityHeadersConfig\n /**\n * Hook that runs BEFORE redirect check.\n * Return a NextResponse to short-circuit, or undefined to continue.\n */\n before?: (\n request: NextRequest,\n ) => NextResponse | undefined | Promise<NextResponse | undefined>\n /**\n * Hook that runs AFTER all processing.\n * Receives the response that will be sent — mutate headers, etc.\n */\n after?: (\n request: NextRequest,\n response: NextResponse,\n ) => NextResponse | Promise<NextResponse>\n}\n\n/**\n * Create a fully-featured Next.js middleware function.\n *\n * With zero config this handles redirects + security headers automatically.\n */\nexport function createMiddleware(config?: SiteKitMiddlewareConfig) {\n const securityHeaders = buildSecurityHeaders(\n config?.securityHeaders,\n )\n\n return async function middleware(\n request: NextRequest,\n ): Promise<NextResponse> {\n // 1. Run user's 'before' hook\n if (config?.before) {\n const earlyResponse = await config.before(request)\n if (earlyResponse) {\n // Apply security headers even to early responses\n applyHeaders(earlyResponse, securityHeaders)\n return earlyResponse\n }\n }\n\n // 2. Check Portal-managed redirects (unless disabled)\n if (config?.redirects !== false) {\n const redirectConfig: RedirectConfig =\n typeof config?.redirects === 'object'\n ? config.redirects\n : {}\n\n const redirect = await handleManagedRedirects(\n request,\n redirectConfig,\n )\n if (redirect) {\n // Redirects get security headers too\n applyHeaders(redirect, securityHeaders)\n return redirect\n }\n }\n\n // 3. Build the pass-through response\n let response = NextResponse.next()\n\n // 4. Apply security headers\n applyHeaders(response, securityHeaders)\n\n // 5. Run user's 'after' hook\n if (config?.after) {\n response = await config.after(request, response)\n }\n\n return response\n }\n}\n\nfunction applyHeaders(\n response: NextResponse,\n headers: Record<string, string>,\n): void {\n for (const [key, value] of Object.entries(headers)) {\n response.headers.set(key, value)\n }\n}\n\n/**\n * Standard matcher config that excludes static assets and images.\n * Export alongside createMiddleware in your middleware.ts.\n */\nexport const siteKitMatcher = {\n matcher: [\n '/((?!_next/static|_next/image|favicon\\\\.ico|.*\\\\.(?:ico|png|jpg|jpeg|gif|webp|svg|woff2?)$).*)',\n ],\n}\n"]}
|