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,98 @@
1
+ 'use client'
2
+ import { UpdateForm, useSingle, useTable } from '@/app/module'
3
+ import { Dialog, Button, VStack, Menu, Portal, useDisclosure, Spinner, HStack, Text } from '@chakra-ui/react'
4
+ import React, { useState, useCallback, useMemo } from 'react'
5
+ import { ModelSelector } from './model-selector'
6
+ import { TemperatureSlider } from './temperature-slider'
7
+ import { useParams } from 'next/navigation'
8
+
9
+ export function SettingsDialog() {
10
+ const { id } = useParams()
11
+ const { index } = useTable('chats')
12
+ const chat = useMemo(() => index[id as keyof typeof index], [id, index])
13
+ const { open, onOpen, onClose } = useDisclosure()
14
+
15
+ if (!chat)
16
+ return null
17
+
18
+ return (
19
+ <>
20
+ <Menu.Item value="settings" onClick={onOpen}>
21
+ Settings <Menu.ItemCommand>⚙️</Menu.ItemCommand>
22
+ </Menu.Item>
23
+
24
+ <Dialog.Root open={open} onOpenChange={(e) => !e.open && onClose()}>
25
+ <Portal>
26
+ <Dialog.Backdrop />
27
+ <Dialog.Positioner>
28
+ <Dialog.Content>
29
+ <Dialog.Header>
30
+ <Dialog.Title>Chat Settings</Dialog.Title>
31
+ <Dialog.CloseTrigger />
32
+ </Dialog.Header>
33
+
34
+ <UpdateForm
35
+ table="chats"
36
+ id={chat.id}
37
+ defaults={{
38
+ model: chat.model || 'openrouter/auto',
39
+ temperature: chat.temperature || 1
40
+ }}
41
+ >
42
+ {(props) => {
43
+ return (
44
+ <form onSubmit={async (e: React.FormEvent) => {
45
+ await props.submit(e)
46
+ onClose()
47
+ }}>
48
+ <Dialog.Body>
49
+ <VStack gap={6} align="stretch">
50
+ {/* Model Selection */}
51
+ <ModelSelector
52
+ value={props.fields.model ?? 'openrouter/auto'}
53
+ onValueChange={value => props.setField('model', value)}
54
+ />
55
+
56
+ {/* Temperature Slider */}
57
+ <TemperatureSlider
58
+ value={props.fields.temperature ?? 1}
59
+ onValueChangeEnd={value => props.setField('temperature', value)}
60
+ />
61
+ </VStack>
62
+ </Dialog.Body>
63
+
64
+ <Dialog.Footer>
65
+ <HStack gap={2}>
66
+ <Dialog.CloseTrigger asChild>
67
+ <Button variant="outline" disabled={props.loading}>
68
+ Cancel
69
+ </Button>
70
+ </Dialog.CloseTrigger>
71
+
72
+ <Button
73
+ type='submit'
74
+ colorPalette="blue"
75
+ disabled={props.loading}
76
+ >
77
+ {props.loading ? (
78
+ <>
79
+ <Spinner size="sm" />
80
+ Saving...
81
+ </>
82
+ ) : (
83
+ 'Save Changes'
84
+ )}
85
+ </Button>
86
+ </HStack>
87
+ </Dialog.Footer>
88
+ </form>
89
+ )
90
+ }}
91
+ </UpdateForm>
92
+ </Dialog.Content>
93
+ </Dialog.Positioner>
94
+ </Portal>
95
+ </Dialog.Root>
96
+ </>
97
+ )
98
+ }
@@ -0,0 +1,67 @@
1
+ 'use client'
2
+ import { useState, useEffect, useCallback, memo } from 'react'
3
+ import { VStack, HStack, Text, Slider } from '@chakra-ui/react'
4
+
5
+ interface TemperatureSliderProps {
6
+ value: number
7
+ onValueChangeEnd: (value: number) => void
8
+ }
9
+
10
+ // Memoize the component to prevent re-renders unless props change
11
+ export const TemperatureSlider = memo(function TemperatureSlider({ value, onValueChangeEnd }: TemperatureSliderProps) {
12
+ // Use local state for immediate feedback
13
+ const [localValue, setLocalValue] = useState(value || 1)
14
+
15
+ // Update local value when prop changes (e.g., when settings are loaded)
16
+ useEffect(() => {
17
+ setLocalValue(value || 1)
18
+ }, [value])
19
+
20
+ // Handle value change - only updates local state
21
+ const handleValueChange = useCallback((values: { value: number[] }) => {
22
+ setLocalValue(values.value[0])
23
+ }, [])
24
+
25
+ // Handle drag end - updates parent
26
+ const handleValueChangeEnd = useCallback(() => {
27
+ onValueChangeEnd(localValue)
28
+ }, [localValue, onValueChangeEnd])
29
+
30
+ return (
31
+ <VStack align="stretch" gap={2}>
32
+ <HStack justify="space-between">
33
+ <Text fontWeight="medium">Temperature</Text>
34
+ <Text fontSize="sm" color="gray.600">
35
+ {localValue.toFixed(1)}
36
+ </Text>
37
+ </HStack>
38
+
39
+ <Text fontSize="sm" color="gray.600">
40
+ Controls randomness: lower is more focused, higher is more creative
41
+ </Text>
42
+
43
+ <Slider.Root
44
+ value={[localValue]}
45
+ onValueChange={handleValueChange}
46
+ onValueChangeEnd={handleValueChangeEnd}
47
+ min={0}
48
+ max={2}
49
+ step={0.1}
50
+ >
51
+ <Slider.Control>
52
+ <Slider.Track>
53
+ <Slider.Range />
54
+ </Slider.Track>
55
+ <Slider.Thumb index={0}>
56
+ <Slider.HiddenInput />
57
+ </Slider.Thumb>
58
+ </Slider.Control>
59
+ <HStack justify="space-between" fontSize="xs" color="gray.500" mt={1}>
60
+ <Text>0 (Focused)</Text>
61
+ <Text>1 (Balanced)</Text>
62
+ <Text>2 (Creative)</Text>
63
+ </HStack>
64
+ </Slider.Root>
65
+ </VStack>
66
+ )
67
+ })
@@ -0,0 +1,32 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import { clientTools } from '@/app/tools'
4
+
5
+ export function ToolResults({ tools }: { tools: Record<string, any> }) {
6
+ return (
7
+ <div style={{ display: 'grid', gap: 8 }}>
8
+ {Object.entries(tools).map(([tool, data]) => (
9
+ <ToolResult key={tool} tool={tool} data={data} />
10
+ ))}
11
+ </div>
12
+ )
13
+ }
14
+
15
+ export function ToolResult({ tool, data }: { tool: string, data: any }) {
16
+ const module = clientTools[tool]
17
+ if (module?.View) {
18
+ const View = module.View
19
+ return (
20
+ <div>
21
+ <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 4 }}>{tool}</div>
22
+ <View data={data} />
23
+ </div>
24
+ )
25
+ }
26
+ return (
27
+ <div>
28
+ <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 4 }}>{tool}</div>
29
+ <pre style={{ whiteSpace: 'pre-wrap' }}>{JSON.stringify(data, null, 2)}</pre>
30
+ </div>
31
+ )
32
+ }
@@ -0,0 +1,75 @@
1
+ import z from "zod"
2
+
3
+ // Core query types for consistent querying across all backends
4
+ export type BasicOperators<T, K extends keyof T> = {
5
+ '$ne'?: T[K]
6
+ '$in'?: T[K][]
7
+ '$nin'?: T[K][]
8
+ '$lt'?: T[K]
9
+ '$lte'?: T[K]
10
+ '$gt'?: T[K]
11
+ '$gte'?: T[K]
12
+ }
13
+
14
+ export type Filters<T> = {
15
+ '$limit'?: number
16
+ '$skip'?: number
17
+ '$sort'?: {
18
+ [K in keyof T]?: 1 | -1
19
+ }
20
+ '$select'?: Array<keyof T>
21
+ }
22
+
23
+ export type Query<T = any> = {
24
+ [K in keyof T]?: T[K] | BasicOperators<T, K>
25
+ } & Filters<T> & {
26
+ '$or'?: Array<Query<T>>
27
+ '$and'?: Array<Query<T>>
28
+ }
29
+
30
+ export type Operators<T, K extends keyof T> = BasicOperators<T, K> & {
31
+ '$or'?: Array<Query<T>>
32
+ '$and'?: Array<Query<T>>
33
+ }
34
+
35
+ // Core CRUD operations using props pattern
36
+ export interface FindProps {
37
+ table?: string
38
+ id: string
39
+ }
40
+
41
+ export interface CreateProps<T = any> {
42
+ table?: string
43
+ data: T
44
+ }
45
+
46
+ export interface UpdateProps<T = any> {
47
+ table?: string
48
+ id: string
49
+ data: Partial<T>
50
+ }
51
+
52
+ export interface RemoveProps {
53
+ table?: string
54
+ id: string
55
+ }
56
+
57
+ export interface ListProps<T = any> {
58
+ table?: string
59
+ query?: Query<T>
60
+ }
61
+
62
+ export interface DatabaseInterface {
63
+ [T: string]: {
64
+ readable: z.SomeZodObject,
65
+ writable: z.SomeZodObject
66
+ }
67
+ }
68
+
69
+ export interface TableInterface<Readable, Writable = Readable> {
70
+ find (props: FindProps ): Promise<Readable>
71
+ create (props: CreateProps<Writable> ): Promise<Readable>
72
+ update (props: UpdateProps<Writable> ): Promise<Readable>
73
+ remove (props: RemoveProps ): Promise<Readable>
74
+ list (props: ListProps<Readable> ): Promise<Readable[]>
75
+ }
@@ -0,0 +1,64 @@
1
+ import z from 'zod'
2
+ import type { DatabaseInterface, FindProps, CreateProps, UpdateProps, RemoveProps, ListProps, TableInterface } from './core'
3
+
4
+ export interface FetcherConfig {
5
+ baseUrl?: string
6
+ headers?: Record<string, string>
7
+ }
8
+
9
+ export function tableInterface<Schema extends DatabaseInterface, Table extends keyof Schema>({
10
+ schema,
11
+ defaultTable,
12
+ baseUrl = '/api/v1',
13
+ headers = {}
14
+ } : {
15
+ schema: Schema,
16
+ defaultTable?: Table,
17
+ baseUrl?: string,
18
+ headers?: Record<string, string>
19
+ } ): TableInterface<z.infer<Schema[keyof Schema]['readable']>, z.infer<Schema[keyof Schema]['writable']>>{
20
+
21
+ return {
22
+ async find({ table = defaultTable as string, id }) {
23
+ const response = await fetch(`${baseUrl}/${table}/${id}`, {
24
+ headers
25
+ })
26
+ return response.json()
27
+ },
28
+
29
+ async create({ table = defaultTable as string, data }) {
30
+ console.log(baseUrl, table, data)
31
+ const response = await fetch(`${baseUrl}/${table}`, {
32
+ method: 'POST',
33
+ headers: { 'Content-Type': 'application/json', ...headers },
34
+ body: JSON.stringify(data)
35
+ })
36
+ return response.json()
37
+ },
38
+
39
+ async update({ table = defaultTable as string, id, data }){
40
+ const response = await fetch(`${baseUrl}/${table}/${id}`, {
41
+ method: 'PATCH',
42
+ headers: { 'Content-Type': 'application/json', ...headers },
43
+ body: JSON.stringify(data)
44
+ })
45
+ return response.json()
46
+ },
47
+
48
+ async remove({ table = defaultTable as string, id }){
49
+ const response = await fetch(`${baseUrl}/${table}/${id}`, {
50
+ method: 'DELETE',
51
+ headers
52
+ })
53
+ return response.json()
54
+ },
55
+
56
+ async list({ table = defaultTable as string, query }){
57
+ const params = new URLSearchParams(query as any)
58
+ const response = await fetch(`${baseUrl}/${table}?${params}`, {
59
+ headers
60
+ })
61
+ return response.json()
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,2 @@
1
+ export * from './core'
2
+ export * from './fetcher'
@@ -0,0 +1,128 @@
1
+ import { NextRequest } from 'next/server'
2
+ import { DatabaseInterface, TableInterface } from './core'
3
+
4
+ export function routes(implementation: TableInterface<any, any>) {
5
+ return {
6
+ // GET /api/v1/[table]/[id]
7
+ find: (
8
+ request: NextRequest,
9
+ { params }: { params: Promise<{ table: string; id: string }> }
10
+ ) =>
11
+ handleRoute(request, params, ({ table, id }) =>
12
+ implementation.find({ table, id })
13
+ ),
14
+
15
+ // GET /api/v1/[table]
16
+ list: (
17
+ request: NextRequest,
18
+ { params }: { params: Promise<{ table: string }> }
19
+ ) =>
20
+ handleRoute(request, params, ({ table }) => {
21
+ const url = new URL(request.url)
22
+ const query = Object.fromEntries(url.searchParams)
23
+ return implementation.list({ table, query })
24
+ }),
25
+
26
+ // POST /api/v1/[table]
27
+ create: (
28
+ request: NextRequest,
29
+ { params }: { params: Promise<{ table: string }> }
30
+ ) =>
31
+ handleRoute(request, params, async ({ table }) => {
32
+ const data = await request.json()
33
+ return implementation.create({ table, data })
34
+ }),
35
+
36
+ // PATCH /api/v1/[table]/[id]
37
+ update: (
38
+ request: NextRequest,
39
+ { params }: { params: Promise<{ table: string; id: string }> }
40
+ ) =>
41
+ handleRoute(request, params, async ({ table, id }) => {
42
+ const data = await request.json()
43
+ return implementation.update({ table, id, data })
44
+ }),
45
+
46
+ // DELETE /api/v1/[table]/[id]
47
+ remove: (
48
+ request: NextRequest,
49
+ { params }: { params: Promise<{ table: string; id: string }> }
50
+ ) =>
51
+ handleRoute(request, params, ({ table, id }) =>
52
+ implementation.remove({ table, id })
53
+ ),
54
+ }
55
+ }
56
+
57
+ export async function handleRoute<P, R>(
58
+ request: NextRequest,
59
+ params: Promise<P>,
60
+ handler: (resolvedParams: any) => Promise<R>
61
+ ) {
62
+ try {
63
+ const resolvedParams = await params
64
+ const result = await handler(resolvedParams)
65
+ return Response.json(result)
66
+ } catch (error) {
67
+ console.error("Route error:", error)
68
+ return Response.json(
69
+ { error: error instanceof Error ? error.message : "Unknown error" },
70
+ { status: 500 }
71
+ )
72
+ }
73
+ }
74
+
75
+ // Utility for creating a single dynamic route handler
76
+ export function createDynamicRoute(implementation: TableInterface<any, any>) {
77
+ const routeHandlers = routes(implementation)
78
+
79
+ return async function dynamicRoute(
80
+ request: NextRequest,
81
+ { params: promise }: { params: Promise<{ params: string[] }> }
82
+ ) {
83
+ const { params } = await promise
84
+ const [table, id] = params
85
+
86
+ const method = request.method
87
+
88
+ try {
89
+ switch (method) {
90
+ case "GET":
91
+ if (id) {
92
+ return routeHandlers.find(request, {
93
+ params: Promise.resolve({ table, id }),
94
+ })
95
+ } else {
96
+ return routeHandlers.list(request, {
97
+ params: Promise.resolve({
98
+ table,
99
+ ...Object.fromEntries(request.nextUrl.searchParams.entries()),
100
+ }),
101
+ })
102
+ }
103
+ case "POST":
104
+ return routeHandlers.create(request, {
105
+ params: Promise.resolve({ table }),
106
+ })
107
+ case "PATCH":
108
+ if (!id) throw new Error("ID required for PATCH")
109
+ return routeHandlers.update(request, {
110
+ params: Promise.resolve({ table, id }),
111
+ })
112
+ case "DELETE":
113
+ if (!id) throw new Error("ID required for DELETE")
114
+ return routeHandlers.remove(request, {
115
+ params: Promise.resolve({ table, id }),
116
+ })
117
+ default:
118
+ return Response.json({ error: "Method not allowed" }, { status: 405 })
119
+ }
120
+ } catch (error) {
121
+ console.error(error)
122
+ return Response.json(
123
+ { error: error instanceof Error ? error.message : "Unknown error" },
124
+ { status: 500 }
125
+ )
126
+ }
127
+ }
128
+ }