Migrate docs workspace to Hexclave packages

This commit is contained in:
Bilal Godil 2026-05-29 14:42:35 -07:00
parent e770d4075d
commit 21548122f3
27 changed files with 1574 additions and 244 deletions

View File

@ -568,3 +568,6 @@ A: Microsoft Entra ID's v2 token endpoint can reject authorization-code exchange
## Q: How should the development-environment dashboard load local config files?
A: Use `jiti` to import the user's config module, matching `stack config push`, so helper functions such as `defineStackConfig(...)` or `makeConfig()` work. Disable `moduleCache` for this reader because the development-environment file watcher may import the same config path repeatedly after edits, and cached modules would otherwise hide changes.
## Q: What is needed to put the legacy Fumadocs `docs/` app back into the Hexclave pnpm workspace?
A: Add `docs` to `pnpm-workspace.yaml`, keep the package named `@hexclave/docs`, use `workspace:*` for `@hexclave/next` and `@hexclave/shared`, and update actual app imports from `@stackframe/stack`/`@stackframe/stack-shared` to `@hexclave/next`/`@hexclave/shared`. Docs app runtime env reads should prefer `NEXT_PUBLIC_HEXCLAVE_*`/`HEXCLAVE_*` while retaining legacy `STACK_*` fallbacks.

View File

