diff --git a/pages/404.tsx b/pages/404.tsx
index ee6cac141..bd4835800 100644
--- a/pages/404.tsx
+++ b/pages/404.tsx
@@ -13,17 +13,24 @@ const REPLACE_PATHNAME = "%%PATHNAME%%";
export async function getStaticProps() {
// Matches mdx/rehyppe.mjs
const highlighter = await shiki.getHighlighter({ theme: "css-variables" });
- const shikiTokens = await highlighter.codeToThemedTokens(
- getCode({ pathname: REPLACE_PATHNAME }),
- "typescript"
- );
- const shikiCodeHtml = shiki.renderToHtml(shikiTokens, {
- elements: {
- pre: ({ children }) => children,
- code: ({ children }) => children,
- line: ({ children }) => `${children}`,
- },
- });
+ // This can fail locally
+ let shikiCodeHtml = "";
+ try {
+ const shikiTokens = await highlighter.codeToThemedTokens(
+ getCode({ pathname: REPLACE_PATHNAME }),
+ "typescript"
+ );
+ shikiCodeHtml = shiki.renderToHtml(shikiTokens, {
+ elements: {
+ pre: ({ children }) => children,
+ code: ({ children }) => children,
+ line: ({ children }) => `${children}`,
+ },
+ });
+ } catch (e) {
+ // If it fails, just leave it blank
+ }
+
return {
props: {
designVersion: "2",
@@ -52,6 +59,9 @@ export default function Custom404({ shikiCodeHtml }) {
const pathname = router.asPath;
const isDocs = pathname.match(/^\/docs/);
+ // For debugging
+ // console.log("404 - Page not found: ", pathname);
+
const title = `404 - Page not found`;
const lede = `We've triggered an event and a serverless function is forwarding it to the team as you read this.`;
diff --git a/pages/docs/guides/index.mdx b/pages/docs/guides/index.mdx
index 170437977..4075c8ca9 100644
--- a/pages/docs/guides/index.mdx
+++ b/pages/docs/guides/index.mdx
@@ -1,5 +1,59 @@
+import { ResourceGrid, Resource } from 'src/shared/Docs/Resources'
+
# Guides
-Dive into advanced uses for Inngest with our guides:
+Learn how to build with Inngest:
+
+## Patterns
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-- [Trigger your code directly from Retool](/docs/guides/trigger-your-code-from-retool)
\ No newline at end of file
+
\ No newline at end of file
diff --git a/pages/docs/index.mdx b/pages/docs/index.mdx
index 5eb131caa..05ffc454d 100644
--- a/pages/docs/index.mdx
+++ b/pages/docs/index.mdx
@@ -1,99 +1,94 @@
+import { CodeBracketSquareIcon } from "@heroicons/react/20/solid"
+import { Home } from 'src/shared/Docs/Home'
import { Guides } from 'src/shared/Docs/Guides'
-import { Resources } from 'src/shared/Docs/Resources'
+import { ResourceGrid, Resource } from 'src/shared/Docs/Resources'
+import { GuideGrid, Guide } from 'src/shared/Docs/Guides'
import { HeroPattern } from 'src/shared/Docs/HeroPattern'
+import EventIcon from 'src/shared/Icons/Event'
+import StepsIcon from 'src/shared/Icons/Steps'
export const pageTitle = 'Inngest Documentation & Guides'
export const description =
'Learn how to use Inngest to deploy reliable background functions to any platform.'
-{/*export const sections = [
- { title: 'Guides', id: 'guides' },
- { title: 'Resources', id: 'resources' },
-]*/}
+{/* TODO - Add cool header graphic*/}
-# Introduction to Inngest
+
-Inngest is an open source platform that adds superpowers to serverless functions. {{ className: 'lead' }}
+## Getting Started
-Using our SDK, a single line of code adds retries, queues, sleeps, cron schedules, fan-out jobs, and reliable steps to serverless functions in your existing projects. It's deployable to any platform, without any infrastructure or configuration. And, everything is locally testable via our UI.
-
-Learn how to get started:
+Discover how to get set up with Inngest in just a few minutes:
-
- {/* */}
+
-## A small but powerful example {{ anchor: false }}
-
-Adding sleeps, retries, and reliable steps to a function:
-
-
-```ts
-import { EventSchemas, Inngest } from "inngest";
-
-type Events = {
- "user/new.signup": {
- data: {
- email: string;
- name: string;
- };
- };
-};
-
-const inngest = new Inngest({
- id: "nextjs-shop",
- schemas: new EventSchemas().fromRecord(),
-});
-
-export default inngest.createFunction(
- { id: "signup-flow" }, // Function options
- { event: "user/new.signup" }, // One or more events that trigger this function
- async ({ event, step }) => {
- // ⚡ If this step fails it will retry automatically. It will only run once
- // if it succeeds
- const promo = await step.run("generate-promo-code", async () => {
- const promoCode = await generatePromoCode();
- return promoCode.code;
- });
-
- // ⚡ Again, if the email provider is down this will retry - but we will
- // only generate one promo code
- await step.run("send-a-welcome-promo", () =>
- sendEmail({ email: event.data, promo })
- );
-
- // 😴 You can sleep on any platform!
- await step.sleep("wait-before-followup", "1 day");
-
- // ⏰ This runs exactly 1 day after the user signs up
- await step.run("send-drip-campaign", () => sendDripCampaign());
- }
-);
-```
-
-
-In this example, you can reliably run serverless functions even if external APIs are down. You can also sleep or delay work without configuring queues. Plus, all events, jobs, and functions are strictly typed via TypeScript for maximum correctness.
-Here's how things look when you run locally:
-
-
-
-
-### Comparisons
-
-Without Inngest, you would have to configure several jobs amongst several different queues, then handle retries yourself. There's also a chance that many promo codes are generated depending on the reliability of that API. With Inngest, you can push this function live and everything happens automatically.
-
-{/*
-
- */}
-
-
-### Resources and help
-
-If you have any questions we're always around in our [Discord community](https://www.inngest.com/discord) or on [GitHub](https://github.com/inngest/inngest).
+## Introduction to Inngest
+
+Inngest as a durable workflow engine that enables you to run reliable code on any platform, including serverless.
+
+With any Inngest SDK, you write **Functions** in your codebase and make them available to Inngest using an HTTP endpoint. Functions are triggered by **Events** which can be sent with our SDKs, via a regular POST request, or can come from an external source such as webhooks.
+
+Functions are composed of **Steps**, which decouple parts of your functions into individually retriable blocks. Steps enable yuo to write complex, durable, long-lived workflows, _event on serverless_, in a single function.
+
+## Guides
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Support
+
+If you need help with Inngest, you can reach out to us in the following ways:
+
+* [Open a ticket in our support center](https://app.inngest.com/support)
+* [Ask your questions in our Discord community](/discord)
+* [Contact our sales engineering team](/contact?ref=docs)
diff --git a/pages/docs/platform/index.mdx b/pages/docs/platform/index.mdx
new file mode 100644
index 000000000..2a40dd9e6
--- /dev/null
+++ b/pages/docs/platform/index.mdx
@@ -0,0 +1,27 @@
+import { GuideGrid, Guide } from 'src/shared/Docs/Guides'
+
+# Platform Guides
+
+Learn how to use the Inngest platform
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/docs/reference/python/index.mdx b/pages/docs/reference/python/index.mdx
new file mode 100644
index 000000000..d426afaf3
--- /dev/null
+++ b/pages/docs/reference/python/index.mdx
@@ -0,0 +1,7 @@
+import GithubIcon from "shared/Icons/Github"
+
+# Python SDK
+
+_Docs coming soon!_ For now, check out the Github repo README for basic info: [ inngest/inngest-py](https://github.com/inngest/inngest-py).
+
+During the beta phase, please share feedback or report issues on [Discord](https://www.inngest.com/discord) or [Github](https://github.com/inngest/inngest-py/issues)
\ No newline at end of file
diff --git a/pages/docs/reference/rest-api/index.mdx b/pages/docs/reference/rest-api/index.mdx
new file mode 100644
index 000000000..da650f35c
--- /dev/null
+++ b/pages/docs/reference/rest-api/index.mdx
@@ -0,0 +1,5 @@
+# REST API
+
+Our API is currently in development. We will be releasing new endpoints as they are ready.
+
+If you have any feedback or suggestions, please send it via [the form on our roadmap here](https://roadmap.inngest.com/).
\ No newline at end of file
diff --git a/pages/docs/reference/typescript/index.mdx b/pages/docs/reference/typescript/index.mdx
new file mode 100644
index 000000000..a15d05e1a
--- /dev/null
+++ b/pages/docs/reference/typescript/index.mdx
@@ -0,0 +1,24 @@
+import GithubIcon from "shared/Icons/Github"
+
+# TypeScript SDK
+
+## Installing
+
+
+```shell {{ title: "npm" }}
+npm install inngest
+```
+```shell {{ title: "pnpm" }}
+pnpm add inngest
+```
+```shell {{ title: "yarn" }}
+yarn add inngest
+```
+
+
+## Source code
+
+Our TypeScript SDK is open source and available on Github: [ inngest/inngest-js](https://github.com/inngest/inngest-js).
+
+
+{/* example repos */}
\ No newline at end of file
diff --git a/pages/docs/sdk/overview.mdx b/pages/docs/sdk/overview.mdx
index 6e5c65728..54af57949 100644
--- a/pages/docs/sdk/overview.mdx
+++ b/pages/docs/sdk/overview.mdx
@@ -1,6 +1,6 @@
-# SDK Overview
+# Installing the SDK
-The Inngest SDK allows you to write reliable, durable functions in your existing projects incrementally. Functions can be automatically triggered by events or run on a schedule without infrastructure, and can be fully serverless or added to your existing HTTP server.
+The Inngest SDK allows you to write reliable, durable functions in your existing projects incrementally. Functions can be automatically triggered by events or run on a schedule without infrastructure, and can be fully serverless or added to your existing HTTP server.
- It works with any framework and platform by using HTTP to call your functions
- It supports serverless providers, without any additional infrastructure
@@ -9,23 +9,22 @@ The Inngest SDK allows you to write reliable, durable functions in your existing
## Getting started
-To get started, install the SDK via npm or Yarn:
+To get started, install the SDK via your favorite package manager:
-```bash
-npm install inngest # or yarn add inngest
+
+```shell {{ title: "npm" }}
+npm install inngest
```
+```shell {{ title: "pnpm" }}
+pnpm add inngest
+```
+```shell {{ title: "yarn" }}
+yarn add inngest
+```
+
-You’ll need to do a few things to get set up, which will only take a few minutes.
+You'll need to do a few things to get set up, which will only take a few minutes.
-1. [Set up and serve the Inngest API](/docs/sdk/serve)
+1. [Set up and serve the Inngest API for your framework](/docs/sdk/serve)
2. [Define and write your functions](/docs/functions)
-3. [Trigger functions with events](/docs/events)
-
-<>
-{/*
-TODO:
-You can skip straight to serving the Inngest API, or read on to learn how the SDK works.
-
-## How the SDK works
-*/}
->
+3. [Trigger functions with events](/docs/events)
\ No newline at end of file
diff --git a/public/assets/textures/wave-gray.svg b/public/assets/textures/wave-gray.svg
new file mode 100644
index 000000000..88f46221f
--- /dev/null
+++ b/public/assets/textures/wave-gray.svg
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/shared/Docs/Footer.tsx b/shared/Docs/Footer.tsx
index 530de3a63..fd703534e 100644
--- a/shared/Docs/Footer.tsx
+++ b/shared/Docs/Footer.tsx
@@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import { Transition } from "@headlessui/react";
import { Button } from "../Button";
-import { navigation } from "./Navigation";
+import { topLevelNav } from "./navigationStructure";
import SocialBadges from "./SocialBadges";
function CheckIcon(props) {
@@ -131,9 +131,19 @@ function PageLink({ label, page, previous = false }) {
);
}
+function flattenNav(nav) {
+ return nav.flatMap((group) => {
+ return group.sectionLinks
+ ? flattenNav(group.sectionLinks)
+ : group.links
+ ? flattenNav(group.links)
+ : group;
+ });
+}
+
function PageNavigation() {
let router = useRouter();
- let allPages = navigation.flatMap((group) => group.links);
+ let allPages = flattenNav(topLevelNav);
let currentPageIndex = allPages.findIndex(
(page) => page.href === router.pathname
);
@@ -145,6 +155,11 @@ function PageNavigation() {
let previousPage = allPages[currentPageIndex - 1];
let nextPage = allPages[currentPageIndex + 1];
+ // Skip next page if it's an external link
+ if (!nextPage?.href.match(/^\//)) {
+ nextPage = null;
+ }
+
if (!previousPage && !nextPage) {
return null;
}
diff --git a/shared/Docs/Guides.tsx b/shared/Docs/Guides.tsx
index 43cb887e1..5092a9fab 100644
--- a/shared/Docs/Guides.tsx
+++ b/shared/Docs/Guides.tsx
@@ -26,29 +26,50 @@ const guides = [
},
];
+export function Guide(guide: {
+ href: string;
+ name: string;
+ description: string;
+}) {
+ return (
+
+
+ {guide.name}
+
+
+ {guide.description}
+
+
+
+
+
+ );
+}
+
+export function GuideGrid({ cols = 4, children }) {
+ return (
+
+ {children}
+
+ );
+}
+
export function Guides() {
return (
Guides
-
+
{guides.map((guide) => (
-
-
- {guide.name}
-
-
- {guide.description}
-
-
-
-
-
+
))}
-
+
);
}
diff --git a/shared/Docs/Home.tsx b/shared/Docs/Home.tsx
new file mode 100644
index 000000000..bc2974a74
--- /dev/null
+++ b/shared/Docs/Home.tsx
@@ -0,0 +1,14 @@
+import Link from "next/link";
+import { BoltIcon } from "@heroicons/react/24/outline";
+import Logo from "../Icons/Logo";
+
+export function Home() {
+ return (
+
+
Inngest Documentation
+
+ Learn how to build with Inngest's durable workflow engine.
+
+
+ );
+}
diff --git a/shared/Docs/Layout.tsx b/shared/Docs/Layout.tsx
index 4e69f0e24..9e2251964 100644
--- a/shared/Docs/Layout.tsx
+++ b/shared/Docs/Layout.tsx
@@ -6,6 +6,7 @@ import { motion } from "framer-motion";
import * as mdxComponents from "src/shared/Docs/mdx";
import { Footer } from "./Footer";
+import { Home } from "./Home";
import { Header } from "./Header";
import Logo from "../Icons/Logo";
import { Navigation } from "./Navigation";
@@ -48,6 +49,7 @@ export function Layout({
const metaDescription =
description || `Inngest documentation for ${preferredTitle}`;
const metaImage = getOpenGraphImageURL({ title: preferredTitle });
+
return (
diff --git a/shared/Docs/Navigation.tsx b/shared/Docs/Navigation.tsx
index d1e7cb083..ce59a1f76 100644
--- a/shared/Docs/Navigation.tsx
+++ b/shared/Docs/Navigation.tsx
@@ -9,7 +9,9 @@ import { useIsInsideMobileNavigation } from "./MobileNavigation";
import { useSectionStore } from "./SectionProvider";
import { Tag } from "./Tag";
import { remToPx } from "../../utils/remToPx";
-import { IconDocs, IconGuide } from "../Icons/duotone";
+import { topLevelNav } from "./navigationStructure";
+
+const BASE_DIR = "/docs";
function useInitialValue(value, condition = true) {
let initialValue = useRef(value).current;
@@ -34,12 +36,16 @@ function NavLink({
tag,
active,
isAnchorLink = false,
+ isTopLevel = false,
+ className = "",
children,
}: {
href: string;
tag?: any;
active?: boolean;
isAnchorLink?: boolean;
+ isTopLevel?: boolean;
+ className?: string;
children: React.ReactNode;
}) {
return (
@@ -47,11 +53,12 @@ function NavLink({
href={href}
aria-current={active ? "page" : undefined}
className={clsx(
- "flex justify-between gap-2 py-1 pr-3 text-sm transition",
- isAnchorLink ? "pl-7" : "pl-4",
+ "flex justify-between gap-2 py-1 pr-3 text-sm font-medium transition group", // group for nested hovers
+ isTopLevel ? "pl-0" : isAnchorLink ? "pl-7" : "pl-4",
active
? "text-slate-900 dark:text-white"
- : "text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white"
+ : "text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white",
+ className
)}
>
{children}
@@ -118,7 +125,8 @@ function ActivePageMarker({ group, pathname }) {
);
}
-function NavigationGroup({ group, className }) {
+// A nested navigation group of links that expand and follow
+function NavigationGroup({ group, className = "" }) {
// If this is the mobile navigation then we always render the initial
// state, so that the state does not change during the close animation.
// The state will still update when we re-open (re-render) the navigation.
@@ -135,7 +143,7 @@ function NavigationGroup({ group, className }) {