asasvirtuais 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +78 -0
  2. package/actions/draw.ts +110 -0
  3. package/components/OAuthCard.tsx +346 -0
  4. package/components/icons.tsx +11 -0
  5. package/components/markdown.tsx +18 -0
  6. package/components/stack/list.tsx +21 -0
  7. package/components/stack/menu.tsx +40 -0
  8. package/components/stack/nav.tsx +39 -0
  9. package/components/table/fixed.tsx +59 -0
  10. package/components/table/key-value.tsx +19 -0
  11. package/components/ui/color-mode.tsx +108 -0
  12. package/components/ui/provider.tsx +15 -0
  13. package/components/ui/toaster.tsx +43 -0
  14. package/components/ui/tooltip.tsx +46 -0
  15. package/hooks/useBoolean.tsx +11 -0
  16. package/hooks/useForwardAs.tsx +29 -0
  17. package/hooks/useHash copy.tsx +27 -0
  18. package/hooks/useHash.tsx +27 -0
  19. package/hooks/useIsMobile.tsx +6 -0
  20. package/hooks/useOAuthTokens.ts +97 -0
  21. package/hooks/useOpenRouterModels.ts +80 -0
  22. package/lib/auth0.ts +11 -0
  23. package/lib/blob.ts +3 -0
  24. package/lib/client-token-storage.ts +216 -0
  25. package/lib/oauth-tokens.ts +85 -0
  26. package/lib/react/context.tsx +20 -0
  27. package/lib/react/index.ts +1 -0
  28. package/lib/tools.ts +375 -0
  29. package/next-env.d.ts +5 -0
  30. package/next.config.ts +23 -0
  31. package/package.json +72 -0
  32. package/packages/blob.ts +97 -0
  33. package/packages/chat/components/chat/feed/index.tsx +76 -0
  34. package/packages/chat/components/chat/feed/story.tsx +18 -0
  35. package/packages/chat/components/chat/index.tsx +16 -0
  36. package/packages/chat/components/chat/story.tsx +74 -0
  37. package/packages/chat/components/debug/index.tsx +54 -0
  38. package/packages/chat/components/header/index.tsx +14 -0
  39. package/packages/chat/components/header/menu/index.tsx +63 -0
  40. package/packages/chat/components/header/story.tsx +33 -0
  41. package/packages/chat/components/header/title/index.tsx +35 -0
  42. package/packages/chat/components/index.ts +13 -0
  43. package/packages/chat/components/input/index.tsx +17 -0
  44. package/packages/chat/components/input/menu/index.tsx +35 -0
  45. package/packages/chat/components/input/send.tsx +21 -0
  46. package/packages/chat/components/input/story.tsx +35 -0
  47. package/packages/chat/components/input/textarea/index.tsx +20 -0
  48. package/packages/chat/components/message/file.tsx +103 -0
  49. package/packages/chat/components/message/menu/index.tsx +26 -0
  50. package/packages/chat/components/message/story.tsx +49 -0
  51. package/packages/chat/components/messages/index.tsx +23 -0
  52. package/packages/chat/components/messages/story.tsx +11 -0
  53. package/packages/chat/components/ui/prose.tsx +263 -0
  54. package/packages/chat/edit-message.tsx +49 -0
  55. package/packages/chat/header.tsx +118 -0
  56. package/packages/chat/index.ts +14 -0
  57. package/packages/chat/input.tsx +89 -0
  58. package/packages/chat/message-menu.tsx +57 -0
  59. package/packages/chat/message.tsx +44 -0
  60. package/packages/chat/messages.tsx +44 -0
  61. package/packages/chat/model-selector.tsx +172 -0
  62. package/packages/chat/scenarios.tsx +68 -0
  63. package/packages/chat/settings.tsx +98 -0
  64. package/packages/chat/temperature-slider.tsx +67 -0
  65. package/packages/chat/tool-results.tsx +32 -0
  66. package/packages/crud/core.ts +75 -0
  67. package/packages/crud/fetcher.ts +64 -0
  68. package/packages/crud/index.ts +2 -0
  69. package/packages/crud/next.ts +128 -0
  70. package/packages/crud/react.tsx +365 -0
  71. package/packages/env.ts +8 -0
  72. package/packages/fields.tsx +157 -0
  73. package/packages/firebase.ts +13 -0
  74. package/packages/firestore.ts +51 -0
  75. package/packages/form.tsx +66 -0
  76. package/packages/next.ts +64 -0
  77. package/packages/openrouter.ts +4 -0
  78. package/packages/react/context.tsx +21 -0
  79. package/packages/react/crud.tsx +372 -0
  80. package/packages/react/hooks.ts +90 -0
  81. package/packages/react/store.tsx +20 -0
  82. package/packages/replit-db.ts +219 -0
  83. package/packages/wretch.ts +22 -0
  84. package/packages/yaml.ts +163 -0
  85. package/pnpm-workspace.yaml +4 -0
  86. package/server/db.ts +15 -0