@ -1,7 +1,7 @@
import { createMDX } from 'fumadocs-mdx/next';
const withMDX = createMDX();
const dashboardUrl = process.env.NEXT_PUBLIC_STACK_DASHBOARD_URL || 'http://localhost:8101';
const dashboardUrl = process.env.NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL ?? process.env.NEXT_PUBLIC_STACK_DASHBOARD_URL ?? 'http://localhost:8101';
/** @type {import('next').NextConfig} */
const config = {
@ -105,4 +105,3 @@ const config = {
};
export default withMDX(config);

View File

@ -1,18 +1,19 @@
{
"name": "@hexclave/docs",
"version": "1.0.0",
"repository": "https://github.com/hexclave/stack-auth",
"repository": "https://github.com/hexclave/hexclave",
"description": "",
"main": "index.js",
"private": true,
"type": "module",
"scripts": {
"clean": "rimraf .next && rimraf node_modules",
"build": "next build",
"dev": "next dev --port ${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}26",
"start": "next start --port ${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}26",
"typecheck": "tsc --noEmit",
"lint": "next lint",
"lint:fix": "next lint --fix",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"postinstall": "fumadocs-mdx",
"generate-openapi-docs": "node scripts/generate-functional-api-docs.mjs",
"clear-docs": "node scripts/clear-docs.js"
@ -27,8 +28,8 @@
"@radix-ui/react-scroll-area": "^1.2.9",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tabs": "^1.1.12",
"@hexclave/next": "workspace:^",
"@hexclave/shared": "workspace:^",
"@hexclave/next": "workspace:*",
"@hexclave/shared": "workspace:*",
"ai": "^6.0.0",
"class-variance-authority": "^0.7.1",
"fumadocs-core": "15.3.3",

View File

@ -1,5 +1,5 @@
import { stackServerApp } from '@/stack';
import { StackHandler } from '@stackframe/stack';
import { StackHandler } from '@hexclave/next';
export default function Handler(props: unknown) {
return <StackHandler fullPage app={stackServerApp} routeProps={props} />;

View File

@ -1,5 +1,5 @@
import { stackServerApp } from '@/stack';
import { StackProvider, StackTheme } from '@stackframe/stack';
import { StackProvider, StackTheme } from '@hexclave/next';
import { RootProvider } from 'fumadocs-ui/provider';
import { Inter } from 'next/font/google';
import './global.css';

View File

@ -1,4 +1,4 @@
import { deindent } from "@stackframe/stack-shared/dist/utils/strings";
import { deindent } from "@hexclave/shared/dist/utils/strings";
import { NextRequest } from "next/server";
export async function GET({}: NextRequest) {

View File

@ -1,8 +1,8 @@
'use client';
import { AdminOwnedProject, CurrentInternalUser, useUser } from '@stackframe/stack';
import { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';
import { stringCompare } from '@stackframe/stack-shared/dist/utils/strings';
import { AdminOwnedProject, CurrentInternalUser, useUser } from '@hexclave/next';
import { runAsynchronously } from '@hexclave/shared/dist/utils/promises';
import { stringCompare } from '@hexclave/shared/dist/utils/strings';
import { AlertTriangle, ChevronDown, Key, X } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import { useSidebar } from '../layouts/sidebar-context';

View File

@ -1,6 +1,6 @@
'use client';
import { useUser } from '@stackframe/stack';
import { useUser } from '@hexclave/next';
import { ArrowRight, Check, Code, Copy, Play, Send, Settings, Zap } from 'lucide-react';
import { useCallback, useEffect, useState } from 'react';
import type { OpenAPIOperation, OpenAPIParameter, OpenAPISchema, OpenAPISpec } from '../../lib/openapi-types';
@ -230,7 +230,7 @@ export function EnhancedAPIPage({ document, operations, description }: EnhancedA
}
// Use local API URL in development, production URL from OpenAPI spec otherwise
const defaultBaseUrl = spec?.servers?.[0]?.url || '';
const localApiUrl = process.env.NEXT_PUBLIC_STACK_API_URL;
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL;
const baseUrl = localApiUrl ? localApiUrl + '/api/v1' : defaultBaseUrl;
let url = baseUrl + path;
@ -439,8 +439,9 @@ function ModernAPIPlayground({
const generateCurlCommand = useCallback(() => {
// Use local API URL in development, production URL otherwise
const defaultBaseUrl = spec.servers?.[0]?.url || '';
const baseUrl = process.env.NEXT_PUBLIC_STACK_API_URL
? process.env.NEXT_PUBLIC_STACK_API_URL + '/api/v1'
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL;
const baseUrl = localApiUrl
? localApiUrl + '/api/v1'
: defaultBaseUrl;
let url = baseUrl + path;
@ -491,8 +492,9 @@ function ModernAPIPlayground({
const generateJavaScriptCode = useCallback(() => {
// Use local API URL in development, production URL otherwise
const defaultBaseUrl = spec.servers?.[0]?.url || '';
const baseUrl = process.env.NEXT_PUBLIC_STACK_API_URL
? process.env.NEXT_PUBLIC_STACK_API_URL + '/api/v1'
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL;
const baseUrl = localApiUrl
? localApiUrl + '/api/v1'
: defaultBaseUrl;
let url = baseUrl + path;
@ -552,8 +554,9 @@ function ModernAPIPlayground({
const generatePythonCode = useCallback(() => {
// Use local API URL in development, production URL otherwise
const defaultBaseUrl = spec.servers?.[0]?.url || '';
const baseUrl = process.env.NEXT_PUBLIC_STACK_API_URL
? process.env.NEXT_PUBLIC_STACK_API_URL + '/api/v1'
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL;
const baseUrl = localApiUrl
? localApiUrl + '/api/v1'
: defaultBaseUrl;
let url = baseUrl + path;

View File

@ -1,8 +1,8 @@
'use client';
import { useChat, type UIMessage } from '@ai-sdk/react';
import { throwErr } from '@stackframe/stack-shared/dist/utils/errors';
import { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';
import { throwErr } from '@hexclave/shared/dist/utils/errors';
import { runAsynchronously } from '@hexclave/shared/dist/utils/promises';
import { convertToModelMessages, DefaultChatTransport, type DynamicToolUIPart } from 'ai';
import { ChevronDown, ChevronUp, ExternalLink, FileText, Maximize2, Minimize2, Send, X } from 'lucide-react';
import { useEffect, useRef, useState } from 'react';
@ -351,7 +351,7 @@ export function AIChatDrawer() {
const height = isHomePage && isScrolled ? 'h-[calc(100vh-1.5rem)]' : 'h-[calc(100vh-1.5rem)]';
const [input, setInput] = useState('');
const apiBaseUrl = process.env.NEXT_PUBLIC_STACK_API_URL ?? throwErr("NEXT_PUBLIC_STACK_API_URL is not set");
const apiBaseUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL ?? throwErr("NEXT_PUBLIC_HEXCLAVE_API_URL or NEXT_PUBLIC_STACK_API_URL is not set");
const {
messages,

View File

@ -1,6 +1,6 @@
'use client';
import { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';
import { runAsynchronously } from '@hexclave/shared/dist/utils/promises';
import { useRouter } from 'next/navigation';
import { useCallback, useEffect } from 'react';

View File

@ -2,7 +2,7 @@
import { CustomSearchDialog } from '@/components/layout/custom-search-dialog';
import { SearchInputToggle } from '@/components/layout/custom-search-toggle';
import { type NavLink } from '@/lib/navigation-utils';
import { UserButton, useUser } from '@stackframe/stack';
import { UserButton, useUser } from '@hexclave/next';
import { Key, Menu, Sparkles, TableOfContents, X } from 'lucide-react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';

View File

@ -1,7 +1,7 @@
'use client';
import { ALL_APPS, AppId } from "@stackframe/stack-shared/dist/apps/apps-config";
import { AppIcon, appSquarePaddingExpression, appSquareWidthExpression } from "@stackframe/stack-shared/dist/apps/apps-ui";
import { ALL_APPS, AppId } from "@hexclave/shared/dist/apps/apps-config";
import { AppIcon, appSquarePaddingExpression, appSquareWidthExpression } from "@hexclave/shared/dist/apps/apps-ui";
import { BarChart3, ClipboardList, Code, CreditCard, Headset, KeyRound, Mail, Mails, PlayCircle, Rocket, ShieldCheck, ShieldEllipsis, Sparkles, Triangle, Tv, UserCog, Users, Vault, Webhook } from "lucide-react";
import Link from "next/link";
import { cn } from "../../lib/cn";

View File

@ -1,6 +1,6 @@
'use client';
import { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';
import { runAsynchronously } from '@hexclave/shared/dist/utils/promises';
import { Check, Copy } from 'lucide-react';
import { useEffect, useState, type ReactNode } from 'react';
import { codeToHtml } from 'shiki';
@ -192,4 +192,3 @@ export function BaseCodeblock({
</div>
);
}

View File

@ -1,6 +1,6 @@
'use client';
import { runAsynchronously } from "@stackframe/stack-shared/dist/utils/promises";
import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
import { Check, ChevronDown, ChevronUp, Code, Copy, X } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { codeToHtml } from 'shiki';

View File

@ -1,7 +1,7 @@
'use client';
import { useUser } from '@stackframe/stack';
import { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';
import { useUser } from '@hexclave/next';
import { runAsynchronously } from '@hexclave/shared/dist/utils/promises';
import { decodeProtectedHeader, decodeJwt as joseDecodeJwt } from 'jose';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { cn } from '../../lib/cn';

View File

@ -1,6 +1,6 @@
'use client';
import { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';
import { runAsynchronously } from '@hexclave/shared/dist/utils/promises';
import React from 'react';
import { ClickableTableOfContents, ParamField } from '../mdx/sdk-components';
import { AsideSection, CollapsibleTypesSection, MethodAside, MethodContent, MethodLayout } from '../ui/method-layout';

View File

@ -1,6 +1,6 @@
'use client';
import { SignIn } from '@stackframe/stack';
import { SignIn } from '@hexclave/next';
import { useState } from 'react';
import { StackContainer } from '../mdx';
import { DynamicCodeblock } from '../mdx/dynamic-code-block';

View File

@ -1,4 +1,4 @@
import { AccountSettings } from '@stackframe/stack';
import { AccountSettings } from '@hexclave/next';
import * as React from 'react';
import { StackContainer } from '../mdx';

View File

@ -1,6 +1,6 @@
'use client';
import { SelectedTeamSwitcher } from '@stackframe/stack';
import { SelectedTeamSwitcher } from '@hexclave/next';
import { useState } from 'react';
import { StackContainer } from '../mdx';
import { DynamicCodeblock } from '../mdx/dynamic-code-block';

View File

@ -1,6 +1,6 @@
'use client';
import { UserButton, useUser } from '@stackframe/stack';
import { UserButton, useUser } from '@hexclave/next';
import { Wrench } from "lucide-react";
import { useState } from "react";
import { DynamicCodeblock } from "../mdx/dynamic-code-block";

View File

@ -1,4 +1,4 @@
import { UserButton } from '@stackframe/stack';
import { UserButton } from '@hexclave/next';
import { StackContainer } from '../mdx';
const mockUser = {

View File

@ -1,4 +1,4 @@
import { throwErr } from '@stackframe/stack-shared/dist/utils/errors';
import { throwErr } from '@hexclave/shared/dist/utils/errors';
import type { PageTree } from 'fumadocs-core/server';
export type DocsSection = 'guides' | 'sdk' | 'components';

View File

@ -1,5 +1,5 @@
import { trackVisit } from '2027-track';
import { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';
import { runAsynchronously } from '@hexclave/shared/dist/utils/promises';
import { NextFetchEvent, NextRequest, NextResponse } from 'next/server';
export default function middleware(request: NextRequest, event: NextFetchEvent) {
@ -74,4 +74,3 @@ export const config = {
'/api/:path*',
],
};

View File

@ -1,13 +1,13 @@
import { StackServerApp } from '@stackframe/stack';
import { StackServerApp } from '@hexclave/next';
import "server-only";
// Explicitly configure Stack Auth for docs app
export const stackServerApp = new StackServerApp({
tokenStore: "nextjs-cookie",
projectId: process.env.NEXT_PUBLIC_STACK_PROJECT_ID,
publishableClientKey: process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.STACK_SECRET_SERVER_KEY,
baseUrl: process.env.NEXT_PUBLIC_STACK_API_URL,
projectId: process.env.NEXT_PUBLIC_HEXCLAVE_PROJECT_ID ?? process.env.NEXT_PUBLIC_STACK_PROJECT_ID,
publishableClientKey: process.env.NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY ?? process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY ?? process.env.STACK_SECRET_SERVER_KEY,
baseUrl: process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL,
analytics: {
replays: {
enabled: true,

View File

@ -13,8 +13,8 @@
"//": "NEXT_LINE_PLATFORM template",
"private": true,
"version": "2.8.109",
"repository": "https://github.com/hexclave/stack-auth",
"version": "1.0.0",
"repository": "https://github.com/hexclave/hexclave",
"sideEffects": false,
"main": "./dist/index.js",
"types": "./dist/index.d.ts",

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,7 @@ packages:
- packages/*
- apps/*
- examples/*
# `docs/` is the legacy fumadocs site, no longer maintained — replaced by
# `docs-mintlify/`. Kept on disk for migration reference; excluded from the
# workspace so it doesn't gate install / typecheck / lint.
- docs
- docs-mintlify
- sdks/*
- sdks/implementations/*