kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
main
rodzic
b2f5397265
commit
b41d4ff1f8
|
@ -1,5 +1,5 @@
|
|||
import { sha256 } from '@agentic/platform-core'
|
||||
|
||||
export async function createConsumerApiKey(): Promise<string> {
|
||||
return `sk-${sha256()}`
|
||||
return `sk-${await sha256()}`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
|
||||
import { ActiveLink } from '@/components/active-link'
|
||||
import { useAgentic } from '@/components/agentic-provider'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
|
||||
export function AuthenticatedHeader() {
|
||||
const ctx = useAgentic()
|
||||
const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false)
|
||||
|
||||
if (!ctx?.isAuthenticated) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu
|
||||
open={isDropdownMenuOpen}
|
||||
onOpenChange={setIsDropdownMenuOpen}
|
||||
>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Avatar className='cursor-pointer'>
|
||||
<AvatarImage src={ctx.api.authSession!.user.image} />
|
||||
<AvatarFallback>
|
||||
{ctx.api.authSession!.user.username?.slice(0, 2).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem asChild>
|
||||
<ActiveLink href='/app' onClick={() => setIsDropdownMenuOpen(false)}>
|
||||
Dashboard
|
||||
</ActiveLink>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem asChild>
|
||||
<ActiveLink
|
||||
href='/app/projects'
|
||||
onClick={() => setIsDropdownMenuOpen(false)}
|
||||
>
|
||||
My Projects
|
||||
</ActiveLink>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem asChild>
|
||||
<ActiveLink
|
||||
href='/app/consumers'
|
||||
onClick={() => setIsDropdownMenuOpen(false)}
|
||||
>
|
||||
My Subscriptions
|
||||
</ActiveLink>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem asChild>
|
||||
<ActiveLink
|
||||
href='/logout'
|
||||
onClick={() => setIsDropdownMenuOpen(false)}
|
||||
>
|
||||
Logout
|
||||
</ActiveLink>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
|
||||
import { ActiveLink } from '@/components/active-link'
|
||||
import { useAgentic } from '@/components/agentic-provider'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
|
||||
import { Button } from '../ui/button'
|
||||
|
||||
export function DynamicHeader() {
|
||||
const ctx = useAgentic()
|
||||
const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
{ctx?.isAuthenticated ? (
|
||||
<DropdownMenu
|
||||
open={isDropdownMenuOpen}
|
||||
onOpenChange={setIsDropdownMenuOpen}
|
||||
>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Avatar className='cursor-pointer'>
|
||||
<AvatarImage src={ctx.api.authSession!.user.image} />
|
||||
<AvatarFallback>
|
||||
{ctx.api.authSession!.user.username?.slice(0, 2).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem asChild>
|
||||
<ActiveLink
|
||||
href='/app'
|
||||
onClick={() => setIsDropdownMenuOpen(false)}
|
||||
>
|
||||
Dashboard
|
||||
</ActiveLink>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem asChild>
|
||||
<ActiveLink
|
||||
href='/app/projects'
|
||||
onClick={() => setIsDropdownMenuOpen(false)}
|
||||
>
|
||||
My Projects
|
||||
</ActiveLink>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem asChild>
|
||||
<ActiveLink
|
||||
href='/app/consumers'
|
||||
onClick={() => setIsDropdownMenuOpen(false)}
|
||||
>
|
||||
My Subscriptions
|
||||
</ActiveLink>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem asChild>
|
||||
<ActiveLink
|
||||
href='/logout'
|
||||
onClick={() => setIsDropdownMenuOpen(false)}
|
||||
>
|
||||
Logout
|
||||
</ActiveLink>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
) : (
|
||||
<>
|
||||
<Button asChild variant='outline'>
|
||||
<ActiveLink href='/login' className='whitespace-nowrap px-4! py-2!'>
|
||||
Log in
|
||||
</ActiveLink>
|
||||
</Button>
|
||||
|
||||
<Button asChild variant='default'>
|
||||
<ActiveLink
|
||||
href='/signup'
|
||||
className='whitespace-nowrap px-4! py-2!'
|
||||
>
|
||||
Sign up
|
||||
</ActiveLink>
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,9 +1,15 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
import { ActiveLink } from '@/components/active-link'
|
||||
import { DarkModeToggle } from '@/components/dark-mode-toggle'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { GitHubIcon } from '@/icons/github'
|
||||
import { githubUrl } from '@/lib/config'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import { DynamicHeader } from './dynamic'
|
||||
import { AuthenticatedHeader } from './authenticated-header'
|
||||
import styles from './styles.module.css'
|
||||
import { UnauthenticatedHeader } from './unauthenticated-header'
|
||||
|
||||
export function Header() {
|
||||
return (
|
||||
|
@ -41,9 +47,19 @@ export function Header() {
|
|||
Docs
|
||||
</ActiveLink>
|
||||
|
||||
<DarkModeToggle />
|
||||
<div className='flex items-center h-full gap-2'>
|
||||
<UnauthenticatedHeader />
|
||||
|
||||
<DynamicHeader />
|
||||
<DarkModeToggle />
|
||||
|
||||
<Button variant='outline' size='icon' asChild>
|
||||
<Link href={githubUrl} target='_blank' rel='noopener noreferrer'>
|
||||
<GitHubIcon className='w-4 h-4' />
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
<AuthenticatedHeader />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
'use client'
|
||||
|
||||
import { ActiveLink } from '@/components/active-link'
|
||||
import { useAgentic } from '@/components/agentic-provider'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
export function UnauthenticatedHeader() {
|
||||
const ctx = useAgentic()
|
||||
|
||||
if (ctx?.isAuthenticated) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button asChild variant='outline'>
|
||||
<ActiveLink href='/login' className='whitespace-nowrap px-4! py-2!'>
|
||||
Log in
|
||||
</ActiveLink>
|
||||
</Button>
|
||||
|
||||
<Button asChild variant='default'>
|
||||
<ActiveLink href='/signup' className='whitespace-nowrap px-4! py-2!'>
|
||||
Sign up
|
||||
</ActiveLink>
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -30,6 +30,7 @@
|
|||
"@sindresorhus/slugify": "catalog:",
|
||||
"decircular": "catalog:",
|
||||
"is-obj": "catalog:",
|
||||
"ohash": "^2.0.11",
|
||||
"parse-json": "catalog:",
|
||||
"sort-keys": "catalog:",
|
||||
"type-fest": "catalog:",
|
||||
|
|
|
@ -1426,6 +1426,9 @@ importers:
|
|||
is-obj:
|
||||
specifier: 'catalog:'
|
||||
version: 3.0.0
|
||||
ohash:
|
||||
specifier: ^2.0.11
|
||||
version: 2.0.11
|
||||
parse-json:
|
||||
specifier: 'catalog:'
|
||||
version: 8.3.0
|
||||
|
|
18
todo.md
18
todo.md
|
@ -7,12 +7,6 @@
|
|||
|
||||
- **api keys should go beyond 1:1 consumers**
|
||||
- **currently not obvious how to get api key**
|
||||
- marketplace public project detail page
|
||||
- add breadcrumb nav: marketplace > @agentic > search
|
||||
- add last published date somewhere
|
||||
- tool input/output schemas; move `$schema` to the top
|
||||
- break out into a few subcomponents; some can be server components
|
||||
- mcp inspector
|
||||
- improve private project page
|
||||
- link to public page if published
|
||||
- list deployments
|
||||
|
@ -20,7 +14,7 @@
|
|||
- marketplace index page
|
||||
- add search / sorting
|
||||
- replace render for api and/or add turbo for caching (too slow to deploy)
|
||||
- create slack + notifications
|
||||
- create slack or discord + notifications
|
||||
|
||||
## TODO: Post-MVP
|
||||
|
||||
|
@ -113,6 +107,7 @@
|
|||
- also add `@agentic/json-schema` to `createJsonSchema` parsing instead of current no-op
|
||||
- add support for [`@google/genai`](https://github.com/googleapis/js-genai) tools adapter
|
||||
- currently difficult due to their use of non-standard json schemas
|
||||
- add support for `crewai`
|
||||
- validate example args against the tool's input schema during config validation
|
||||
- add scroll appearance motion to hero animation
|
||||
- add ts sdk examples to e2e tests
|
||||
|
@ -131,3 +126,12 @@
|
|||
- add support for enterprise / custom / contact us pricing
|
||||
- consider changing homepage hero CTA to include publishing
|
||||
- docs: add notes about constraints on mcp origin servers (static tools)
|
||||
- analytics dashboard
|
||||
- UX onboarding
|
||||
- visual pricing plan config + previews
|
||||
- marketplace public project detail page
|
||||
- add breadcrumb nav: marketplace > @agentic > search
|
||||
- add last published date somewhere
|
||||
- tool input/output schemas; move `$schema` to the top
|
||||
- break out into a few subcomponents; some can be server components
|
||||
- mcp inspector
|
||||
|
|
Ładowanie…
Reference in New Issue