@@ -0,0 +1,59 @@
1
+ import { Table, TableCell, TableColumnHeader, TableColumnProps, TableRow } from '@chakra-ui/react/table'
2
+ import { FunctionComponent, PropsWithChildren, ReactNode } from 'react'
3
+
4
+ export type FixedTableProps = Table.RootProps & { guide: ReactNode }
5
+
6
+ export default function FixedTable( { children, guide, ...props } : FixedTableProps ) {
7
+
8
+ return (
9
+ <Table.ScrollArea>
10
+ <Table.Root tableLayout='fixed' {...props}>
11
+ <Table.Header position='sticky' top={0} zIndex={2}>
12
+ {guide}
13
+ </Table.Header>
14
+ <Table.Body zIndex={1}>
15
+ {children}
16
+ </Table.Body>
17
+ <Table.Footer position='sticky' bottom={0} zIndex={2}>
18
+ {guide}
19
+ </Table.Footer>
20
+ </Table.Root>
21
+ </Table.ScrollArea>
22
+ )
23
+ }
24
+
25
+ type TitleSizes = {
26
+ [KEY in string]: {
27
+ label: string,
28
+ width: TableColumnProps['w'],
29
+ }
30
+ }
31
+
32
+ type FixedTableComponents<T extends TitleSizes> = {
33
+ Components: {
34
+ [K in keyof T] : {
35
+ Header: FunctionComponent,
36
+ Data: FunctionComponent<PropsWithChildren>
37
+ }
38
+ },
39
+ HeadersRow: FunctionComponent,
40
+ }
41
+ export const makeFixedTableComponents = <T extends TitleSizes>(titleSizes: T): FixedTableComponents<T> => {
42
+ const Components = Object.fromEntries(
43
+ Object.entries(titleSizes).map(([key, {label, width}]) => [key, {
44
+ Header: () => <TableColumnHeader w={width}>{label}</TableColumnHeader>,
45
+ Data: ({children}: PropsWithChildren) => <TableCell w={width}>{children}</TableCell>,
46
+ }])
47
+ )
48
+ const HeadersRow = () => (
49
+ <TableRow>
50
+ {Object.entries(Components).map(([key, { Header }], i) => (
51
+ <Header key={key + i}/>
52
+ ))}
53
+ </TableRow>
54
+ )
55
+ return {
56
+ Components,
57
+ HeadersRow,
58
+ } as unknown as FixedTableComponents<T>
59
+ }
@@ -0,0 +1,19 @@
1
+ import { Table } from '@chakra-ui/react/table'
2
+
3
+ export type KeyValueTableProps = Table.RootProps & { values: { [K in string | number]: string | number } }
4
+
5
+ export default function KeyValueTable( { children, ...props } : KeyValueTableProps ) {
6
+
7
+ return (
8
+ <Table.Root variant='outline' {...props}>
9
+ <Table.Body zIndex={1}>
10
+ {Object.entries(props.values).map(([key, value]) => (
11
+ <Table.Row key={key}>
12
+ <Table.ColumnHeader>{key}</Table.ColumnHeader>
13
+ <Table.Cell>{value}</Table.Cell>
14
+ </Table.Row>
15
+ ))}
16
+ </Table.Body>
17
+ </Table.Root>
18
+ )
19
+ }
@@ -0,0 +1,108 @@
1
+ "use client"
2
+
3
+ import type { IconButtonProps, SpanProps } from "@chakra-ui/react"
4
+ import { ClientOnly, IconButton, Skeleton, Span } from "@chakra-ui/react"
5
+ import { ThemeProvider, useTheme } from "next-themes"
6
+ import type { ThemeProviderProps } from "next-themes"
7
+ import * as React from "react"
8
+ import { LuMoon, LuSun } from "react-icons/lu"
9
+
10
+ export interface ColorModeProviderProps extends ThemeProviderProps {}
11
+
12
+ export function ColorModeProvider(props: ColorModeProviderProps) {
13
+ return (
14
+ <ThemeProvider attribute="class" disableTransitionOnChange {...props} />
15
+ )
16
+ }
17
+
18
+ export type ColorMode = "light" | "dark"
19
+
20
+ export interface UseColorModeReturn {
21
+ colorMode: ColorMode
22
+ setColorMode: (colorMode: ColorMode) => void
23
+ toggleColorMode: () => void
24
+ }
25
+
26
+ export function useColorMode(): UseColorModeReturn {
27
+ const { resolvedTheme, setTheme, forcedTheme } = useTheme()
28
+ const colorMode = forcedTheme || resolvedTheme
29
+ const toggleColorMode = () => {
30
+ setTheme(resolvedTheme === "dark" ? "light" : "dark")
31
+ }
32
+ return {
33
+ colorMode: colorMode as ColorMode,
34
+ setColorMode: setTheme,
35
+ toggleColorMode,
36
+ }
37
+ }
38
+
39
+ export function useColorModeValue<T>(light: T, dark: T) {
40
+ const { colorMode } = useColorMode()
41
+ return colorMode === "dark" ? dark : light
42
+ }
43
+
44
+ export function ColorModeIcon() {
45
+ const { colorMode } = useColorMode()
46
+ return colorMode === "dark" ? <LuMoon /> : <LuSun />
47
+ }
48
+
49
+ interface ColorModeButtonProps extends Omit<IconButtonProps, "aria-label"> {}
50
+
51
+ export const ColorModeButton = React.forwardRef<
52
+ HTMLButtonElement,
53
+ ColorModeButtonProps
54
+ >(function ColorModeButton(props, ref) {
55
+ const { toggleColorMode } = useColorMode()
56
+ return (
57
+ <ClientOnly fallback={<Skeleton boxSize="8" />}>
58
+ <IconButton
59
+ onClick={toggleColorMode}
60
+ variant="ghost"
61
+ aria-label="Toggle color mode"
62
+ size="sm"
63
+ ref={ref}
64
+ {...props}
65
+ css={{
66
+ _icon: {
67
+ width: "5",
68
+ height: "5",
69
+ },
70
+ }}
71
+ >
72
+ <ColorModeIcon />
73
+ </IconButton>
74
+ </ClientOnly>
75
+ )
76
+ })
77
+
78
+ export const LightMode = React.forwardRef<HTMLSpanElement, SpanProps>(
79
+ function LightMode(props, ref) {
80
+ return (
81
+ <Span
82
+ color="fg"
83
+ display="contents"
84
+ className="chakra-theme light"
85
+ colorPalette="gray"
86
+ colorScheme="light"
87
+ ref={ref}
88
+ {...props}
89
+ />
90
+ )
91
+ },
92
+ )
93
+
94
+ export const DarkMode = React.forwardRef<HTMLSpanElement, SpanProps>(
95
+ function DarkMode(props, ref) {
96
+ return (
97
+ <Span
98
+ color="fg"
99
+ display="contents"
100
+ className="chakra-theme dark"
101
+ colorPalette="gray"
102
+ colorScheme="dark"
103
+ ref={ref}
104
+ {...props}
105
+ />
106
+ )
107
+ },
108
+ )
@@ -0,0 +1,15 @@
1
+ "use client"
2
+
3
+ import { ChakraProvider, defaultSystem } from "@chakra-ui/react"
4
+ import {
5
+ ColorModeProvider,
6
+ type ColorModeProviderProps,
7
+ } from "./color-mode"
8
+
9
+ export function Provider(props: ColorModeProviderProps) {
10
+ return (
11
+ <ChakraProvider value={defaultSystem}>
12
+ <ColorModeProvider {...props} />
13
+ </ChakraProvider>
14
+ )
15
+ }
@@ -0,0 +1,43 @@
1
+ "use client"
2
+
3
+ import {
4
+ Toaster as ChakraToaster,
5
+ Portal,
6
+ Spinner,
7
+ Stack,
8
+ Toast,
9
+ createToaster,
10
+ } from "@chakra-ui/react"
11
+
12
+ export const toaster = createToaster({
13
+ placement: "bottom-end",
14
+ pauseOnPageIdle: true,
15
+ })
16
+
17
+ export const Toaster = () => {
18
+ return (
19
+ <Portal>
20
+ <ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}>
21
+ {(toast) => (
22
+ <Toast.Root width={{ md: "sm" }}>
23
+ {toast.type === "loading" ? (
24
+ <Spinner size="sm" color="blue.solid" />
25
+ ) : (
26
+ <Toast.Indicator />
27
+ )}
28
+ <Stack gap="1" flex="1" maxWidth="100%">
29
+ {toast.title && <Toast.Title>{toast.title}</Toast.Title>}
30
+ {toast.description && (
31
+ <Toast.Description>{toast.description}</Toast.Description>
32
+ )}
33
+ </Stack>
34
+ {toast.action && (
35
+ <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
36
+ )}
37
+ {toast.closable && <Toast.CloseTrigger />}
38
+ </Toast.Root>
39
+ )}
40
+ </ChakraToaster>
41
+ </Portal>
42
+ )
43
+ }
@@ -0,0 +1,46 @@
1
+ import { Tooltip as ChakraTooltip, Portal } from "@chakra-ui/react"
2
+ import * as React from "react"
3
+
4
+ export interface TooltipProps extends ChakraTooltip.RootProps {
5
+ showArrow?: boolean
6
+ portalled?: boolean
7
+ portalRef?: React.RefObject<HTMLElement>
8
+ content: React.ReactNode
9
+ contentProps?: ChakraTooltip.ContentProps
10
+ disabled?: boolean
11
+ }
12
+
13
+ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
14
+ function Tooltip(props, ref) {
15
+ const {
16
+ showArrow,
17
+ children,
18
+ disabled,
19
+ portalled = true,
20
+ content,
21
+ contentProps,
22
+ portalRef,
23
+ ...rest
24
+ } = props
25
+
26
+ if (disabled) return children
27
+
28
+ return (
29
+ <ChakraTooltip.Root {...rest}>
30
+ <ChakraTooltip.Trigger asChild>{children}</ChakraTooltip.Trigger>
31
+ <Portal disabled={!portalled} container={portalRef}>
32
+ <ChakraTooltip.Positioner>
33
+ <ChakraTooltip.Content ref={ref} {...contentProps}>
34
+ {showArrow && (
35
+ <ChakraTooltip.Arrow>
36
+ <ChakraTooltip.ArrowTip />
37
+ </ChakraTooltip.Arrow>
38
+ )}
39
+ {content}
40
+ </ChakraTooltip.Content>
41
+ </ChakraTooltip.Positioner>
42
+ </Portal>
43
+ </ChakraTooltip.Root>
44
+ )
45
+ },
46
+ )
@@ -0,0 +1,11 @@
1
+ 'use client'
2
+ import { useCallback, useState } from 'react'
3
+
4
+ export default function useBoolean(initial: boolean = false) {
5
+ const [value, setValue] = useState(initial)
6
+ const on = () => setValue(true)
7
+ const off = () => setValue(false)
8
+ const toggle = () => setValue(prev => !prev)
9
+ const conditionalValue = useCallback( (a: any, b: any) => value ? a : b, [value] )
10
+ return [value, { on, off, toggle } as const, conditionalValue] as const
11
+ }
@@ -0,0 +1,29 @@
1
+ /** Goal: combine List (which has context) with Stack (which is more geared towards CSS for Flex utility)
2
+ * Issue: <StackList as='menu'/> the as prop overwrites the as={Stack}
3
+ * Solution: The as prop has to be reapplied, so inside StackList as={<Stack as={as}}} />
4
+ * Issue: That prevents props from being passed to Stack
5
+ * Solution: use forwardRef as={forwardRef(({as, ...props}, ref) => <Stack ref={ref} as={as} {...props} /> )}
6
+ * Issue: This is clearly a case to apply recursion.
7
+ * Issue: as={forwardRef(...)} results in components being created dynamically, which might cause undesired rerenders
8
+ *
9
+ */
10
+ import { useMemo, forwardRef, ElementType } from 'react'
11
+
12
+ export default function useForwardAs<C extends ElementType, AS extends ElementType>(Component: C, AsComponent?: AS): C {
13
+
14
+ // @ts-expect-error
15
+ return useMemo(() => (
16
+ forwardRef((props, ref) => {
17
+ if (AsComponent)
18
+ if (typeof AsComponent === 'string')
19
+ // @ts-expect-error
20
+ return <Component ref={ref} {...props} as={AsComponent} />
21
+ else
22
+ // @ts-expect-error
23
+ return <AsComponent ref={ref} {...props} as={Component} />
24
+ else
25
+ // @ts-expect-error
26
+ return <Component ref={ref} {...props} />
27
+ })
28
+ ), [AsComponent]) as C
29
+ }
@@ -0,0 +1,27 @@
1
+ 'use client'
2
+
3
+ import { useCallback, useEffect, useState } from 'react'
4
+
5
+ export default function useHash() {
6
+
7
+ const [hash, _setHash] = useState<string>('')
8
+
9
+ useEffect(() => {
10
+
11
+ const handleHashChange = () => {
12
+ _setHash(window.location.hash.slice(1))
13
+ }
14
+
15
+ handleHashChange()
16
+
17
+ window.addEventListener('hashchange', handleHashChange)
18
+
19
+ return () => window.removeEventListener('hashchange', handleHashChange)
20
+ }, [])
21
+
22
+ const setHash = useCallback((hash: string) => {
23
+ window.location.hash = hash
24
+ }, [])
25
+
26
+ return [hash, setHash] as const
27
+ }
@@ -0,0 +1,27 @@
1
+ 'use client'
2
+
3
+ import { useCallback, useEffect, useState } from 'react'
4
+
5
+ export default function useHash() {
6
+
7
+ const [hash, _setHash] = useState<string>('')
8
+
9
+ useEffect(() => {
10
+
11
+ const handleHashChange = () => {
12
+ _setHash(window.location.hash.slice(1))
13
+ }
14
+
15
+ handleHashChange()
16
+
17
+ window.addEventListener('hashchange', handleHashChange)
18
+
19
+ return () => window.removeEventListener('hashchange', handleHashChange)
20
+ }, [])
21
+
22
+ const setHash = useCallback((hash: string) => {
23
+ window.location.hash = hash
24
+ }, [])
25
+
26
+ return [hash, setHash] as const
27
+ }
@@ -0,0 +1,6 @@
1
+ 'use client'
2
+ import { useBreakpointValue } from '@chakra-ui/react'
3
+
4
+ export default function useIsMobile() {
5
+ return useBreakpointValue({ base: true, md: false }, { ssr: false })
6
+ }
@@ -0,0 +1,97 @@
1
+ 'use client'
2
+
3
+ import { useState, useEffect, useCallback } from 'react'
4
+ import { clientTokenStorage } from '@/lib/client-token-storage'
5
+
6
+ interface TokenInfo {
7
+ platform: string
8
+ isConnected: boolean
9
+ expiresAt?: string
10
+ }
11
+
12
+ export function useOAuthTokens() {
13
+ const [tokens, setTokens] = useState<Record<string, TokenInfo>>({})
14
+ const [isLoading, setIsLoading] = useState(true)
15
+
16
+ const loadTokens = useCallback(async () => {
17
+ try {
18
+ setIsLoading(true)
19
+
20
+ // First, fetch token status from server
21
+ const response = await fetch('/api/oauth/tokens')
22
+ if (response.ok) {
23
+ const data = await response.json()
24
+ const serverTokens: Record<string, TokenInfo> = {}
25
+
26
+ if (data.tokens) {
27
+ data.tokens.forEach((token: TokenInfo) => {
28
+ serverTokens[token.platform] = token
29
+ })
30
+ }
31
+
32
+ setTokens(serverTokens)
33
+ }
34
+
35
+ // Also check local storage for any tokens
36
+ const localTokens = await clientTokenStorage.getAllTokens()
37
+ if (localTokens.length > 0) {
38
+ setTokens(prev => {
39
+ const updated = { ...prev }
40
+ localTokens.forEach(token => {
41
+ updated[token.platform] = {
42
+ platform: token.platform,
43
+ isConnected: true,
44
+ expiresAt: token.expiresAt
45
+ }
46
+ })
47
+ return updated
48
+ })
49
+ }
50
+ } catch (error) {
51
+ console.error('Failed to load tokens:', error)
52
+ } finally {
53
+ setIsLoading(false)
54
+ }
55
+ }, [])
56
+
57
+ useEffect(() => {
58
+ loadTokens()
59
+ }, [loadTokens])
60
+
61
+ const refreshTokenStatus = useCallback(async (platform: string) => {
62
+ try {
63
+ const response = await fetch(`/api/oauth/tokens?platform=${platform}`)
64
+ if (response.ok) {
65
+ const data = await response.json()
66
+ setTokens(prev => ({
67
+ ...prev,
68
+ [platform]: {
69
+ platform,
70
+ isConnected: data.isConnected,
71
+ expiresAt: data.expiresAt
72
+ }
73
+ }))
74
+
75
+ // Also update local storage
76
+ if (data.accessToken) {
77
+ await clientTokenStorage.storeToken({
78
+ id: platform,
79
+ platform,
80
+ accessToken: data.accessToken,
81
+ expiresAt: data.expiresAt,
82
+ lastRefreshed: new Date().toISOString()
83
+ })
84
+ }
85
+ }
86
+ } catch (error) {
87
+ console.error(`Failed to refresh token status for ${platform}:`, error)
88
+ }
89
+ }, [])
90
+
91
+ return {
92
+ tokens,
93
+ isLoading,
94
+ refreshTokenStatus,
95
+ reloadAllTokens: loadTokens
96
+ }
97
+ }
@@ -0,0 +1,80 @@
1
+ 'use client'
2
+ import { useState, useEffect } from 'react'
3
+
4
+ export interface OpenRouterModel {
5
+ id: string
6
+ name: string
7
+ description?: string
8
+ context_length?: number
9
+ pricing?: {
10
+ prompt?: string
11
+ completion?: string
12
+ }
13
+ architecture?: {
14
+ modality?: string
15
+ }
16
+ }
17
+
18
+ interface UseOpenRouterModelsResult {
19
+ models: OpenRouterModel[]
20
+ loading: boolean
21
+ error: string | null
22
+ }
23
+
24
+ export function useOpenRouterModels(): UseOpenRouterModelsResult {
25
+ const [models, setModels] = useState<OpenRouterModel[]>([])
26
+ const [loading, setLoading] = useState(true)
27
+ const [error, setError] = useState<string | null>(null)
28
+
29
+ useEffect(() => {
30
+ async function fetchModels() {
31
+ try {
32
+ setLoading(true)
33
+ setError(null)
34
+
35
+ const response = await fetch('https://openrouter.ai/api/v1/models', {
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ },
39
+ })
40
+
41
+ if (!response.ok) {
42
+ throw new Error(`Failed to fetch models: ${response.statusText}`)
43
+ }
44
+
45
+ const data = await response.json()
46
+
47
+ // Filter and sort models for better UX
48
+ const filteredModels = data.data
49
+ ?.filter((model: any) =>
50
+ model.id &&
51
+ model.name &&
52
+ !model.id.includes(':free') // Exclude free models for cleaner list
53
+ )
54
+ ?.sort((a: any, b: any) => a.name.localeCompare(b.name))
55
+ ?.slice(0, 50) || [] // Limit to 50 models for performance
56
+
57
+ setModels(filteredModels)
58
+ } catch (err) {
59
+ console.error('Error fetching OpenRouter models:', err)
60
+ setError(err instanceof Error ? err.message : 'Unknown error occurred')
61
+
62
+ // Fallback to default models
63
+ setModels([
64
+ { id: 'openrouter/auto', name: 'Auto (Recommended)' },
65
+ { id: 'anthropic/claude-3.5-sonnet', name: 'Claude 3.5 Sonnet' },
66
+ { id: 'openai/gpt-4o', name: 'GPT-4o' },
67
+ { id: 'openai/gpt-4o-mini', name: 'GPT-4o Mini' },
68
+ { id: 'google/gemini-pro', name: 'Gemini Pro' },
69
+ { id: 'meta-llama/llama-3.1-8b-instruct', name: 'Llama 3.1 8B' },
70
+ ])
71
+ } finally {
72
+ setLoading(false)
73
+ }
74
+ }
75
+
76
+ fetchModels()
77
+ }, [])
78
+
79
+ return { models, loading, error }
80
+ }
package/lib/auth0.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { Auth0Client } from '@auth0/nextjs-auth0/server'
2
+ import { redirect } from 'next/navigation'
3
+
4
+ export const auth0 = new Auth0Client()
5
+
6
+ export async function authenticate() {
7
+ const session = await auth0.getSession()
8
+ if (! session?.user)
9
+ return redirect('/auth/login')
10
+ return session.user
11
+ }
package/lib/blob.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { put, del, getDownloadUrl } from '@vercel/blob'
2
+
3
+ export const blob = { put, del, getDownloadUrl }