diff --git a/.gitignore b/.gitignore index 1437c53f7..64f8a3bc0 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,9 @@ yarn-error.log* # vercel .vercel + + +# llms.txt +/public/llms.txt +/public/llms-full.txt +/public/**/*.md diff --git a/.prettierignore b/.prettierignore index d25efbcd2..91da5dfa1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ .gitignore -.next/** \ No newline at end of file +.next/** +/public/**/*.md \ No newline at end of file diff --git a/data/integrationsSidebar.json b/data/integrationsSidebar.json new file mode 100644 index 000000000..3ab7c21cb --- /dev/null +++ b/data/integrationsSidebar.json @@ -0,0 +1,146 @@ +[ + { + "title": "Integrations", + "slug": "/integrations", + "pages": [{ "slug": "/overview", "title": "Overview" }] + }, + { + "title": "Sources", + "slug": "/integrations/sources", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/segment", "title": "Segment" }, + { "slug": "/rudderstack", "title": "RudderStack" }, + { "slug": "/hightouch", "title": "Hightouch" }, + { "slug": "/census", "title": "Census" }, + { "slug": "/polytomic", "title": "Polytomic" }, + { "slug": "/jitsu", "title": "Jitsu" }, + { "slug": "/freshpaint", "title": "Freshpaint" }, + { "slug": "/http", "title": "HTTP" } + ] + }, + { + "title": "Email", + "slug": "/integrations/email", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/layouts", "title": "Layouts" }, + { "slug": "/settings", "title": "Settings and overrides" }, + { "slug": "/attachments", "title": "Sending attachments" }, + { "slug": "/aws-ses", "title": "AWS SES" }, + { "slug": "/mailersend", "title": "MailerSend" }, + { "slug": "/mailgun", "title": "Mailgun" }, + { "slug": "/mailjet", "title": "Mailjet" }, + { "slug": "/mailtrap", "title": "Mailtrap" }, + { "slug": "/mandrill", "title": "Mandrill" }, + { "slug": "/postmark", "title": "Postmark" }, + { "slug": "/resend", "title": "Resend" }, + { "slug": "/sendgrid", "title": "SendGrid" }, + { "slug": "/smtp", "title": "SMTP" }, + { "slug": "/sparkpost", "title": "SparkPost" } + ] + }, + { + "title": "Chat", + "slug": "/integrations/chat", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { + "title": "Slack", + "slug": "/slack", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { + "slug": "/sending-an-internal-message", + "title": "Sending an internal message" + }, + { + "slug": "/sending-a-direct-message", + "title": "Sending a direct message" + }, + { + "slug": "/sending-a-message-to-channels", + "title": "Sending a message to channels" + } + ] + }, + { + "title": "Microsoft Teams", + "slug": "/microsoft-teams", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { + "slug": "/sending-an-internal-message", + "title": "Sending an internal message" + }, + { + "slug": "/sending-a-direct-message", + "title": "Sending a direct message" + }, + { + "slug": "/sending-a-message-to-channels", + "title": "Sending a message to channels" + } + ] + }, + { "slug": "/discord", "title": "Discord" }, + { "slug": "/whatsapp", "title": "WhatsApp" } + ] + }, + { + "title": "In-app", + "slug": "/integrations/in-app", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/knock", "title": "Knock" } + ] + }, + { + "title": "Push", + "slug": "/integrations/push", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/token-deregistration", "title": "Token deregistration" }, + { "slug": "/apns", "title": "Apple (APNS)" }, + { "slug": "/firebase", "title": "Firebase (FCM)" }, + { "slug": "/expo", "title": "Expo (React Native)" }, + { "slug": "/one-signal", "title": "OneSignal" } + ] + }, + { + "title": "SMS", + "slug": "/integrations/sms", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/settings-and-overrides", "title": "Settings and overrides" }, + { "slug": "/africas-talking", "title": "Africa's Talking" }, + { "slug": "/aws-sns", "title": "AWS SNS" }, + { "slug": "/mailersend", "title": "MailerSend" }, + { "slug": "/messagebird", "title": "MessageBird" }, + { "slug": "/plivo", "title": "Plivo" }, + { "slug": "/sinch", "title": "Sinch" }, + { "slug": "/sinch-message-media", "title": "Sinch MessageMedia" }, + { "slug": "/telnyx", "title": "Telnyx" }, + { "slug": "/twilio", "title": "Twilio" }, + { "slug": "/vonage", "title": "Vonage" } + ] + }, + { + "title": "Webhook", + "slug": "/integrations/webhook", + "pages": [{ "slug": "/overview", "title": "Overview" }] + }, + { + "title": "Extensions", + "slug": "/integrations/extensions", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/vercel", "title": "Vercel" }, + { "slug": "/datadog", "title": "Datadog" }, + { "slug": "/new-relic", "title": "New Relic" }, + { "slug": "/segment", "title": "Segment" }, + { "slug": "/heap", "title": "Heap" }, + { "slug": "/data-sync", "title": "Data warehouse sync" } + ] + } +] diff --git a/data/integrationsSidebar.ts b/data/integrationsSidebar.ts index e534adec3..0306efba4 100644 --- a/data/integrationsSidebar.ts +++ b/data/integrationsSidebar.ts @@ -1,155 +1,6 @@ import { SidebarSection } from "./types"; +import integrationSidebarJson from "./integrationsSidebar.json"; -const sidebarContent: SidebarSection[] = [ - { - title: "Integrations", - slug: "/integrations", - pages: [{ slug: "/overview", title: "Overview" }], - }, - { - title: "Sources", - slug: "/integrations/sources", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/segment", title: "Segment" }, - { slug: "/rudderstack", title: "RudderStack" }, - { slug: "/hightouch", title: "Hightouch" }, - { slug: "/census", title: "Census" }, - { slug: "/polytomic", title: "Polytomic" }, - { slug: "/jitsu", title: "Jitsu" }, - { slug: "/freshpaint", title: "Freshpaint" }, - { slug: "/http", title: "HTTP" }, - ], - }, - { - title: "Email", - slug: "/integrations/email", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/layouts", title: "Layouts" }, - { slug: "/settings", title: "Settings and overrides" }, - { slug: "/attachments", title: "Sending attachments" }, - { slug: "/aws-ses", title: "AWS SES" }, - { slug: "/mailersend", title: "MailerSend" }, - { slug: "/mailgun", title: "Mailgun" }, - { slug: "/mailjet", title: "Mailjet" }, - { slug: "/mailtrap", title: "Mailtrap" }, - { slug: "/mandrill", title: "Mandrill" }, - { slug: "/postmark", title: "Postmark" }, - { slug: "/resend", title: "Resend" }, - { slug: "/sendgrid", title: "SendGrid" }, - { slug: "/smtp", title: "SMTP" }, - { slug: "/sparkpost", title: "SparkPost" }, - ], - }, - - { - title: "Chat", - slug: "/integrations/chat", - pages: [ - { slug: "/overview", title: "Overview" }, - { - title: "Slack", - slug: "/slack", - pages: [ - { slug: "/overview", title: "Overview" }, - { - slug: "/sending-an-internal-message", - title: "Sending an internal message", - }, - { - slug: "/sending-a-direct-message", - title: "Sending a direct message", - }, - { - slug: "/sending-a-message-to-channels", - title: "Sending a message to channels", - }, - ], - }, - { - title: "Microsoft Teams", - slug: "/microsoft-teams", - pages: [ - { slug: "/overview", title: "Overview" }, - { - slug: "/sending-an-internal-message", - title: "Sending an internal message", - }, - { - slug: "/sending-a-direct-message", - title: "Sending a direct message", - }, - { - slug: "/sending-a-message-to-channels", - title: "Sending a message to channels", - }, - ], - }, - { slug: "/discord", title: "Discord" }, - { slug: "/whatsapp", title: "WhatsApp" }, - ], - }, - - { - title: "In-app", - slug: "/integrations/in-app", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/knock", title: "Knock" }, - ], - }, - - { - title: "Push", - slug: "/integrations/push", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/token-deregistration", title: "Token deregistration" }, - { slug: "/apns", title: "Apple (APNS)" }, - { slug: "/firebase", title: "Firebase (FCM)" }, - { slug: "/expo", title: "Expo (React Native)" }, - { slug: "/one-signal", title: "OneSignal" }, - ], - }, - - { - title: "SMS", - slug: "/integrations/sms", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/settings-and-overrides", title: "Settings and overrides" }, - { slug: "/africas-talking", title: "Africa's Talking" }, - { slug: "/aws-sns", title: "AWS SNS" }, - { slug: "/mailersend", title: "MailerSend" }, - { slug: "/messagebird", title: "MessageBird" }, - { slug: "/plivo", title: "Plivo" }, - { slug: "/sinch", title: "Sinch" }, - { slug: "/sinch-message-media", title: "Sinch MessageMedia" }, - { slug: "/telnyx", title: "Telnyx" }, - { slug: "/twilio", title: "Twilio" }, - { slug: "/vonage", title: "Vonage" }, - ], - }, - { - title: "Webhook", - slug: "/integrations/webhook", - pages: [{ slug: "/overview", title: "Overview" }], - }, - - { - title: "Extensions", - slug: "/integrations/extensions", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/vercel", title: "Vercel" }, - { slug: "/datadog", title: "Datadog" }, - { slug: "/new-relic", title: "New Relic" }, - { slug: "/segment", title: "Segment" }, - { slug: "/heap", title: "Heap" }, - { slug: "/data-sync", title: "Data warehouse sync" }, - ], - }, -]; +const sidebarContent: SidebarSection[] = integrationSidebarJson; export default sidebarContent; diff --git a/data/sidebar.json b/data/sidebar.json new file mode 100644 index 000000000..465963675 --- /dev/null +++ b/data/sidebar.json @@ -0,0 +1,381 @@ +[ + { + "title": "Getting started", + "slug": "/getting-started", + "desc": "A technical and non-technical introduction to the basics of Knock, and a step-by-step guide to get you going in minutes.", + "pages": [ + { "slug": "/what-is-knock", "title": "What is Knock?" }, + { "slug": "/quick-start", "title": "Quick start" }, + { "slug": "/example-apps", "title": "Example apps" } + ] + }, + { + "title": "Concepts", + "slug": "/concepts", + "desc": "Learn about the key concepts in Knock.", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/workflows", "title": "Workflows" }, + { "slug": "/channels", "title": "Channels" }, + { "slug": "/commits", "title": "Commits" }, + { "slug": "/environments", "title": "Environments" }, + { "slug": "/recipients", "title": "Recipients" }, + { "slug": "/users", "title": "Users" }, + { "slug": "/preferences", "title": "Preferences" }, + { "slug": "/objects", "title": "Objects" }, + { "slug": "/subscriptions", "title": "Subscriptions" }, + { "slug": "/schedules", "title": "Schedules" }, + { "slug": "/tenants", "title": "Tenants" }, + { "slug": "/messages", "title": "Messages" }, + { "slug": "/translations", "title": "Translations" }, + { "slug": "/conditions", "title": "Conditions" }, + { "slug": "/variables", "title": "Variables" }, + { "slug": "/audiences", "title": "Audiences", "isBeta": true } + ] + }, + { + "title": "Designing workflows", + "slug": "/designing-workflows", + "desc": "Learn how to design notifications using Knock's workflow builder, then explore advanced features such as batching, delays, and more.", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/delay-function", "title": "Delay function" }, + { "slug": "/batch-function", "title": "Batch function" }, + { "slug": "/branch-function", "title": "Branch function" }, + { "slug": "/fetch-function", "title": "Fetch function" }, + { "slug": "/throttle-function", "title": "Throttle function" }, + { + "slug": "/trigger-workflow-function", + "title": "Trigger workflow function", + "isBeta": true + }, + { "slug": "/step-conditions", "title": "Step conditions" }, + { "slug": "/channel-step", "title": "Channel steps" }, + { "slug": "/send-windows", "title": "Send windows" }, + { "slug": "/partials", "title": "Partials" }, + { + "title": "Template editor", + "slug": "/template-editor", + "pages": [ + { + "slug": "/overview", + "title": "Overview" + }, + { + "slug": "/variables", + "title": "Variables" + }, + { + "slug": "/referencing-data", + "title": "Referencing data" + }, + { + "slug": "/reference-liquid-helpers", + "title": "Liquid helpers" + } + ] + } + ] + }, + { + "title": "Managing recipients", + "slug": "/managing-recipients", + "desc": "Learn more about how to manage notification recipients with Knock.", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/identifying-recipients", "title": "Identifying recipients" }, + { "slug": "/setting-channel-data", "title": "Setting channel data" }, + { "slug": "/deleting-users", "title": "Deleting users" }, + { "slug": "/merging-users", "title": "Merging users" } + ] + }, + { + "title": "Send notifications", + "slug": "/send-notifications", + "desc": "Learn how to send and debug notifications using Knock.", + "pages": [ + { + "slug": "/triggering-workflows", + "title": "Triggering workflows", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/api", "title": "With the API" }, + { "slug": "/schedules", "title": "On a schedule" }, + { "slug": "/events", "title": "From an event" }, + { "slug": "/audiences", "title": "For an audience", "isBeta": true } + ] + }, + { "slug": "/canceling-workflows", "title": "Canceling workflows" }, + { + "slug": "/delivering-notifications", + "title": "Delivering notifications" + }, + { "slug": "/message-statuses", "title": "Message statuses" }, + { "slug": "/tracking", "title": "Link & open tracking" }, + { "slug": "/testing-workflows", "title": "Testing workflows" }, + { "slug": "/debugging-workflows", "title": "Debugging workflows" } + ] + }, + { + "title": "Preferences", + "slug": "/preferences", + "desc": "Learn how to power notification preferences with Knock.", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/tenant-preferences", "title": "Tenant preferences" }, + { "slug": "/object-preferences", "title": "Object preferences" }, + { "slug": "/preference-conditions", "title": "Preferences conditions" } + ] + }, + { + "title": "Building in-app UI", + "slug": "/in-app-ui", + "desc": "Use the Knock in-app experiences APIs and components to build rich notifications experiences inside of your product.", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { + "slug": "/api-overview", + "title": "API endpoints" + }, + { + "slug": "/security-and-authentication", + "title": "Security & authentication" + }, + { + "slug": "/message-types", + "title": "Message types", + "isBeta": true + }, + { + "title": "React", + "slug": "/react", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/feed", "title": "Notification feed" }, + { + "slug": "/messaging-components", + "title": "Messaging components", + "isBeta": true + }, + { "slug": "/toasts", "title": "Toasts" }, + { "slug": "/inbox", "title": "Notification inbox" }, + { + "slug": "/custom-notifications-ui", + "title": "Custom feed UI (headless)" + }, + { "slug": "/preferences", "title": "Preferences" }, + { "slug": "/slack-kit", "title": "SlackKit" }, + { "slug": "/teams-kit", "title": "TeamsKit" }, + { + "slug": "/filtering-in-app-feeds", + "title": "Filtering feeds" + }, + { + "slug": "/customizing-feed-components", + "title": "Customizing feed components" + } + ] + }, + { + "title": "Javascript", + "slug": "/javascript", + "pages": [{ "slug": "/overview", "title": "Overview" }] + }, + { + "title": "Angular", + "slug": "/angular", + "pages": [{ "slug": "/overview", "title": "Overview" }] + }, + { + "title": "React Native", + "slug": "/react-native", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/components", "title": "Components" }, + { + "slug": "/customization", + "title": "Customization" + }, + { + "slug": "/notification-feeds", + "title": "Custom notifications UI (headless)" + } + ] + }, + { + "title": "iOS (Swift)", + "slug": "/ios", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/components", "title": "Components" }, + { + "slug": "/customization", + "title": "Customization" + } + ] + }, + { + "title": "Android (Kotlin)", + "slug": "/android", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/components", "title": "Components" }, + { + "slug": "/customization", + "title": "Customization" + } + ] + }, + { + "title": "Flutter", + "slug": "/flutter", + "pages": [{ "slug": "/overview", "title": "Overview" }] + } + ] + }, + { + "title": "Developer tools", + "slug": "/developer-tools", + "desc": "Use our powerful developer tools in order to integrate Knock seamlessly into your development workflow.", + "pages": [ + { "slug": "/api-keys", "title": "API keys" }, + { "slug": "/service-tokens", "title": "Service tokens" }, + { "slug": "/knock-cli", "title": "Knock CLI" }, + { "slug": "/management-api", "title": "Management API" }, + { "slug": "/api-logs", "title": "API logs" }, + { "slug": "/knock-and-postman", "title": "Knock and Postman" }, + { "slug": "/security", "title": "Security" }, + { "slug": "/integrating-into-cicd", "title": "Integrating into CI/CD" }, + { + "slug": "/outbound-webhooks", + "title": "Outbound webhooks", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/event-types", "title": "Event types" } + ] + }, + { "slug": "/validating-trigger-data", "title": "Validating trigger data" } + ] + }, + { + "title": "SDKs", + "slug": "/sdks", + "desc": "", + "pages": [ + { + "title": "Overview", + "slug": "/overview" + }, + { + "title": "React (Web)", + "slug": "/react", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/reference", "title": "API reference" } + ] + }, + { + "title": "Javascript (Web)", + "slug": "/javascript", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/quick-start", "title": "Quick start" }, + { "slug": "/reference", "title": "API reference" } + ] + }, + { + "title": "iOS (Swift)", + "slug": "/ios", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/quick-start", "title": "Quick start" }, + { "slug": "/push-notifications", "title": "Push notifications" }, + { "slug": "/deep-links", "title": "Deep/universal links" }, + { "slug": "/reference", "title": "API reference" } + ] + }, + { + "title": "Android (Kotlin)", + "slug": "/android", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/quick-start", "title": "Quick start" }, + { "slug": "/push-notifications", "title": "Push notifications" }, + { "slug": "/deep-links", "title": "Deep links" }, + { "slug": "/reference", "title": "API reference" } + ] + }, + { + "title": "Flutter", + "slug": "/flutter", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/quick-start", "title": "Quick start" }, + { "slug": "/reference", "title": "API reference" } + ] + }, + { + "title": "React Native", + "slug": "/react-native", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/quick-start", "title": "Quick start" }, + { "slug": "/push-notifications", "title": "Push notifications" }, + { "slug": "/reference", "title": "API reference" } + ] + }, + { + "title": "Expo", + "slug": "/expo", + "pages": [ + { "slug": "/overview", "title": "Overview" }, + { "slug": "/push-notifications", "title": "Push notifications" }, + { "slug": "/reference", "title": "API reference" } + ] + } + ] + }, + { + "title": "Manage your account", + "slug": "/manage-your-account", + "desc": "Learn more about the tools available in managing your Knock account.", + "pages": [ + { "slug": "/authentication-methods", "title": "Authentication methods" }, + { "slug": "/saml-sso", "title": "SAML SSO" }, + { "slug": "/directory-sync", "title": "Directory sync (SCIM)" }, + { "slug": "/managing-members", "title": "Managing members" }, + { "slug": "/roles-and-permissions", "title": "Roles and permissions" }, + { "slug": "/audit-logs", "title": "Audit logs" }, + { "slug": "/data-obfuscation", "title": "Data obfuscation" }, + { "slug": "/account-timezone", "title": "Account timezone" }, + { "slug": "/data-retention", "title": "Data retention" } + ] + }, + { + "title": "Guides", + "slug": "/guides", + "pages": [ + { + "slug": "/implementation-guide", + "title": "Knock implementation guide" + }, + { + "slug": "/alerting", + "title": "Alerting" + }, + { + "slug": "/customer-webhooks", + "title": "Customer-facing webhooks" + }, + { + "slug": "/building-recurring-digests", + "title": "Recurring digests" + }, + { "slug": "/migrate-from-courier", "title": "Migrate from Courier" }, + { + "slug": "/modeling-users-objects-and-tenants", + "title": "Modeling Users, Objects, and Tenants" + } + ] + } +] diff --git a/data/sidebar.ts b/data/sidebar.ts index 85b199c20..6f6d45349 100644 --- a/data/sidebar.ts +++ b/data/sidebar.ts @@ -1,385 +1,6 @@ import { SidebarSection } from "./types"; +import sidebarJson from "./sidebar.json"; -const sidebarContent: SidebarSection[] = [ - { - title: "Getting started", - slug: "/getting-started", - desc: "A technical and non-technical introduction to the basics of Knock, and a step-by-step guide to get you going in minutes.", - pages: [ - { slug: "/what-is-knock", title: "What is Knock?" }, - { slug: "/quick-start", title: "Quick start" }, - { slug: "/example-apps", title: "Example apps" }, - ], - }, - { - title: "Concepts", - slug: "/concepts", - desc: "Learn about the key concepts in Knock.", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/workflows", title: "Workflows" }, - { slug: "/channels", title: "Channels" }, - { slug: "/commits", title: "Commits" }, - { slug: "/environments", title: "Environments" }, - { slug: "/recipients", title: "Recipients" }, - { slug: "/users", title: "Users" }, - { slug: "/preferences", title: "Preferences" }, - { slug: "/objects", title: "Objects" }, - { slug: "/subscriptions", title: "Subscriptions" }, - { slug: "/schedules", title: "Schedules" }, - { slug: "/tenants", title: "Tenants" }, - { slug: "/messages", title: "Messages" }, - { slug: "/translations", title: "Translations" }, - { slug: "/conditions", title: "Conditions" }, - { slug: "/variables", title: "Variables" }, - { slug: "/audiences", title: "Audiences", isBeta: true }, - ], - }, - { - title: "Designing workflows", - slug: "/designing-workflows", - desc: "Learn how to design notifications using Knock's workflow builder, then explore advanced features such as batching, delays, and more.", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/delay-function", title: "Delay function" }, - { slug: "/batch-function", title: "Batch function" }, - { slug: "/branch-function", title: "Branch function" }, - { slug: "/fetch-function", title: "Fetch function" }, - { slug: "/throttle-function", title: "Throttle function" }, - { - slug: "/trigger-workflow-function", - title: "Trigger workflow function", - isBeta: true, - }, - { slug: "/step-conditions", title: "Step conditions" }, - { slug: "/channel-step", title: "Channel steps" }, - { slug: "/send-windows", title: "Send windows" }, - { slug: "/partials", title: "Partials" }, - { - title: "Template editor", - slug: "/template-editor", - pages: [ - { - slug: "/overview", - title: "Overview", - }, - { - slug: "/variables", - title: "Variables", - }, - { - slug: "/referencing-data", - title: "Referencing data", - }, - { - slug: "/reference-liquid-helpers", - title: "Liquid helpers", - }, - ], - }, - ], - }, - { - title: "Managing recipients", - slug: "/managing-recipients", - desc: "Learn more about how to manage notification recipients with Knock.", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/identifying-recipients", title: "Identifying recipients" }, - { slug: "/setting-channel-data", title: "Setting channel data" }, - { slug: "/deleting-users", title: "Deleting users" }, - { slug: "/merging-users", title: "Merging users" }, - ], - }, - { - title: "Send notifications", - slug: "/send-notifications", - desc: "Learn how to send and debug notifications using Knock.", - pages: [ - { - slug: "/triggering-workflows", - title: "Triggering workflows", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/api", title: "With the API" }, - { slug: "/schedules", title: "On a schedule" }, - { slug: "/events", title: "From an event" }, - { slug: "/audiences", title: "For an audience", isBeta: true }, - ], - }, - { slug: "/canceling-workflows", title: "Canceling workflows" }, - { slug: "/delivering-notifications", title: "Delivering notifications" }, - { slug: "/message-statuses", title: "Message statuses" }, - { slug: "/tracking", title: "Link & open tracking" }, - { slug: "/testing-workflows", title: "Testing workflows" }, - { slug: "/debugging-workflows", title: "Debugging workflows" }, - ], - }, - { - title: "Preferences", - slug: "/preferences", - desc: "Learn how to power notification preferences with Knock.", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/tenant-preferences", title: "Tenant preferences" }, - { slug: "/object-preferences", title: "Object preferences" }, - { slug: "/preference-conditions", title: "Preferences conditions" }, - ], - }, - { - title: "Building in-app UI", - slug: "/in-app-ui", - desc: "Use the Knock in-app experiences APIs and components to build rich notifications experiences inside of your product.", - pages: [ - { slug: "/overview", title: "Overview" }, - { - slug: "/api-overview", - title: "API endpoints", - }, - { - slug: "/security-and-authentication", - title: "Security & authentication", - }, - { - slug: "/message-types", - title: "Message types", - isBeta: true, - }, - { - title: "React", - slug: "/react", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/feed", title: "Notification feed" }, - { - slug: "/messaging-components", - title: "Messaging components", - isBeta: true, - }, - { slug: "/toasts", title: "Toasts" }, - { slug: "/inbox", title: "Notification inbox" }, - { - slug: "/custom-notifications-ui", - title: "Custom feed UI (headless)", - }, - { slug: "/preferences", title: "Preferences" }, - { slug: "/slack-kit", title: "SlackKit" }, - { slug: "/teams-kit", title: "TeamsKit" }, - { - slug: "/filtering-in-app-feeds", - title: "Filtering feeds", - }, - { - slug: "/customizing-feed-components", - title: "Customizing feed components", - }, - ], - }, - { - title: "Javascript", - slug: "/javascript", - pages: [{ slug: "/overview", title: "Overview" }], - }, - { - title: "Angular", - slug: "/angular", - pages: [{ slug: "/overview", title: "Overview" }], - }, - { - title: "React Native", - slug: "/react-native", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/components", title: "Components" }, - { - slug: "/customization", - title: "Customization", - }, - { - slug: "/notification-feeds", - title: "Custom notifications UI (headless)", - }, - ], - }, - { - title: "iOS (Swift)", - slug: "/ios", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/components", title: "Components" }, - { - slug: "/customization", - title: "Customization", - }, - ], - }, - { - title: "Android (Kotlin)", - slug: "/android", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/components", title: "Components" }, - { - slug: "/customization", - title: "Customization", - }, - ], - }, - { - title: "Flutter", - slug: "/flutter", - pages: [{ slug: "/overview", title: "Overview" }], - }, - ], - }, - { - title: "Developer tools", - slug: "/developer-tools", - desc: "Use our powerful developer tools in order to integrate Knock seamlessly into your development workflow.", - pages: [ - { slug: "/api-keys", title: "API keys" }, - { slug: "/service-tokens", title: "Service tokens" }, - { slug: "/knock-cli", title: "Knock CLI" }, - { slug: "/management-api", title: "Management API" }, - { slug: "/api-logs", title: "API logs" }, - { slug: "/knock-and-postman", title: "Knock and Postman" }, - { slug: "/security", title: "Security" }, - { slug: "/integrating-into-cicd", title: "Integrating into CI/CD" }, - { - slug: "/outbound-webhooks", - title: "Outbound webhooks", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/event-types", title: "Event types" }, - ], - }, - { slug: "/validating-trigger-data", title: "Validating trigger data" }, - ], - }, - - { - title: "SDKs", - slug: "/sdks", - desc: "", - pages: [ - { - title: "Overview", - slug: "/overview", - }, - { - title: "React (Web)", - slug: "/react", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/reference", title: "API reference" }, - ], - }, - { - title: "Javascript (Web)", - slug: "/javascript", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/quick-start", title: "Quick start" }, - { slug: "/reference", title: "API reference" }, - ], - }, - { - title: "iOS (Swift)", - slug: "/ios", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/quick-start", title: "Quick start" }, - { slug: "/push-notifications", title: "Push notifications" }, - { slug: "/deep-links", title: "Deep/universal links" }, - { slug: "/reference", title: "API reference" }, - ], - }, - { - title: "Android (Kotlin)", - slug: "/android", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/quick-start", title: "Quick start" }, - { slug: "/push-notifications", title: "Push notifications" }, - { slug: "/deep-links", title: "Deep links" }, - { slug: "/reference", title: "API reference" }, - ], - }, - { - title: "Flutter", - slug: "/flutter", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/quick-start", title: "Quick start" }, - { slug: "/reference", title: "API reference" }, - ], - }, - { - title: "React Native", - slug: "/react-native", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/quick-start", title: "Quick start" }, - { slug: "/push-notifications", title: "Push notifications" }, - { slug: "/reference", title: "API reference" }, - ], - }, - { - title: "Expo", - slug: "/expo", - pages: [ - { slug: "/overview", title: "Overview" }, - { slug: "/push-notifications", title: "Push notifications" }, - { slug: "/reference", title: "API reference" }, - ], - }, - ], - }, - - { - title: "Manage your account", - slug: "/manage-your-account", - desc: "Learn more about the tools available in managing your Knock account.", - pages: [ - { slug: "/authentication-methods", title: "Authentication methods" }, - { slug: "/saml-sso", title: "SAML SSO" }, - { slug: "/directory-sync", title: "Directory sync (SCIM)" }, - { slug: "/managing-members", title: "Managing members" }, - { slug: "/roles-and-permissions", title: "Roles and permissions" }, - { slug: "/audit-logs", title: "Audit logs" }, - { slug: "/data-obfuscation", title: "Data obfuscation" }, - { slug: "/account-timezone", title: "Account timezone" }, - { slug: "/data-retention", title: "Data retention" }, - ], - }, - - { - title: "Guides", - slug: "/guides", - pages: [ - { - slug: "/implementation-guide", - title: "Knock implementation guide", - }, - { - slug: "/alerting", - title: "Alerting", - }, - { - slug: "/customer-webhooks", - title: "Customer-facing webhooks", - }, - { - slug: "/building-recurring-digests", - title: "Recurring digests", - }, - { slug: "/migrate-from-courier", title: "Migrate from Courier" }, - { - slug: "/modeling-users-objects-and-tenants", - title: "Modeling Users, Objects, and Tenants", - }, - ], - }, -]; +const sidebarContent: SidebarSection[] = sidebarJson; export default sidebarContent; diff --git a/package.json b/package.json index 0c2862ee1..cf18c5090 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,10 @@ "type-check": "tsc", "format": "prettier \"**/*.+(ts|js|tsx|mdx|md)\"", "format.write": "yarn run format --write", - "format.check": "yarn run format --check" + "format.check": "yarn run format --check", + "generate-llms": "node scripts/generateLlmsTxt.mjs", + "predev": "yarn generate-llms", + "prebuild": "yarn generate-llms" }, "dependencies": { "@algolia/autocomplete-js": "^1.6.3", @@ -49,8 +52,12 @@ "react-syntax-highlighter": "^15.4.3", "react-use-clipboard": "1.0.7", "rehype-mdx-code-props": "^2.0.0", + "remark-frontmatter": "^5.0.0", "remark-gfm": "3.0.1", - "tailwindcss-radix": "^2.5.0" + "remark-parse": "^11.0.0", + "tailwindcss-radix": "^2.5.0", + "unified": "^11.0.5", + "yaml": "^2.7.0" }, "devDependencies": { "@types/gtag.js": "^0.0.5", @@ -66,6 +73,7 @@ "rehype-autolink-headings": "^7.0.0", "remark-slug": "^6.0.0", "tailwindcss": "^3.3.3", + "ts-node": "^10.9.2", "typescript": "^5.2.2" } } diff --git a/pages/[...slug].tsx b/pages/[...slug].tsx index 34295f36a..d4ded4d0e 100644 --- a/pages/[...slug].tsx +++ b/pages/[...slug].tsx @@ -117,8 +117,8 @@ export async function getStaticProps({ params: { slug } }) { const mdxSource = await serialize<{}, FrontMatter>(source, { parseFrontmatter: true, mdxOptions: { - remarkPlugins: [remarkSlug, remarkGfm], - rehypePlugins: [rehypeMdxCodeProps, rehypeAutolinkHeadings] as any, + remarkPlugins: [[remarkSlug], [remarkGfm]] as any[], + rehypePlugins: [rehypeMdxCodeProps, rehypeAutolinkHeadings] as any[], }, }); diff --git a/scripts/generateLlmsTxt.mjs b/scripts/generateLlmsTxt.mjs new file mode 100644 index 000000000..c917cf774 --- /dev/null +++ b/scripts/generateLlmsTxt.mjs @@ -0,0 +1,191 @@ +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +import { dirname } from "path"; +import { unified } from "unified"; +import remarkParse from "remark-parse"; +import remarkFrontmatter from "remark-frontmatter"; +import yaml from "yaml"; +import sidebarContent from "../data/sidebar.json" assert { type: "json" }; +import integrationSidebarContent from "../data/integrationsSidebar.json" assert { type: "json" }; + +const apiContent = [ + { + title: "API Reference", + slug: "", + desc: "Complete reference documentation for the Knock API.", + pages: [ + { slug: "/reference", title: "API Reference" }, + { slug: "/cli", title: "CLI Reference" }, + { slug: "/mapi", title: "Management API Reference" }, + ], + }, +]; +// Get current file's directory (ESM equivalent of __dirname) +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// Utility functions +async function parseFrontmatter(markdownContent) { + const file = await unified() + .use(remarkParse) + .use(remarkFrontmatter, ["yaml"]) + .parse(markdownContent); + + const yamlNode = file.children.find((node) => node.type === "yaml"); + if (!yamlNode) return null; + return yaml.parse(yamlNode.value); +} + +async function writePublicMarkdown(slug, content) { + try { + const publicPath = path.join( + process.cwd(), + "public", + `${slug.slice(1)}.md`, + ); + // Create directories if they don't exist + fs.mkdirSync(path.dirname(publicPath), { recursive: true }); + fs.writeFileSync(publicPath, content, "utf-8"); + } catch (error) { + console.warn(`Warning: Could not write public markdown for ${slug}`, error); + } +} + +async function getMarkdownContent(slug) { + try { + const markdownPath = path.join( + process.cwd(), + "content", + `${slug.slice(1)}.mdx`, + ); + + if (fs.existsSync(markdownPath)) { + const content = fs.readFileSync(markdownPath, "utf-8"); + const frontmatter = await parseFrontmatter(content); + return { + description: frontmatter?.description || "", + fullContent: content, + }; + } + } catch (error) { + console.warn(`Warning: Could not load content for ${slug}`); + } + return { description: "", fullContent: "" }; +} + +// Process pages and generate both index and full content +async function processPages( + pages, + parentSlug, + indexContent, + fullContent, + indentLevel = 0, +) { + for (const page of pages) { + const fullHref = `${parentSlug}${page.slug}`; + const { description, fullContent: pageContent } = await getMarkdownContent( + fullHref, + ); + const indent = " ".repeat(indentLevel); + const betaTag = page.isBeta ? " (Beta)" : ""; + const descriptionText = description ? `: ${description}` : ""; + + // Add to index content with .md extension + indexContent.push( + `${indent}- [${page.title}${betaTag}](${fullHref}.md)${descriptionText}`, + ); + + // Add to full content + fullContent.push(`## ${page.title}${betaTag}`); + if (description) fullContent.push(description); + if (pageContent) { + fullContent.push(pageContent); + // Write to public directory if we have content + await writePublicMarkdown(fullHref, pageContent); + } + fullContent.push(""); // Empty line for spacing + + // Process nested pages + if (page.pages) { + await processPages( + page.pages, + fullHref, + indexContent, + fullContent, + indentLevel + 1, + ); + } + } +} + +async function processSections(sections, indexContent, fullContent) { + for (const section of sections) { + // Add section to index + indexContent.push(`## ${section.title}`); + if (section.desc) { + indexContent.push(section.desc); + } + indexContent.push(""); + + // Add section to full content + fullContent.push(`# ${section.title}`); + if (section.desc) { + fullContent.push(section.desc); + } + fullContent.push(""); + + // Process all pages in the section + await processPages(section.pages, section.slug, indexContent, fullContent); + indexContent.push(""); // Extra newline between sections + fullContent.push(""); // Extra newline between sections + } +} + +async function generateAllLlmsFiles() { + try { + const publicDir = path.join(process.cwd(), "public"); + if (!fs.existsSync(publicDir)) { + fs.mkdirSync(publicDir, { recursive: true }); + } + + // Initialize content arrays + const indexContent = ["# Knock Documentation\n"]; + const fullContent = ["# Knock Documentation\n"]; + + // Process main sidebar content + await processSections(sidebarContent, indexContent, fullContent); + + // Add divider before integrations + indexContent.push("---\n"); + fullContent.push("---\n"); + + // Process integration sidebar content + await processSections(integrationSidebarContent, indexContent, fullContent); + // Process API content + await processSections(apiContent, indexContent, fullContent); + // Write files + fs.writeFileSync( + path.join(publicDir, "llms.txt"), + indexContent.join("\n"), + "utf-8", + ); + fs.writeFileSync( + path.join(publicDir, "llms-full.txt"), + fullContent.join("\n"), + "utf-8", + ); + + console.log("✅ All LLMS files generated successfully"); + } catch (error) { + console.error("Error generating LLMS files:", error); + process.exit(1); + } +} + +// Run if this is the main module +if (import.meta.url === `file://${process.argv[1]}`) { + generateAllLlmsFiles().catch(console.error); +} + +export { generateAllLlmsFiles }; diff --git a/yarn.lock b/yarn.lock index 44b0f814b..c09f2fb3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4728,6 +4728,13 @@ fault@^1.0.0: dependencies: format "^0.2.0" +fault@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fault/-/fault-2.0.1.tgz#d47ca9f37ca26e4bd38374a7c500b5a384755b6c" + integrity sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ== + dependencies: + format "^0.2.0" + fflate@^0.7.3: version "0.7.4" resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.7.4.tgz#61587e5d958fdabb5a9368a302c25363f4f69f50" @@ -6225,6 +6232,18 @@ mdast-util-from-markdown@^2.0.0: micromark-util-types "^2.0.0" unist-util-stringify-position "^4.0.0" +mdast-util-frontmatter@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz#f5f929eb1eb36c8a7737475c7eb438261f964ee8" + integrity sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + escape-string-regexp "^5.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + micromark-extension-frontmatter "^2.0.0" + mdast-util-gfm-autolink-literal@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz#67a13abe813d7eba350453a5333ae1bc0ec05c06" @@ -6535,6 +6554,16 @@ micromark-core-commonmark@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" +micromark-extension-frontmatter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz#651c52ffa5d7a8eeed687c513cd869885882d67a" + integrity sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg== + dependencies: + fault "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-gfm-autolink-literal@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz#5853f0e579bbd8ef9e39a7c0f0f27c5a063a66e7" @@ -8160,6 +8189,16 @@ rehype-raw@^6.1.1: hast-util-raw "^7.2.0" unified "^10.0.0" +remark-frontmatter@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz#b68d61552a421ec412c76f4f66c344627dc187a2" + integrity sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-frontmatter "^2.0.0" + micromark-extension-frontmatter "^2.0.0" + unified "^11.0.0" + remark-gfm@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f" @@ -8187,6 +8226,16 @@ remark-parse@^10.0.0: mdast-util-from-markdown "^1.0.0" unified "^10.0.0" +remark-parse@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1" + integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + micromark-util-types "^2.0.0" + unified "^11.0.0" + remark-rehype@^10.0.0: version "10.1.0" resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" @@ -8858,6 +8907,25 @@ ts-node@^10.8.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + ts-pattern@5.0.5: version "5.0.5" resolved "https://registry.yarnpkg.com/ts-pattern/-/ts-pattern-5.0.5.tgz#20f82d50ea56c1d9cd1aa772911f7bb545d9607d" @@ -9016,6 +9084,19 @@ unified@^11.0.0: trough "^2.0.0" vfile "^6.0.0" +unified@^11.0.5: + version "11.0.5" + resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1" + integrity sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA== + dependencies: + "@types/unist" "^3.0.0" + bail "^2.0.0" + devlop "^1.0.0" + extend "^3.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^6.0.0" + unist-util-generated@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae" @@ -9447,6 +9528,11 @@ yaml@^2.1.1: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.3.tgz#01f6d18ef036446340007db8e016810e5d64aad9" integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ== +yaml@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.0.tgz#aef9bb617a64c937a9a748803786ad8d3ffe1e98" + integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"