mirror of
https://github.com/vercel/workflow.git
synced 2026-09-14 19:59:43 +08:00
main
14 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3c7875ad73 |
[docs] upgrade @vercel/geistdocs to 1.19.0 (#3170)
* chore: upgrade @vercel/geistdocs to 1.17.1
Picks up the new footer (Footer no longer takes a config prop), the
heading font-weight change to 450, and the tightened navbar OSS-menu
marks. Also switches the site's own navbar logo from the vendored
geistcn LogoWorkflow fallback to the package's LogoWorkflowSdk, using
its new tuned default height instead of a hardcoded 15.
Fixes a resulting regression: navbarOssProducts entries lacked an `id`,
so resolveOssProducts' `product.id !== activeProduct` filter evaluated
to `undefined !== undefined` (false) for every entry and emptied the
OSS flyout. Added stable `id`/`label` values to each entry.
* refactor: use default navbarOssProducts list instead of a custom override
The manual navbarOssProducts array (with local logo imports/heights) is
no longer needed now that the package's DEFAULT_OSS_PRODUCTS list
already includes all these SDKs with proper id/label/section values.
navbarActiveProduct: 'workflow-sdk' now handles self-exclusion instead.
* fix: use bg-background-200 for docs surfaces to match the template
The docs, cookbook, and v5 route layouts plus the shared DocsLayout
container hardcoded bg-background-100 (pure white), so /docs/* pages
rendered on a lighter surface than the rest of the site. Switch them to
bg-background-200, matching the geistdocs template's page background.
* style: adopt package text-heading-* utilities for homepage headings
The marketing homepage headings hardcoded font-semibold (weight 600)
plus manual responsive sizes/tracking, so they rendered heavier than
the docs headings that now use Geist's 450 heading weight. Swap each
display heading to the package's text-heading-* utilities, which bundle
the 450 weight, line-height, and tracking, mapped across breakpoints to
the nearest design-system size. Inline label/emphasis spans keep their
own weight.
* style: adopt package text-heading-* utilities for worlds headings
Extends the homepage heading change to the /worlds section: the world
listing, detail, compare, and building-a-world pages plus their
components hardcoded font-semibold display headings. Swap each to the
package's text-heading-* utilities (450 weight + line-height +
tracking), mapped across breakpoints to the nearest design-system size.
Mono stat numbers, per-benchmark item labels, and the dialog title keep
their own weight.
* style: remove the bordered grid framing from the homepage
The homepage sections were wrapped in a grid divide-y border-y sm:border-x
container, drawing side borders and divider lines between every section.
Drop that framing so the sections flow with whitespace separation.
* style: remove vertical column dividers from homepage sections
Drop the divide-x column dividers still drawn inside the use-cases
(3-col), feature-grid (2-col), and templates sections, so no vertical
lines remain after the section-grid removal. Section padding keeps the
columns visually separated.
* style: make the homepage "Get started" CTA button rounded-full
* style: use text-heading-* for the feature-grid paragraph text
The two 2-col feature blurbs ("Deep integration with AI SDK.",
"Durable agents by default.") hardcoded their size/leading/tracking
plus font-medium/font-semibold weights. Those manual sizes already
equal text-heading-20/24, so swap to text-heading-20 lg:text-heading-24
— same sizes, but the Geist 450 heading weight (lead drops 600 -> 500
via the utility's [&>strong] rule). The lead stays gray-1000 for
emphasis; body stays gray-900.
* style: fade out the run-anywhere provider logos at the left/right edges
Add linear-gradient masks to the flanking cloud-provider logo groups in
the "Run anywhere, no lock-in" viz so they fade to transparent toward
the outer edges, leaving the centered code block untouched.
* style: widen the right-edge fade on the Vercel dashboard viz
The "Workflow SDK on Vercel" dashboard is offset off the right edge, so
the existing to_left black_10% mask fell off-screen and the visible
right edge hard-clipped. Widen it to black_40% so the dashboard fades
out gradually at the visible right edge.
* style: add spacing between the Vercel, use-cases, and templates sections
Wrap the UseCases and Templates sections with a top margin so there's
clear separation between "Workflow SDK on Vercel", "Build anything with
AI Agents", and "Get started" now that the section dividers are gone.
* style: widen the homepage layout from 1080px to 1200px
* style: align use-cases code block and templates cards with the Vercel section
Switch the "Build anything with" and "Get started" sections from
grid-cols-3 / [1fr_2fr] to [1fr_1.5fr], matching the "Workflow SDK on
Vercel" section above so their code block and cards share the same
right-hand column. The wider text column also lets "Build anything with"
sit on one line. Normalize both to outer padding + column gap so the
code block and cards line up exactly.
* style: extend use-cases/templates content to the right layout edge
Drop the right padding at md+ (md:pr-0) so the code block and template
cards reach the same right edge as the "Workflow SDK on Vercel"
dashboard above, which bleeds to the container edge. Mobile keeps its
padding.
* style: remove the divider between the two feature cards
Drop divide-y/lg:divide-y-0 from the feature grid so no border shows
between "Deep integration with AI SDK" and "Durable agents by default".
* refactor: position homepage sections on a shared 12-col grid
Replace the ad-hoc [1fr_1.5fr] + md:pr-0 + lg:pl-* positioning on the
Vercel, use-cases, and templates sections with a shared grid-cols-12
layout (text col-span-5, visual col-span-7), matching the vercel.com
marketing grid convention. The Vercel dashboard becomes a proper grid
cell instead of an absolutely-offset right-bleed, so all three
sections' visuals align by the grid columns with no magic values.
* style: align homepage width with the navbar content
Widen the homepage container from max-w-[1200px] to the site's
max-w-[1448px] (matching the navbar/footer) and reduce the section
gutters from sm:px-12 to sm:px-6, so section content lines up with the
navbar's content edges (right edge flush at the same column as the
navbar and footer). Also convert the "Reliability-as-code" section to
the shared grid-cols-12 layout (col-span-5 text / col-span-7 code
example), replacing its lg:grid-cols-[330px_1fr] magic values.
* refactor: handle homepage horizontal padding at the root container
Move the mobile/desktop gutter (px-4 sm:px-6) onto the homepage root
container and remove the horizontal padding from every section
component. Section content still aligns with the navbar/footer content
edges, but the gutter is now defined once instead of repeated per
section. Inner-element padding (tab buttons, visual internals) is
unchanged.
* style: left-align content sections on mobile + fix run-anywhere/o11y viz
- Left-align the centered content sections on mobile only (FeatureCardWide,
TweetWall heading, Frameworks, Run-anywhere heading/buttons), restoring
their centered layout at sm and up.
- Make the "Inspect every run" timeline span edge-to-edge by shifting its
gantt from a 14-col grid (content in cols 2-13) to a flush 12-col grid.
- Constrain the run-anywhere viz cluster to the code block width so the
provider cards (AWS/Docker/etc.) overlap behind the code block again.
* style: anchor run-anywhere provider cards to overlap the code block
Position the flanking provider-card groups relative to the centered
code block (right/left calc(50%+140px)) instead of the section edges,
so the cards sit behind and overlap the code block regardless of the
section width.
* style: make the reliability-as-code example fill its column to the right edge
Drop max-w-3xl mx-auto from the workflow/non-workflow code examples so
they fill the col-span-7 cell, aligning the code block's right edge with
the layout's right content edge (matching the tabs and other sections).
* style: split feature-card copy into a title + description
Break the AI SDK / durable-agents feature blurbs into a heading and a
separate muted description with a gap (matching the other sections)
instead of one inline paragraph, and drop the trailing periods from the
feature titles so they read as headings.
* update
* update
* style: give the tweet cards a bg-background-100 surface
* fix(swc-playground): pin monaco-editor to 0.55.1
The lockfile refresh resolved the unpinned `monaco-editor: "latest"` from
0.55.1 to 0.56.0, breaking the workflow-swc-playground Turbopack build.
0.56.0 rewrote its exports map to reroot subpaths under `esm/vs/`
("./*": "./esm/vs/*.js"). monaco-vim@0.4.4 deep-imports
`monaco-editor/esm/vs/editor/editor.api` and
`.../common/commands/shiftCommand`, which now map to
`esm/vs/esm/vs/...` — a path that does not exist. Under 0.55.1
("./*": "./*") both specifiers resolve to real files.
monaco-vim 0.4.4 is the latest published release, so pinning
monaco-editor is the only available fix.
* update
---------
Signed-off-by: christopherkindl <53372002+christopherkindl@users.noreply.github.com>
|
||
|
|
32ac8e73fd |
Fix Biome lint violations and add Biome CI check (#3222)
* Fix Biome lint violations and add Biome CI check Biome was not configured to respect .gitignore, so ~92% of the 13,355 reported diagnostics came from gitignored build artifacts. Enable VCS integration (useIgnoreFile), apply safe auto-fixes across the repo, fix the remaining mechanical errors by hand, downgrade judgment-call a11y / dangerouslySetInnerHTML rules to warnings, and add a 'biome ci' job to the Lint workflow so violations block PRs going forward. * Use an empty changeset (no behavior change, no release needed) |
||
|
|
21448a8ab3 |
chore(docs): update @vercel/geistdocs to 1.14.0 (#3002)
Co-authored-by: Peter Wielander <mittgfu@gmail.com> |
||
|
|
8a872529fe |
docs: make /worlds the canonical home for World docs (#2934)
* docs: make /worlds the canonical home for World docs The world pages (Local/Postgres/Vercel) and Building a World were duplicated inside the v4 and v5 docs trees while /worlds/[id] rendered the v4 copy — hiding v5-only content like multi-region and leaving two diverging sources of truth. - Move world docs to an unversioned docs/content/worlds/ collection (based on the v5 copies, with inline 4.x callouts for factory naming and 5.x-only env vars), rendered at /worlds/* - Add /worlds/building-a-world; flatten the docs Deploying section to a single intro page and drop its Rocket icon - Point every link, frontmatter ref, and worlds-manifest docs field at /worlds/*; add redirects for the removed v5 and building-a-world URLs - Keep world docs on agent-facing surfaces: search, llms.txt, sitemap.md/.xml, and .md exports now serve the worlds collection - Extend the docs link linter to validate worlds pages (with heading anchors) and their outgoing links Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * docs: version the world docs like the docs trees (v4/v5 switcher) Instead of a single unversioned copy, world docs now follow the same versioning strategy as the docs pages: content/worlds/v4 is served at /worlds/* (current) and content/worlds/v5 at /v5/worlds/*, restoring the original per-version content. Each world detail page (and Building a World) renders the docs version switcher — the worlds listing page has no natural home for it, so it lives on the world pages themselves. - Render-time href rewriting on v5 pages now covers /worlds/... links (shared rewriteHrefForVersion helper, also used by the v5 docs and cookbook routes), and the markdown-export rewrite does the same - v5 world pages are noindexed with a canonical to /worlds/<id>; community worlds stay unversioned (/v5/worlds/<id> redirects) - /v5/docs/deploying/world/* redirects now land on /v5/worlds/*; /v5/worlds and /v5/worlds/compare redirect to the unversioned pages - Link linter models the versioned worlds URL spaces (v5 pages resolve /worlds hrefs against the v5 collection); sitemap.md and the .md export routes cover /v5/worlds/* Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * docs: fix v4 multi-region anchor and tighten version-prefix matching Address PR review: - The v4 Deploying page linked /worlds/vercel#multi-region, but the Multi-region section only exists on the v5 world page; use the explicit cross-version /v5/worlds/vercel#multi-region link (this was the Docs Links CI failure) - rewriteHrefForVersion now uses the boundary-checked hasPathPrefix (shared leaf module lib/geistdocs/path-prefix.ts, also used by source.ts) instead of bare startsWith - buildVersionUrl's shared-route fast path is segment-based rather than substring includes() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> --------- Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
aa93cc5e69 |
Migrate docs to package-backed geistdocs (#2222)
* Migrate docs to package-backed geistdocs * update agent install cmd on home page * add copy prompt component usage * update docs test for sitemap inclusion * cut unused components * address docs migration review feedback * address stale review feedback: geistdocs 1.8.2, version icons, cookbook prompts * drop Workflow from OSS products dropdown (self-link) * bump @vercel/geistdocs to 1.11.0 * fix: resolve pnpm-lock.yaml conflict marker from main merge --------- Co-authored-by: Peter Wielander <peter.wielander@vercel.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
6fad87b2a4 |
docs: derive section landing-page cards from the page tree + lint drift (#2567)
Section index card grids (e.g. foundations) were hand-written and drifted from the sidebar (meta.json) and the actual pages. Make them derive from the fumadocs page tree (single source of truth) and add CI lint so the card grid and navigation can't fall out of sync again. - resolveSectionChildren + <AutoCards/>, bound in both v4 and v5 docs routes (correct /docs vs /v5/docs URL spaces) - getLLMText expands <AutoCards/> so llms.txt/.md/copy-page keep child links - manualCards frontmatter opt-out for curated pages (source.config.ts) - checkSectionCards (card<->nav completeness) + checkMetaEntriesResolve (dangling meta entries) in scripts/lint.ts - convert foundations + errors (drift fixes) and v5 observability to AutoCards - mark deploying + ai as manualCards (intentionally curated) - remove dangling meta entries: v4 cancellation (x2), root introduction (x2), v4/internal serializable-abort-controller Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
3ae0ae2917 |
Deprecate DurableAgent and update it with WorkflowAgent in v5 docs (#2285)
* docs: deprecate DurableAgent in v5 * docs: fix workflow docs CI failures * docs: trim deprecated DurableAgent guidance * docs: point v5 cookbook to WorkflowAgent * docs: fix v5 cookbook navigation * docs: align WorkflowAgent guide * docs: add WorkflowAgent cookbook heading * docs: expand WorkflowAgent cookbook handoff |
||
|
|
ea16d04599 |
docs: split v4/v5 content trees and fix version switcher end-to-end (#1948)
* docs: split v4/v5 content, fix version switcher end-to-end ## Content restructuring - Split `docs/content/docs/` into `docs/content/docs/v4/` and `docs/content/docs/v5/` so each version is a fully independent content tree with no shared-file coupling - v4 excludes the four pages that are v5-only (AbortController cancellation docs and the serializable-abort-controller internal page) - v5 retains all pages; `preRelease` frontmatter field removed (no longer needed now that each version is its own folder) - Removed `AbortController` / `AbortSignal` from v4 serialization page (section moved to v5 only) ## Fumadocs source - Added `v4docs` and `v5docs` as separate `defineDocs()` collections in `source.config.ts`; shared `docsSchema` (no more `preRelease` field) - `source.ts` exports both `source` (v4, `baseUrl: /docs`) and `v5Source` (v5, same base URL) ## Version routing - `version-source.ts` simplified: `filterPreReleaseFromNodes` and `isPreReleaseUrl` logic removed; v4 tree uses `source`, v5 tree uses `v5Source` + `rewriteNodeUrls` - v4 `page.tsx`: removed `preRelease` guard (v4Source has no such pages) - v5 `page.tsx`: uses `v5Source` for `getPage` / `generateStaticParams` / `generateMetadata`; `v5Link` wrapper rewrites `/docs/…` hrefs to `/v5/docs/…` so inline MDX links stay in the v5 context ## Versioned cookbook - Added `app/[lang]/v5/cookbook/` layout + page (mirrors v4 but uses `v5Source`, `rewriteCookbookUrlForVersion`, and `V5CookbookLink`) - `getCookbookTree` accepts a `versionPrefix` parameter; sidebar URLs are prefixed accordingly (`/v5/cookbook/…`) - `cookbook-tree.ts`: added `skipVersions?: string[]` per-recipe field for version-specific exclusions; `distributed-abort-controller` is marked `skipVersions: ['v5']` ## Version switcher — state & navigation - New `VersionProvider` context (`hooks/geistdocs/use-version.tsx`) backed by `localStorage`: URL is source of truth on versioned pages, `localStorage` carries the preference across non-versioned pages (cookbook overview, worlds, etc.) - `VersionSwitcher` uses `useVersion()` context instead of URL-only detection; now visible on all pages including cookbook - `DesktopMenu` and `MobileMenu` use `activeVersion` from context so the "Docs" and "Cookbook" navbar links resolve to the correct version prefix on every page - `buildVersionUrl` expanded to handle `/cookbook/…` paths alongside `/docs/…`; non-versioned routes (worlds, api) return unchanged - `switchVersion` does a `HEAD` probe before navigating; falls back to the versioned cookbook or docs home if the target page doesn't exist in that version (handles v4-only → v5 and v5-only → v4 cases) ## Cookbook content (v5) - Rewrote `agent-cancellation` recipe using a single `AbortController` pattern; removed Hard Cancellation vs Stop Signal two-approach comparison - Deleted `distributed-abort-controller` recipe from v5 (native `AbortController` serialization makes it unnecessary) - Removed references to distributed-abort-controller from `cookbook/index.mdx` and `common-patterns/timeouts.mdx` Co-authored-by: Cursor <cursoragent@cursor.com> * fix(docs): use abortSignal (not signal) in DurableAgent.stream() options Co-authored-by: Cursor <cursoragent@cursor.com> * fix(docs): update prepack scripts to use versioned content paths Content moved from docs/content/docs/ to docs/content/docs/v5/ on main (pre-release channel). Stable branch will use v4/ after backport. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
aee56993c7 |
feat: serializable AbortController/AbortSignal (#1301)
* feat: add docs and test stubs for serializable AbortController/AbortSignal Adds documentation and test infrastructure for making AbortController and AbortSignal serializable across workflow and step boundaries. The feature uses a dual hook+stream backing: hooks for deterministic replay in the workflow context, streams for real-time propagation to running steps. Docs: - Cancellation guide (foundations) covering AbortSignal and run cancellation - How Cancellation Works (how-it-works) explaining hook+stream internals - AbortSignal.timeout() error page for the workflow VM restriction - Updated serialization docs with AbortController/AbortSignal section Tests (all .todo stubs for TDD): - VM behavior: AbortController API, static methods, hook integration - Step-side: stream reader setup, abort propagation, ops queue - Serialization round-trips: all boundaries, encryption, nested structures - Consistency: race conditions, partial failure, eventual convergence - E2E workflows: timeout, parallel, step-initiated, hook-triggered, replay Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use correct frontmatter type for error page Change type from "error" to "troubleshooting" to match the valid frontmatter schema used by all other error pages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: address review feedback on cancellation docs - abort() in workflow does not synchronously update signal.aborted; instead it queues hook resumption and the replay handles state update - stream name and hook token are generated at serialization time (not deterministically in the workflow) and stored in the event log - use throwIfAborted() instead of manual signal.aborted checks Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: document runtime change for processing abort queue items on completion The current runtime only processes invocation queue items on suspension. When abort() is called after the last suspension point and the workflow completes, the queue items are dropped with a warning. Document that the runtime needs to flush abort-related items on completion/failure too. Add test stubs for this behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: generalize queue processing on completion to all item types Processing pending invocations queue items on workflow completion/failure should apply to all queue item types (steps, hooks, waits, abort signals), not just abort-related ones. Update docs and tests accordingly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: abort errors in steps are automatically wrapped in FatalError When a step throws due to an abort (AbortError from fetch, throwIfAborted, etc.), the error is wrapped in FatalError so the step skips retries. An abort is intentional cancellation, not a transient failure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: remove contrived "aborting from within a step" example Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add meaningful step-initiated abort example (quota monitor) Replace the contrived example with a watchdog pattern where a monitoring step polls an external condition and aborts parallel work when triggered. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: remove unnecessary "as const" from hook cancellation example Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: implement serializable AbortController/AbortSignal Core serialization layer: - Add AbortController/AbortSignal to SerializableSpecial interface - Add reducers for all 4 contexts (external, workflow, step, common) - Add revivers for all 4 contexts with stream-backed propagation - Add reviveAbortController helper for step/external contexts - Guard instanceof checks for VMs without AbortController global Workflow VM: - New workflow/abort-controller.ts with createCreateAbortController factory - WorkflowAbortSignal class with hook-backed state - AbortSignal static methods (abort, any, timeout blocked) - Hook integration via invocations queue and events consumer Supporting changes: - Add ABORT_STREAM_NAME, ABORT_HOOK_TOKEN symbols - Add getAbortStreamId() for system stream namespace - Add isSystem, abortRequested, abortReason to HookInvocationQueueItem - Add isSystem to world Hook entity and events - Wrap AbortError in FatalError in step handler (skip retries) - Add AbortController/AbortSignal to Serializable type - Add observability revivers for abort types - Add isSystem to postgres schema and web-shared attribute panel All 454 existing tests pass with no regressions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: wire up AbortController in workflow VM and process queue on completion - Wire up AbortController/AbortSignal in workflow VM (workflow.ts) - Add abort processing to suspension handler (hook resume + stream write) - Process pending queue items on workflow completion (throw WorkflowSuspension instead of warning for actionable items) - Fix instanceof guards for non-function AbortSignal in VM - Update test to expect WorkflowSuspension for unawaited steps All 454 existing tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: implement tests and Request.signal serialization Tests (516 passing, 18 todo for integration tests): - 18 VM behavior tests (abort-controller.test.ts) - 18 step-side behavior tests (abort-controller-step.test.ts) - 4 consistency tests + 14 integration todos (abort-consistency.test.ts) - 14 serialization round-trip tests (serialization.test.ts) - 7 hook integration + 4 integration todos (step.test.ts) Request.signal serialization: - Add signal field to SerializableSpecial Request type - Include signal in Request reducer when present - Pass signal through in external and step Request revivers Fix workflow reviver for AbortController/AbortSignal: - Use plain objects instead of prototype-based stubs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: implement all remaining .todo test stubs Convert all 27 remaining .todo stubs to real implementations: - 14 consistency tests (race conditions, partial failures, queue processing) - 4 hook integration tests (suspension handler, hydration, eventual consistency) - 9 e2e tests (timeout, parallel, step-abort, hook-cancel, replay, external signal) All 558 tests pass, 0 todos remaining. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review comments + add changelog PR review fixes: - Move cancellation after streaming in foundations nav - Fix AbortSignal reducer to detect WorkflowAbortSignal via symbol - Guard AbortController reducer from matching AbortSignal objects - Add e2e tests: throwIfAborted, reason types, uncaught fetch AbortError Changelog: - Add hidden changelog section (not in sidebar, accessible via URL) - Add draft changelog entry for serializable AbortController/AbortSignal Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: show changelog in nav for preview deployments only - Add `preview` flag to nav items in geistdocs.tsx - Filter preview items in Navbar (server component) based on VERCEL_ENV - Show "Preview" badge on preview nav items in DesktopMenu - Changelog link visible in preview deployments and local dev only Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: move preview badge from home page to navbar Move the PreviewBadge (with package tarball install modal) from the fixed bottom-right position on the home page to the navbar, so it appears on every page during preview deployments. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: consolidate preview tools into single Internal page Replace separate Changelog nav item and PreviewBadge with a single "Internal" page that only appears in preview deployments: - Rename docs/changelog/ to docs/internal/ - Internal page includes preview package install commands and draft changelogs in one place - Nav shows "Internal" with Preview badge in preview/dev only - Remove PreviewBadge from navbar (now on the Internal page) - Add callout that page is preview-only Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: use real deployment URLs on internal page + exclude from indexing - Add PreviewInstall component with copy-to-clipboard buttons using the actual VERCEL_URL (not placeholders) - Register PreviewInstallServer as MDX component for docs pages - Exclude /internal/ pages from sitemap.xml, sitemap.md, and llms.mdx - Add robots.txt Disallow for /internal/ paths Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add missing type declarations for docs code sample typechecking Add declare statements and @setup/@skip-typecheck annotations for undeclared functions in code samples (stepA, stepB, fetchData, cancellableStep, splitIntoChunks, processChunk). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add missing type declarations for all docs code samples Fix docs typecheck CI by adding declare statements and @skip-typecheck annotations for all undeclared function references across cancellation docs, error page, how-it-works page, and internal changelog. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: only suspend on completion for abort items, not all pending items The previous logic threw WorkflowSuspension for any pending queue item on completion (steps, waits, hooks). This broke fire-and-forget patterns like `void sleep('1d').then(...)` which intentionally leave a wait in the queue without awaiting it. Now only abort-related items (hooks with abortRequested) trigger suspension on completion. Other pending items get the original warning behavior — they may be intentional fire-and-forget operations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: all pending queue items are fire-and-forget on completion Remove special-case suspension for abort items on workflow completion. ALL pending queue items (steps, hooks, waits, abort signals) are now fire-and-forget when the workflow completes — they get warned about but don't block completion. This matches the existing behavior for fire-and-forget patterns like `void sleep('1d').then(...)`. Abort signals propagate through the normal suspension flow during the workflow (not at completion time). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve docs typecheck errors in code samples Move declare statements before imports to avoid TypeScript overload signature conflicts with auto-inferred imports. Add @skip-typecheck for conceptual snippets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: abort() in workflow updates signal.aborted synchronously abort() must update signal.aborted immediately so that: 1. Subsequent reads in the workflow see the correct state 2. Serialization captures aborted=true when passing signal to steps 3. Event listeners fire synchronously The hook resumption still happens via the suspension handler for durable event log recording. Both local state and durable state are now updated. Fixes e2e failures where steps received aborted=false for signals that were aborted before being passed to the step. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: update how-it-works to reflect synchronous signal.aborted update abort() now updates signal.aborted synchronously in the workflow. Update lifecycle diagram and remove outdated paragraph about signal not being updated synchronously. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: ensure abort listeners fire at deterministic point across replays On replay, hook_received is processed during event consumer subscription (at AbortController construction time), which is BEFORE the abort() call in the workflow code. If listeners fired during event processing, they'd fire at a different point than on first-run — breaking determinism. Solution: split abort into two phases: 1. _markAbortedFromReplay(): Sets signal.aborted=true (for reads/serialization) but does NOT fire listeners. Called by event consumer during replay. 2. abort(): Detects the replay flag and fires listeners at the call site. On first-run, fires listeners immediately as before. This ensures listeners fire at the abort() call site on BOTH first-run and replay, maintaining consistent ordering of side effects. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add replay ordering tests for interleaved hook scenarios Add 3 tests validating that abort listeners fire at the abort() call site on both first-run and replay, even when other hook events are interleaved in the event log. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: signal.aborted stays false until abort() is called for deterministic replay _markAbortedFromReplay no longer sets signal.aborted = true. Both aborted state and listener firing are fully deferred to abort(). This prevents if-checks on signal.aborted from taking different branches on first-run vs replay. Add deterministic branching test (unit + e2e): const controller = new AbortController(); if (controller.signal.aborted) { return 'was aborted'; // never taken } else { controller.abort(); return 'just aborted'; // always taken, both runs } Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add abort+hook ordering matrix e2e tests (4 combinations) Test all combinations of listener registration order and event trigger order to validate deterministic ordering across first-run and replay: 1. addEventListener first, abort() first 2. addEventListener first, resumeHook first 3. hook.then first, abort() first 4. hook.then first, resumeHook first Each test verifies that abort-listener fires synchronously at the abort() call site (immediately before 'after-abort' in the log), regardless of when the hook is resumed or when listeners are registered. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: simplify abort — event consumer calls _setAborted directly Remove the deferred _markAbortedFromReplay approach. The event consumer now calls _setAborted directly when hook_received is processed, which sets signal.aborted = true AND fires listeners at that point. This is correct because: - Cross-execution aborts (step/external): signal.aborted SHOULD be true on replay since the abort is a fact from a previous run. Listeners must fire so the workflow can react to the abort. - Same-execution aborts: abort() fires _setAborted synchronously. On replay, the event consumer fires it first, and abort() is a no-op. - The promiseQueue ensures listeners fire at the deterministic point matching the hook_received event's position in the event log. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: skip abort+hook ordering e2e tests pending full integration The 4 ordering matrix tests require the abort controller's internal system hook to be fully wired through the suspension handler. The hook creation timing interacts with the user hook lookup in getHookByToken. Skip until the full integration is complete. All 13 other abort e2e tests pass on CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * handle dangling streams * fix postgres world * fix abort serialization bug * refactors * add drizzle migration file * fix tests * fix tests * replace setTimeout probe and any casts with typed abort internals Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * cover post-serialization abort and nested-in-Request reader cleanup Two leak paths the prior fix left uncovered: - External signal aborted after serialization: verifies the listener attached by reduceAbortWithListener actually fires and writes the abort packet once the caller aborts later. - Signal nested inside a Request: exposed a real leak. The Request constructor copies the signal to an internal AbortSignal, so the ABORT_READER_CANCEL symbol set by reviveAbortSignal never reached request.signal, and cancelAbortReaders' walker had no Request case so Object.values(request) returned []. Fixed both sides: - Request reviver copies abort-internal symbols via copyAbortInternals - Walker descends into Request.signal explicitly Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * add v4/v5 docs switcher and pre-release gating - Mark new abort-controller/cancellation pages with preRelease: true (cancellation, how-it-works/cancellation, abort-signal-timeout-in-workflow, serializable-abort-controller). preRelease is a new optional frontmatter field declared in source.config.ts. - lib/geistdocs/versions.ts: declarative version list (v4 Latest, v5 Pre-release) plus getVersionFromPathname and buildVersionUrl helpers used by the switcher. - lib/geistdocs/version-source.ts: filter preRelease pages out of the v4 sidebar tree; rewrite sidebar URLs to /v5/docs/* on v5 so links stay in the pre-release view. - components/geistdocs/version-switcher.tsx: dropdown at the top of the sidebar, styled after the ai-sdk.dev pattern (label + subtitle). - components/geistdocs/pre-release-banner.tsx: banner rendered above the docs layout on all /v5/docs/* routes, linking back to /docs/* (Latest). - app/[lang]/v5/docs: parallel route (layout + page) that reuses the existing docs rendering but keeps preRelease pages visible. - app/[lang]/docs/[[...slug]]: 404 direct access to preRelease pages on v4 so unreleased content is never reachable without the /v5 prefix. - next.config.ts: /v5/docs -> /v5/docs/getting-started mirror of the existing /docs -> /docs/getting-started redirect. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix version switcher URL when default locale is hidden buildVersionUrl assumed segment 0 was the locale, but next.js i18n middleware hides the default locale from the URL so usePathname() returns '/docs/...' rather than '/en/docs/...'. The old logic treated 'docs' as the locale and produced '/docs/v5/getting-started' (404) instead of '/v5/docs/getting-started'. Detect the locale by checking whether segment 0 is a known structural token ('docs' or 'v5') rather than by position, so the function works for both '/docs/...' and '/<locale>/docs/...' inputs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * match ai-sdk pre-release banner styling Filled sparkles glyph, blue tint on the message text, and a plain underlined "Go to ..." link in the foreground color instead of a bordered pill. Matches the ai-sdk.dev v7 banner reference. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * match ai-sdk switcher icons and banner link color - Switcher: colored rounded icon tile next to each version (orange tint for pre-release, blue for latest), matching the ai-sdk.dev dropdown. Uses a workflow glyph inside a tinted ring. - Banner link: blue text with a softer underline by default, deeper blue on hover. Replaces the foreground-colored link that didn't match ai-sdk's styling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * use exact ai-sdk icons and darker banner link - Switcher tile: use the T-mark SVG and the bg-orange-100/border-orange-300 (pre-release) / bg-blue-100/border-blue-300 (latest) palette extracted from the ai-sdk.dev live markup, with matching dark-mode variants. - Pre-release banner sparkle: replaced the placeholder with the exact three-path geist sparkle used by ai-sdk. - Banner "Go to Latest" link: foreground color with a muted underline by default (same weight as ai-sdk's near-black link), underline intensifies on hover. The previous blue-600 was too light. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(docs): correct dark-mode colors for pre-release banner and version switcher The geistcn design-system palette inverts brightness semantics in dark mode (low indices = dim, high indices = bright) and remaps `blue-*` but not `orange-*`, so the previous token choices rendered as dim gray-blue text and a mid-bright blue icon inconsistent with the dropdown list. - Banner: use `dark:text-blue-900` for icon + label and switch the "Go to" link from `text-foreground` to the same blue (with a blue underline) so it reads as a single colored banner. - VersionSwitcher: move the text color onto the SVG itself so the `DropdownMenuItem` SVG-color override no longer hijacks the T color, and invert the dark blue palette (dark bg, light border, bright T) so the selected/trigger icon matches the list icon. - Active-row check icon: use green instead of `fd-primary` (which resolves to near-white in dark mode). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: add signal field to Request serializable type The merge from main moved the Request type into serialization/types.ts without carrying over the signal?: AbortSignal field, causing the abort-related reducers/revivers in serialization.ts to fail typecheck. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor: address review feedback on abort serialization - Dedupe abort listener attach in serialization reducers via marker symbol (prevents N-listener leak when one controller is serialized to N steps, which would double-close the backing stream on abort). - Replace token.replace('abrt_', '') string-surgery in suspension-handler by storing streamName directly on HookInvocationQueueItem at the point where it's already known (workflow/abort-controller.ts construction). - Document the deliberate sync-vs-microtask listener divergence in the workflow VM (replay determinism > spec parity inside the VM). - Add changeset noting the AbortError -> FatalError behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: correct cancellation docs against implementation - Remove the contradictory paragraph claiming signal.aborted is not set synchronously when abort() is called in the workflow. The implementation sets it sync via _setAborted; replay re-applies via the events consumer. - Reword the "Stream Succeeds, Hook Fails" recovery — there's no in-process retry loop on the step-side resumeHook call; convergence comes from the next replay re-reading the stream. - Tighten Request.signal handling: plain non-aborted native signals are intentionally dropped to avoid minting stream infra for auto-generated Request signals; only already-aborted or workflow-tagged signals are forwarded. - Replace the wrong "Pending queue items processed on completion" bullet with an accurate fire-and-forget note matching the warn-only behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: DOMException serialization (replace broken isNativeError guard) DOMException is `instanceof Error` in Node but does NOT pass `types.isNativeError()` — the existing reducer's first guard was `isNativeError(value)`, so DOMException never matched. Devalue then fell through to its arbitrary-POJO failure path. This surfaced as a real bug for AbortController/AbortSignal: when abort() is called with no argument, native AbortController synthesizes a default DOMException as signal.reason. Returning that signal's reason from a step (e.g. `{aborted, reason: signal.reason}`) crashed step return-value serialization. Replace the guard with a constructor-name check (cross-VM safe; same pattern used elsewhere for matching Error subclasses across realms). Also fixes 7 pre-existing DOMException tests in serialization.test.ts that were previously failing on main. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: drain pending queue items on workflow completion End-of-run now goes through the same suspension handler that processes a real suspension. Previously, items left in the invocations queue when the workflow function returned (or threw) were dropped with an "uncommitted operation" warning — `controller.abort()` called as the last statement of a workflow never actually propagated. Concretely fixes: - Abort hooks now write hook_received + stream packet so in-flight steps on other compute instances see signal.aborted=true and bail out. - Unawaited hooks are created (so external callers can resume them). - Unawaited steps and sleeps are queued (will execute / fire later). Strengthens abortTimeoutWorkflow's test to inspect the event log for the hook_received event — the original assertion only verified the workflow VM's local signal.aborted, which was set synchronously by the abort() call regardless of whether propagation actually happened. The strengthened test fails on main and passes after this commit. Drops the warnPendingQueueItems warning entirely. Drain failures are swallowed so the workflow's own outcome (return value or thrown error) remains the source of truth for the run's terminal state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: cover the deserialized AbortSignal listener path with an in-flight fetch The existing abort tests exercised either the polled `signal.aborted` read path (longStep busy-wait) or the already-aborted-before-fetch path. Nothing exercised the live listener path: signal starts non-aborted, step kicks off a fetch against a slow endpoint, abort fires while fetch is awaiting the response, and fetch's internal `signal.addEventListener('abort', …)` listener cancels the in-flight HTTP request. The pre-existing `fetchWithSignal` helper step was orphaned — defined but not referenced by any workflow. Wires it into a new `abortFetchInFlightWorkflow` that races a 30s fetch against a 2s sleep, aborts when the sleep wins, and returns the step's catch-path result. The test asserts both `winner=timeout` and `fetchResult.aborted=true`, which together prove fetch saw the cancellation mid-flight (the natural-completion path would set ok=true,aborted=false). Adds a local /api/delay endpoint to the nextjs-turbopack workbench so the test doesn't depend on an external service. Honors the request's own AbortSignal so cancelled connections close immediately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: extend abortFromStepWorkflow to verify in-flight sibling cancellation The original test only asserted that the workflow VM's signal saw aborted=true after a step called controller.abort(). It didn't actually verify that another in-flight step received the cancellation through the backing stream — those two paths are different (workflow VM signal updates via the hook event; sibling-step propagation runs through the live stream packet). Restructure the workflow to run longStep (a 30s polling loop on signal.aborted) in parallel with abortFromStep (now sleeps 1s, then aborts). The new assertion expects longStep.result === 'aborted' — proving it exited via the abort branch within ~1.5s, NOT ran to its 30s natural completion. Returning 'completed' would mean realtime cross-step cancellation is broken. abortFromStep gained an optional delayMs parameter so it can be sequenced against a sibling without an out-of-band sleep. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: dehydrate abort stream packets via the same machinery as hook events The abort stream packet was being encoded with bare `JSON.stringify({reason})` on the writer and decoded with `JSON.parse(text).reason` on the reader. That codec drops `undefined` (so a reason-less abort wrote literally `{}` and the observability UI showed an empty stream), and doesn't handle DOMException or any other type the rest of the codebase serializes via devalue+reducers. Switch all three sites — suspension-handler workflow-side write, patched abort step-side write, and `setupAbortStreamReader` — to use `dehydrateStepArguments`/`hydrateStepArguments`. Now the `reason` round-trips with full type fidelity (DOMException, custom errors, encrypted payloads), matching what the hook event payload already does. The suspension handler literally reuses the same dehydrated bytes for the event and the stream so they're guaranteed identical. Encryption key threading: - Suspension handler: `encryptionKey` was already in scope. - Patched abort: read from `contextStorage.getStore()?.encryptionKey` (set by the step handler before invoking the deserialize chain). - Reader (`setupAbortStreamReader`): read from `contextStorage.getStore()?.encryptionKey` for the same reason; falls back to `undefined` when called outside step context (the hydrate path is key-tolerant). On-disk verification: - Before: chunk for `controller.abort()` (no reason) was `00 7b 7d` — 3 bytes, the literal JSON `{}`, no reason carried at all. - After: chunk is `00 64 65 76 6c [{"aborted":1,"reason":2},true,"test"]` — 43 bytes, devalue-flat-encoded with the reason intact. Updated the existing stream-reader unit test to encode its mock payload through the same dehydrate path so the reader can decode it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: cover addEventListener, mid-flight throwIfAborted, and step-initiated determinism The polled-`signal.aborted` path was the only abort consumption pattern exercised end-to-end. Three new e2e tests fill the gaps: - **abortListenerWorkflow** — `signal.addEventListener('abort', cb)` firing on the deserialized step-side signal. Distinct from abortFetchInFlightWorkflow which only proves it indirectly through fetch's internal listener; this one verifies user-attached listeners directly. Step resolves with via:'listener' if propagation worked, via:'timeout' on a 30s safety timeout if it didn't. - **abortThrowIfAbortedMidFlightWorkflow** — throwIfAborted() in a polling loop, not just at step entry. The existing abortThrowIfAbortedWorkflow only covers the synchronous-throw case on a pre-aborted signal. This one starts the signal non-aborted, polls throwIfAborted every 500ms, and aborts from a sibling step after 1s. Verifies the DOMException propagates as FatalError (no retries) when fired mid-flight. - **abortDeterministicBranchFromStepWorkflow** — counterpart to abortDeterministicBranchWorkflow, but with the abort source being a step (via the patched abort() path / hook event) instead of the workflow body. Both branch-reads MUST take the same path on every replay. Uncovered a real semantic: signal.aborted reflects step-initiated aborts only after the next promise-queue checkpoint (sleep, step await, etc.) since _setAborted is chained on promiseQueue. The test inserts the required sleep('1s') checkpoint and asserts both pre and post values. Helper steps factored: stepWaitingOnAbortListener and stepPollingThrowIfAborted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: drop signal.aborted shortcut in stepWaitingOnAbortListener The shortcut would have masked a regression in the addEventListener-on-an- already-aborted-signal contract. Per the AbortSignal spec, calling addEventListener('abort', cb) on an aborted signal fires the callback (on a microtask), so user code that subscribes via the listener path alone — the common pattern — depends on it. Test the contract directly: rely solely on the listener resolving the promise. If addEventListener-on-aborted ever silently breaks, this test now reports via:'timeout' instead of paving over it with a fast-path that reads signal.aborted directly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: add DOMException reviver to observabilityRevivers so the o11y UI hydrates abort reasons The observability UI (and CLI) hydrates step IO via `observabilityRevivers`, which had no `DOMException` entry. When a step returned a value containing a DOMException (typically `{aborted, reason: <DOMException>}` — synthesized by native AbortController when abort() is called with no reason), devalue's `parse` would throw on the `["DOMException", ...]` tag, `hydrateStepIO`'s try/catch would swallow it, and the raw devalue-flat string survived to the UI. The user-visible result was step Output showing literal text like: devl[{"aborted":1,"reason":2},true,["DOMException",3]...] instead of a JSON viewer with a proper DOMException card. Add the reviver. Reconstruct as a real DOMException when the global is available (modern browsers + Node 18+, where the o11y consumers run), falling back to a name-tagged Error otherwise. Preserves message/name/ stack/cause for display. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: cover the external-signal-aborted-in-flight propagation path The existing abortExternalSignalWorkflow only validates a static read of an already-aborted signal — it tells us nothing about whether an abort that fires AFTER serialization actually propagates from the caller process, through the listener attached at workflow-start, into the backing stream, and out into the deserialized signals on the in-flight step compute. Add abortExternalSignalInFlightWorkflow that takes a non-aborted signal and runs two parallel consumption patterns against it: longStep (polling signal.aborted) and stepWaitingOnAbortListener (addEventListener path). The test creates a fresh AbortController, calls start() with its non-aborted signal, and aborts the source controller 1.5s later via setTimeout — well after both steps are mid-flight on their compute instances. Both consumers must see the cancellation: - pollResult === 'aborted' (NOT 'completed' — that would mean longStep ran the full 30s without ever seeing signal.aborted=true) - listenerResult.via === 'listener' (NOT 'timeout' — that would mean the addEventListener callback never fired) This exercises the longest end-to-end abort path in the codebase: caller-process AbortController → serialization-time listener → backing stream → step compute → deserialized signal → (poll OR addEventListener) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): use httpbin.org/delay for abortFetchInFlightWorkflow The previous setup added a /api/delay route to workbench/nextjs-turbopack to give the test a slow endpoint to fetch against. That made the workflow fail in CI on every other workbench (nextjs-webpack, astro, sveltekit, …) since the route only existed on one of them — fetch returned 404 and the test failed within 1s instead of taking the expected ~3s. Switch to httpbin.org/delay/30, the same external-service pattern used by other e2e workflows in this file (jsonplaceholder, example.com). Removes the per-workbench dependency. Drops the now-unused deploymentUrl argument from the workflow signature and test call site. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: fix serialization page — drop duplicate header, move AbortController section Two issues on the serialization foundations page: 1. `## Pass-by-Value Semantics` appeared twice. The second occurrence had no body, which rendered as an orphaned heading just above the AbortController section in the docs preview. 2. `## AbortController & AbortSignal` was at the bottom of the page, after `## Custom Class Serialization`. It belongs above the custom-class section so the standard serializable types are grouped together before the advanced topic. Removes the empty duplicate; relocates the AbortController section to sit between Request & Response and Custom Class Serialization. No content changes inside the section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: note that run.cancel() is the same as the observability Cancel button The Run Cancellation section showed the programmatic path but didn't tie it back to the UI. Add a callout: calling run.cancel() is the same action as clicking the Cancel button on a run in the observability UI — both produce identical run_cancelled events. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: cover AbortSignal.any in both workflow VM and step contexts Two distinct paths: the workflow VM ships its own AbortSignal.any impl in workflow/abort-controller.ts (composes WorkflowAbortSignals via listeners, no stream/hook backing on the composite), while steps use the native Node implementation over deserialized signals. Neither was tested. abortAnyInWorkflowWorkflow exercises the VM impl directly: creates two controllers, composes their signals via AbortSignal.any, aborts one, and asserts the composite reflects the abort synchronously without any stream round-trip. Also asserts the other source signal is unaffected so a mass-abort regression would surface here. abortAnyInStepWorkflow exercises the longest end-to-end path that uses AbortSignal.any: source controller is aborted by a sibling step, abort flows through the workflow's VM, then the backing stream, into the step's deserialized signal, into the AbortSignal.any composite, into the user's listener. Returning via:'timeout' instead of via:'listener' would mean a break anywhere on that chain. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Update .changeset/fix-dom-exception-serialization.md Co-authored-by: Peter Wielander <mittgfu@gmail.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * Update .changeset/serializable-abort-controller.md Co-authored-by: Peter Wielander <mittgfu@gmail.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * Update .changeset/drain-pending-queue-on-completion.md Co-authored-by: Peter Wielander <mittgfu@gmail.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * docs(errors): match slug-as-title convention + simplify the timeout example Two toolbar-comment fixes on the abort-signal-timeout-in-workflow error page: 1. The page title was Title Case ("AbortSignal.timeout() in Workflow") while every other page in docs/content/docs/errors/ uses the kebab-case slug as the title (e.g. timeout-in-workflow, fetch-in-workflow, workflow-not-registered). Match the convention. 2. The recommended replacement for AbortSignal.timeout() was a Promise.race that wrapped the abort + null sentinel + custom Error throw. Boil it down to the much simpler: const controller = new AbortController(); void sleep("10s").then(() => controller.abort()); return await fetchData(controller.signal); If fetchData finishes within 10s you get the response; if not, the timer fires controller.abort(), fetch rejects with AbortError, and the step's failure propagates to the workflow as a FatalError (no retries). Same observable behavior, no Promise.race scaffolding. Adds abortVoidSleepTimeoutWorkflow + matching e2e test that exercises this exact pattern end-to-end so the doc example is verified runnable (not just pseudocode). Asserts the fetch is cancelled mid-flight by the timer, returning aborted=true,ok=false from the step. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Peter Wielander <mittgfu@gmail.com> |
||
|
|
851a530164 |
Add cookbook with 50 workflow pattern recipes (#1564)
* Add cookbook section with 50 workflow pattern recipes
Migrate the "Workflow API Explorer" decision tree concept from
workflow-campaign-demos into useworkflow.dev docs as a Cookbook.
Infrastructure:
- docs/lib/cookbook-tree.ts: decision tree data, 50 recipe metadata entries, slug-to-category mapping
- docs/components/geistdocs/cookbook-explorer.tsx: interactive "I want to..." decision tree UI with breadcrumb navigation
- docs/content/docs/cookbook/index.mdx: landing page rendering CookbookExplorer component
- docs/content/docs/cookbook/meta.json + 8 category meta.json files for sidebar nav
- docs/content/docs/meta.json: added cookbook to docs nav between foundations and how-it-works
- docs/app/[lang]/docs/[[...slug]]/page.tsx: registered CookbookExplorer component
50 recipe MDX files across 8 categories (payments, approvals, resilience,
notifications, webhooks, data-processing, routing, observability), each with:
- Frontmatter (title, description, type: guide, summary with use-case scenario)
- Simplified code snippet (core pattern only, stripped of demo UI concerns)
- Full implementation code snippet (exact source from campaign demos)
- Key APIs section with links to API reference docs
* ploop: iteration 1 checkpoint
Automated checkpoint commit.
Ploop-Iter: 1
* fix: polish cookbook public routing
Keep the cookbook surface canonical at /cookbooks so docs navigation, sitemap output, and AI/chat entry points stop leaking the legacy /docs/cookbook paths.
Correct the approval-chain example so the docs teach the intended sequential approval semantics instead of implying the workflow approves after the first successful level. This keeps the cookbook aligned with the docs quality bar and avoids misleading readers with inconsistent behavior.
Ploop-Iter: 2
* docs: canonicalize cookbook doc routes
Align cookbook-facing docs outputs with the new public route so
redirects, sitemap entries, and LLM-facing exports stay consistent.
This keeps the polished cookbook section discoverable at its canonical
location while trimming the last demo-heavy recipe examples toward the
same concise style as the rest of the docs.
Ploop-Iter: 3
* ploop: iteration 4 checkpoint
Automated checkpoint commit.
Ploop-Iter: 4
* fix(docs): finalize cookbook route split
Keep cookbook content discoverable after moving it to a first-class /cookbooks surface so navigation, canonical metadata, and markdown consumers resolve the new public URLs consistently.
Avoid serving the legacy /docs/cookbook tree as if it were still part of the docs section, which reduces duplicate navigation paths and prevents stale static output from competing with the new route structure.
Ploop-Iter: 5
* docs: improve cookbook discovery
The cookbook landing page needs to work for both exploratory users and users who already know the pattern they want. This keeps the guided decision tree while adding shared category metadata and a searchable browse mode so recipe discovery feels faster and more consistent with the rest of the docs experience.
Ploop-Iter: 6
* docs: refine cookbook pattern examples
Tighten the simplified cookbook recipes so the examples teach the intended workflow semantics clearly and consistently. The changes keep the documentation focused on the core control-flow patterns reviewers called out, while removing ambiguity around partial arrivals, deadlines, and first-success behavior.
Ploop-Iter: 7
* docs: decouple cookbook sidebar tree
Separate cookbook navigation from the docs page tree so the standalone /cookbooks experience stays stable after the route move and the main docs sidebar no longer leaks cookbook entries.\n\nThis keeps cookbook navigation driven by explicit recipe metadata, which avoids duplicated section titles and makes the docs and cookbook surfaces easier to evolve independently.\n\nPloop-Iter: 8
* fix(docs): align cookbook public nav
Keep cookbook pages on their public /cookbooks surface so metadata and copied markdown do not leak legacy /docs/cookbook paths.\n\nSimplify sidebar rendering to trust the injected page tree, which avoids route-specific filtering and keeps cookbook navigation consistent with the active layout tree.\n\nPloop-Iter: 9
* refactor(docs): decouple cookbook routing
Move cookbook rendering off the shared docs route so cookbook pages can behave like a first-class docs surface without leaking cookbook-specific UI into the main docs experience.
Centralizing cookbook tree filtering keeps sidebar behavior consistent in one place and avoids duplicate cookbook navigation state across layouts.
Ploop-Iter: 10
* docs: improve cookbook explorer accessibility
Improve the cookbooks entrypoint so loading and keyboard navigation
are usable without visual cues, and keep guided and browse modes
resilient while the route hydrates.
Ploop-Iter: 11
* ploop: iteration 12 checkpoint
Automated checkpoint commit.
Ploop-Iter: 12
* docs: rename cookbooks route to cookbook (singular)
* docs: add 5 cookbook overview design variations
Add getRecipeHref, getRecipesByCategory, and collectSlugs helpers to
cookbook-tree.ts, then create 5 distinct overview page variations at
/cookbook/v1 through /cookbook/v5 for side-by-side comparison:
- v1: Category Grid (zero-JS scannable overview)
- v2: Search-First (real-time filtering with category pills)
- v3: Accordion Catalog (expandable category sections)
- v4: Decision Wizard (step-by-step guided questions)
- v5: Problem-Solution Table (master-detail by scenario)
Also adds .impeccable.md with project design context.
* docs: remove unrelated package.json bumps and generated artifacts
* docs: restructure cookbook from 50 recipes into 27 consolidated pages
Restructure the cookbook based on team meeting feedback, toolbar comments,
mux-ai pattern analysis, and Vercel org code search. Consolidates duplicates,
adds missing patterns, ensures all examples have proper directives and
type-check against the real workflow SDK.
New structure:
- common-patterns/ (9): saga, batching, rate-limiting, fan-out,
scheduling, idempotency, webhooks, content-router, child-workflows
- agent-patterns/ (5): durable-agent, tool-streaming,
human-in-the-loop, tool-orchestration, stop-workflow
- integrations/ (3): ai-sdk, sandbox, chat-sdk
- advanced/ (6): serializable-steps, durable-objects,
isomorphic-packages, secure-credentials, custom-serialization,
publishing-libraries
All 92 code snippets pass docs-typecheck against real workflow SDK types.
Deleted 8 old category folders. Updated cookbook-tree.ts, explorer, nav.
* docs: add workflow migration guides
Help teams evaluating the GA launch translate existing durable workflow systems into Vercel Workflow without reverse-engineering concept parity from product docs alone.
The guides focus on real migration decisions and concrete TypeScript examples so adoption can be driven by implementation clarity rather than platform marketing.
Ploop-Iter: 1
* ploop: iteration 2 checkpoint
Automated checkpoint commit.
Ploop-Iter: 2
* docs: refine workflow migration guides
Clarify the migration narrative for GA so teams evaluating a move from Temporal, Inngest, or Step Functions get examples that are realistic enough to trust and pricing guidance that matches the current platform model.
The Inngest guide needed a complete order-saga flow so the durable orchestration, compensation, and streaming patterns read as a credible migration target instead of a partial sketch. The pricing language across all three guides also needed to be aligned with current Workflow and Vercel compute billing semantics to avoid creating the wrong cost expectations during evaluation.
Ploop-Iter: 3
* ploop: iteration 1 checkpoint
Automated checkpoint commit.
Ploop-Iter: 1
* docs(skill): refine workflow migration guidance
Clarify migration rules so agents choose the correct resume primitive, keep streaming guidance aligned with runtime behavior, and avoid implying Vercel-managed execution for self-hosted targets.
This reduces avoidable migration mistakes in generated guidance and keeps the skill consistent with the acceptance criteria used to evaluate it.
Ploop-Iter: 2
* ploop: iteration 3 checkpoint
Automated checkpoint commit.
Ploop-Iter: 3
* docs(skills): refine workflow migration guidance
Reduce the migration skill entry point to the decision surface agents need\nso they can select the correct resume pattern without carrying duplicate\nexamples in the initial context.\n\nClarify framework precedence so prompts that explicitly ask for\nframework-agnostic boundaries do not get Hono- or Next-specific route\nshapes, while preserving framework-specific examples when requested.\n\nCentralize canonical resume examples in the shared patterns reference to\nkeep the guidance consistent across migration paths and reduce drift.\n\nPloop-Iter: 4
* docs: add workflow deep-dive references
Add a cohesive set of deep-dive reference articles so the GA launch
has architecture-level documentation grounded in the current SDK
implementation. This gives readers verified explanations of runtime,
replay, streaming, compiler, and cost-model behavior while linking the
series together for easier navigation.
Ploop-Iter: 1
* ploop: iteration 5 checkpoint
Automated checkpoint commit.
Ploop-Iter: 5
* docs: normalize deep-dive related links
Keep the new deep-dive reference pages cross-linked so readers can move between adjacent runtime concepts without depending on older how-it-works pages alone.
This preserves navigational consistency across the GA launch docs set and reduces the chance that architectural explanations drift into isolated pages that are harder to discover and maintain.
Ploop-Iter: 2
* docs(skill): refine workflow migration routing
Tighten the migration guidance so agents choose the correct resume surface and runtime boundary earlier, reducing incorrect mixed patterns in generated migrations.
Add explicit fast paths for self-hosted targets and Step Functions task-token callbacks so the skill stays consistent on callback URL vs deterministic resume decisions.
Ploop-Iter: 6
* docs: refine workflow migration skill guidance
Clarify route selection so the migration skill composes resume, runtime, and app-boundary concerns deterministically. Add a canonical Step Functions self-hosted Hono callback recipe so migrations produce the correct callback-url pattern without mixing incompatible hook surfaces.\n\nPloop-Iter: 7
* docs: checkpoint deep-dive drafts
Preserve the verified GA launch deep-dive drafts in git so the campaign work can continue from a stable checkpoint.
Capture the reviewed documentation progress now to reduce risk of drift between source-backed research and the publishable drafts.
Ploop-Iter: 3
* docs(skills): tighten workflow migration routing
Clarify the migration skill's route-selection rules so generated guidance stays consistent across resume surfaces, runtime targets, and named framework boundaries.
This reduces ambiguous outputs where agents might mix framework syntaxes or invent callback routes for webhook-based flows, which leads to migration guidance that does not match the user's runtime model.
Ploop-Iter: 8
* docs: finalize workflow deep dives
Clarify the runtime mechanics behind the GA deep-dive series so launch content stays aligned with the implementation and existing docs. Tightening these explanations reduces the risk of readers internalizing inaccurate mental models about replay, compilation, and workflow execution.\n\nPloop-Iter: 4
* docs(skills): refine workflow migration routing
Clarify route selection so migrations choose the correct resume surface and app boundary patterns for the target runtime and framework. Strengthen verification guidance to reject invented callback routes in URL-based flows and keep examples aligned with the documented migration rules.
Ploop-Iter: 9
* docs: sync compiler deep-dive runtime details
Align the compiler deep-dive trio with the actual Workflow runtime so launch materials describe the same execution model users rely on. This keeps the GA narrative accurate around deterministic replay, step queue triggers, and runtime bundle responsibilities, reducing the risk of docs teaching an architecture the SDK does not implement.
Ploop-Iter: 5
* docs(skill): tighten workflow migration guidance
Reduce hot-path skill context so migration routing stays easier to select and
verify during activation.
Trimmed examples and converted long invalid samples into concise failure rules
so the skill points agents to on-demand references instead of loading bulky
worked code by default.
Ploop-Iter: 10
* docs: tighten workflow migration guidance
Clarify route-key planning and resume-surface defaults so migration outputs
stay deterministic when prompts underspecify callback behavior.
Strengthen the deep-dive docs to trace runtime handoffs more directly,
which reduces ambiguity about how the compiler split maps to durable
execution behavior.
Ploop-Iter: 11
* docs: refine streaming and cost deep dives
Clarify the operational model behind durable streaming and zero-cost suspension so launch materials stay source-accurate for readers comparing workflow runtimes.
The updates make the workflow-step boundary, persistence path, and queue-driven cost story more explicit, reducing ambiguity around where stream I/O is allowed and why long waits do not consume compute.
Ploop-Iter: 6
* ploop: iteration 12 checkpoint
Automated checkpoint commit.
Ploop-Iter: 12
* docs: tighten deep-dive streaming accuracy
Align the launch deep dives with the current runtime so campaign content does not misstate suspension behavior or streaming backend capabilities.
These edits clarify the distinct resume paths for step suspension versus timed waits and document the backend-specific streaming guarantees now available across local, Vercel, and Postgres worlds, reducing the risk that readers build incorrect mental models from launch materials.
Ploop-Iter: 7
* docs(skills): refine callback resume taxonomy
Clarify when migrations should use deterministic internal resume versus generated callback URLs so skill outputs stay consistent across frameworks and hosting targets. Distinguish default webhook responses from manual-response flows to prevent ambiguous guidance and keep the shared callback references directly inspectable.\n\nPloop-Iter: 13
* docs: refine deep-dive runtime wording
Clarify the runtime semantics behind suspension and durable streaming so the GA launch materials stay aligned with the source of truth.
These edits tighten descriptions around wake-up paths, backend behavior, and stream lifecycle details to reduce ambiguity for readers comparing the docs to the implementation.
Ploop-Iter: 8
* docs: clarify webhook response mode defaults
Clarify when migrations should use the default webhook behavior versus
manual responses so agents make the same callback choice across the
skill entrypoint, shared patterns, and API reference.
This reduces avoidable ambiguity for callback-url prompts and makes the
default 202 behavior explicit unless a prompt requires custom response
semantics.
Ploop-Iter: 14
* docs: align cost model wake-up semantics
Prevent the GA launch materials from teaching an incorrect mental model about how suspended runs wake back up. The updated wording keeps the blog, social, and reference variants anchored to the real runtime paths so readers understand which transitions are queue-delayed, which are step-driven re-enqueues, and why that distinction matters for the cost story.
Ploop-Iter: 9
* ploop: iteration 10 checkpoint
Automated checkpoint commit.
Ploop-Iter: 10
* docs: clarify webhook resume choices
Explain the resume-surface decision points so migration and API guidance steer authors toward the correct webhook or hook pattern for the prompt.
Reduce common callback-routing mistakes early in the docs and skill so agents make fewer wrong assumptions during workflow migrations.
Ploop-Iter: 15
* docs: tighten cost model deep dives
Clarify the cost-model narrative so launch materials make source-verifiable
claims about suspension, wake-up paths, and polling behavior.
This keeps the GA messaging aligned with the runtime's actual control
flow and avoids overclaiming where the implementation has narrower
semantics than the original copy suggested.
Ploop-Iter: 11
* docs(skills): tighten resume routing guidance
Keep the migration skill entrypoint small so agents load the routing contract only when the source actually pauses for external resume. Clarify the public webhook docs around the default callback flow to reduce accidental use of lower-level runtime APIs.\n\nPloop-Iter: 16
* docs: tighten deep-dive runtime claims
Align the launch materials with the current runtime semantics so the
cost-model and execution-model narrative stays defensible against the
actual implementation.
This keeps the GA campaign focused on claims we can support directly from
source, especially around suspension, re-enqueue behavior, and the
difference between orchestration compute and client-side polling helpers.
Ploop-Iter: 12
* docs: correct cost model deep dive claims
Align the cost-model launch content with the runtime's actual suspension and re-entry mechanics so GA messaging does not overstate identical-cost waits or imply residency that the queue-based engine does not have.
This keeps the public explanation consistent with source-backed behavior around timed wake-ups, explicit workflow re-queue after step completion, and the distinction between idle worker residency and boundary I/O.
Ploop-Iter: 13
* chore: remove non-cookbook files from cookbook branch
Remove deep-dive articles, migration guides/skill, vercel-toolbar skill,
workflow-skills test fixtures, and misc artifacts that belong in separate
branches (deep-dives, migration-guides). Revert create-webhook.mdx,
getting-started/meta.json, and code-transform.mdx to main versions.
* docs: address toolbar feedback on cookbook pages
Address Vercel toolbar comments from Nathan Rajlich, Peter Wielander, Pranay Prakash, and Karthik Kalyanaraman on the cookbook branch.
In saga.mdx, remove the unnecessary `if (!(error instanceof FatalError)) throw error;` guard in the catch block — compensations should always unwind regardless of error type. Replace the `while/pop()!()` loop with a cleaner `for...of reverse()` to avoid the non-null assertion.
In ai-sdk.mdx, split the "Using Different Providers" section into two subsections: "Vercel Gateway (string model IDs)" clarifying that all string model IDs route through Gateway, and "Direct Provider Access" showing how to import from provider packages like `@workflow/ai/openai` to bypass Gateway. Change the "Tool Functions as Steps" section to "Tool Functions with Steps" and reword to explain that tool execute functions can optionally include steps via "use step" but don't have to — when they aren't steps, they run in workflow context and can modify workflow state directly.
In sandbox.mdx, rewrite the page to reflect that `@vercel/sandbox` now has first-class Workflow SDK support. Replace all `declare function` stubs and `// TODO` placeholders with real `import { Sandbox } from "@vercel/sandbox"`. Remove the four separate "use step" wrapper functions (provisionSandbox, runCommand, teardownSandbox, saveSandboxSnapshot) and show direct `Sandbox.create()`, `sandbox.runCommand()`, and `sandbox.destroy()` calls in the workflow function since these implicitly run as steps. Simplify the agent tool example to use inline execute functions that call Sandbox methods directly with an `activeSandbox` variable for workflow state.
Across all cookbook files, replace "Workflow DevKit" with "Workflow SDK" (8 instances in 5 files: publishing-libraries.mdx, secure-credentials.mdx, ai-sdk.mdx, chat-sdk.mdx, sandbox.mdx).
* docs: simplify cookbook index to plain MDX listing
Replace the interactive CookbookExplorer (726-line decision tree + browse
component) with a simple MDX page that lists recipes grouped by category
with linked titles and descriptions. Remove v1-v5 design variations and
trim cookbook-tree.ts to sidebar-only metadata.
* fix type checks
---------
Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com>
|
||
|
|
2cc8c3dc9c |
Update docs (#1010)
* Run update script * Update deps * Restore code block modifications * Reapply navbar patch * Restore custom proxy config * Add md-metadata * Add new frontmatter |
||
|
|
41f28d8b80 |
fix(docs): complete OpenGraph image integration for docs pages (#917)
* changeset Signed-off-by: voyager14 <21mh124@queensu.ca> * refactor OG image generation into shared utility Signed-off-by: voyager14 <21mh124@queensu.ca> * fix og image height mismatch Signed-off-by: voyager14 <21mh124@queensu.ca> * fix: add missing getPageImage and include OG assets in Vercel output Signed-off-by: voyager14 <21mh124@queensu.ca> * exclude og in middleware Signed-off-by: voyager14 <21mh124@queensu.ca> * fix(docs): wire up OpenGraph images for docs pages Complete the OG image integration that was started in PR #858: - Add openGraph.images metadata to docs page generateMetadata using the getPageImage helper from source.ts - Add metadataBase to the root layout so Next.js can resolve OG URLs - Remove unused generatePageMetadata helper from docs-page.tsx This ensures docs pages like /docs/how-it-works/event-sourcing have proper OpenGraph images when shared on social media. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * fix(docs): use dynamic OG image for homepage The static opengraph-image.png at the app root wasn't being served because all routes are under [lang]/. Next.js OG images need to be in the same route segment as the page they apply to. - Create dynamic opengraph-image.tsx in [lang]/(home)/ using the shared createOgImage utility - Remove the unused static opengraph-image.png from app root Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): use dynamic metadataBase for preview deployments The metadataBase was hardcoded to useworkflow.dev, which caused preview deployments to generate OG image URLs pointing to production instead of the preview URL. Now uses: - Production: https://useworkflow.dev - Preview: https://${VERCEL_URL} - Local dev: http://localhost:3000 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): address PR review comments for OG images - Fix semibold font weight from 500 to 600 (semibold is weight 600) - Extract OG_IMAGE_SIZE constant to lib/og/index.tsx for consistency - Use shared constant in all opengraph-image.tsx files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): match OG image styling to production design - Fix title styling: "Workflow:" in white, rest in grey (#888888) - Remove description from homepage OG image - Adjust positioning and font size to match expected design - Reduce text width to prevent overflow Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): add display flex for Satori multi-child divs Satori requires explicit display: flex on divs with multiple children. Added flex flex-wrap to the title div containing the two spans. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): simplify OG image layout with stacked title Use separate divs for "Workflow:" and title instead of trying to inline them with flex-wrap, which was causing layout issues in Satori. - "Workflow:" on first line in white - Title on second line in grey - Reduced font size slightly to prevent overflow - Properly stacked with flex-col layout Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): correct OG image positioning below background Workflow: text The background.png already contains "Workflow:" text, so we only need to render the dynamic title positioned below it. - Remove hardcoded "Workflow:" from JSX (it's in the background image) - Adjust top positioning to 290px to place title below background text - Restore textWrap: balance for proper text flow Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): align OG title with background Workflow: text Position and size title to match background image's Workflow: text, using non-breaking spaces for horizontal offset so title flows inline. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): restore debug border on OG image container Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): add homepage OG route and fix positioning - Add /og route for homepage OG image (avoids i18n middleware conflict) - Remove broken opengraph-image.tsx that conflicted with middleware - Add explicit openGraph metadata to homepage - Restore debug border for positioning Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): add OG routes for worlds pages - Add /og/worlds route for worlds listing page - Add /og/worlds/[id] route for individual world pages - Remove broken opengraph-image.tsx that conflicted with i18n middleware - Add explicit openGraph metadata to worlds pages Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(docs): remove badge from worlds OG images Badge was causing layout issues with title positioning. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add descriptions to AI, foundations, how-it-works, deploying, and observability pages Add terse descriptions for OG image rendering to: - 8 AI docs - 9 foundations docs - 4 how-it-works docs - 5 deploying docs - 1 observability doc Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add descriptions to API reference, errors, and remaining getting-started pages Add terse descriptions for OG image rendering to: - 23 API reference docs (workflow, workflow/api, @workflow/ai, workflow/next) - 9 errors docs - 5 getting-started docs (Astro, Express, Fastify, NestJS, Vite) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Signed-off-by: voyager14 <21mh124@queensu.ca> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: voyager14 <21mh124@queensu.ca> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
9ec21584d6 | Update docs template (#552) | ||
|
|
c0991b4ff7 |
Update docs (#349)
* Initial migration
* Remove ExperimentalPackageCallout
* Remove Callout imports
* Add missing dep
* Update postgres-world.mdx
* Add missing deps, remove unused files
* Restore homepage css
* Update logo, fix homepage
* Update run-anywhere.tsx
* Remove duplicate h1 tags
* Fix package install commands
* Update global.css
* Update code-block.tsx
* Fix framework descriptions
* Remove unused files
* Fix steps
* Update sidebar.tsx
* Remove excess horizontal rules
* Remove unused components
* Cleanup home code-block component
* Update route.ts
* Add missing feed dep
* Rename middleware to proxy
* Update next config
* Update route.tsx
* Move generateDefinition call into tsx
* Update page.tsx
* Update sidebar.tsx
* Update layout.tsx
* Remove unused files
* Fix nav
* Update route.ts
* Remove deprecated lint:links
* Load fonts locally
* Update layout.tsx
* Update route.ts
* Update Geistdocs
* Update hero.tsx
* Update search.tsx
* Update search.tsx
* docs: update url structure in chat tools example
* chore: replace gpt-5 reasoning with gpt-5.1
* docs: update instructions for llm to be more workflow-centric
* Revert "docs: update instructions for llm to be more workflow-centric"
This reverts commit
|