@geenius/db 0.2.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.
package/LICENSE ADDED
@@ -0,0 +1 @@
1
+ MIT License — © Antigravity HQ
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # `@geenius/db`
2
+
3
+ > Multi-provider database adapter implementations for the Geenius ecosystem.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ `@geenius/db` provides real database provider implementations that conform to the `DbAdapter` interface from `@geenius/adapters-shared`. This is the package you use when you need to connect to an actual database.
10
+
11
+ ### Providers
12
+
13
+ | Provider | Factory | SDK |
14
+ |----------|---------|-----|
15
+ | **Convex** | `createConvexDbAdapter()` | `convex` |
16
+ | **Supabase** | `createSupabaseDbAdapter()` | `@supabase/supabase-js` |
17
+ | **Neon (Drizzle)** | `createNeonDbAdapter()` | `@neondatabase/serverless` + `drizzle-orm` |
18
+ | **MongoDB** | `createMongoDbAdapter()` | `mongodb` |
19
+ | **Cloudflare KV** | `createCloudflareKVDbAdapter()` | `@cloudflare/workers-types` |
20
+ | **In-Memory** | `createMemoryDbAdapter()` | *(none)* |
21
+
22
+ > For localStorage-based prototyping (Pronto tier), use `createLocalStorageDbAdapter()` from `@geenius/adapters`.
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pnpm add @geenius/db
30
+ ```
31
+
32
+ ## Sub-package Exports
33
+
34
+ ```typescript
35
+ import { createConvexDbAdapter, createSupabaseDbAdapter } from '@geenius/db' // shared
36
+ import { DbProvider, useDb } from '@geenius/db/react' // React hooks
37
+ import { DbProvider, createDb } from '@geenius/db/solidjs' // SolidJS primitives
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Quick Start
43
+
44
+ ### Convex
45
+
46
+ ```typescript
47
+ import { createConvexDbAdapter } from '@geenius/db'
48
+
49
+ const db = createConvexDbAdapter({
50
+ client: convexClient,
51
+ functions: {
52
+ create: api.adapters.create,
53
+ get: api.adapters.get,
54
+ update: api.adapters.update,
55
+ delete: api.adapters.delete,
56
+ list: api.adapters.list,
57
+ query: api.adapters.query,
58
+ count: api.adapters.count,
59
+ },
60
+ })
61
+ ```
62
+
63
+ ### Supabase
64
+
65
+ ```typescript
66
+ import { createSupabaseDbAdapter } from '@geenius/db'
67
+
68
+ const db = createSupabaseDbAdapter({
69
+ supabaseUrl: process.env.SUPABASE_URL!,
70
+ supabaseKey: process.env.SUPABASE_ANON_KEY!,
71
+ })
72
+ ```
73
+
74
+ ### Neon (Drizzle)
75
+
76
+ ```typescript
77
+ import { createNeonDbAdapter } from '@geenius/db'
78
+ import { eq, and, gt, like } from 'drizzle-orm'
79
+
80
+ const db = createNeonDbAdapter({
81
+ connectionString: process.env.DATABASE_URL!,
82
+ schema: myDrizzleSchema,
83
+ operators: { eq, and, gt, like, or, ne, lt, lte, gte, sql },
84
+ })
85
+ ```
86
+
87
+ ### MongoDB
88
+
89
+ ```typescript
90
+ import { createMongoDbAdapter } from '@geenius/db'
91
+
92
+ const db = createMongoDbAdapter({
93
+ uri: process.env.MONGODB_URI!,
94
+ dbName: 'my-app',
95
+ })
96
+ ```
97
+
98
+ ### React Provider
99
+
100
+ ```tsx
101
+ import { DbProvider, useDb } from '@geenius/db/react'
102
+ import { createConvexDbAdapter } from '@geenius/db'
103
+
104
+ function App() {
105
+ const db = createConvexDbAdapter({ ... })
106
+ return (
107
+ <DbProvider adapter={db}>
108
+ <MyComponent />
109
+ </DbProvider>
110
+ )
111
+ }
112
+
113
+ function MyComponent() {
114
+ const db = useDb()
115
+ // db.list('users'), db.create('users', { name: '...' }), etc.
116
+ }
117
+ ```
118
+
119
+ ### SolidJS Provider
120
+
121
+ ```tsx
122
+ import { DbProvider, createDb } from '@geenius/db/solidjs'
123
+ import { createConvexDbAdapter } from '@geenius/db'
124
+
125
+ function App() {
126
+ const db = createConvexDbAdapter({ ... })
127
+ return (
128
+ <DbProvider adapter={db}>
129
+ <MyComponent />
130
+ </DbProvider>
131
+ )
132
+ }
133
+
134
+ function MyComponent() {
135
+ const db = createDb()
136
+ // db.list('users'), db.create('users', { name: '...' }), etc.
137
+ }
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Architecture
143
+
144
+ This package implements the `DbAdapter` interface defined in `@geenius/adapters-shared`:
145
+
146
+ ```typescript
147
+ interface DbAdapter {
148
+ create<T>(collection: string, data: Omit<T, 'id'>): Promise<T & { id: string }>
149
+ get<T>(collection: string, id: string): Promise<T | null>
150
+ update<T>(collection: string, id: string, data: Partial<T>): Promise<T | null>
151
+ delete(collection: string, id: string): Promise<boolean>
152
+ list<T>(collection: string, options?: ListOptions): Promise<T[]>
153
+ query<T>(collection: string, filter: QueryFilter): Promise<T[]>
154
+ count(collection: string, filter?: QueryFilter): Promise<number>
155
+ }
156
+ ```
157
+
158
+ All providers throw `DbError` from `@geenius/adapters-shared` on failure.
159
+
160
+ ---
161
+
162
+ ## License
163
+
164
+ MIT — © Antigravity HQ
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@geenius/db",
3
+ "type": "module",
4
+ "version": "0.2.0",
5
+ "description": "Geenius DB — Multi-provider database adapter implementations (Convex, Supabase, Neon, MongoDB, CloudflareKV)",
6
+ "author": "Antigravity HQ",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/geenius-dev/geenius-db.git"
11
+ },
12
+ "keywords": [
13
+ "database",
14
+ "adapter",
15
+ "convex",
16
+ "supabase",
17
+ "neon",
18
+ "mongodb",
19
+ "cloudflare-kv",
20
+ "react",
21
+ "solidjs",
22
+ "geenius"
23
+ ],
24
+ "scripts": {
25
+ "dev": "pnpm -r --parallel type-check",
26
+ "build": "pnpm -r build",
27
+ "clean": "pnpm -r clean",
28
+ "lint": "pnpm -r --parallel type-check",
29
+ "test": "echo \"No tests configured yet\" && exit 0",
30
+ "type-check": "pnpm -r type-check",
31
+ "format": "prettier --write \"packages/*/src/**/*.{ts,tsx}\"",
32
+ "version:patch": "pnpm -r exec -- npm version patch --no-git-tag-version && npm version patch -m 'v%s'",
33
+ "version:minor": "pnpm -r exec -- npm version minor --no-git-tag-version && npm version minor -m 'v%s'",
34
+ "version:major": "pnpm -r exec -- npm version major --no-git-tag-version && npm version major -m 'v%s'",
35
+ "release": "git push && git push --tags",
36
+ "publish:all": "pnpm -r publish --access public"
37
+ },
38
+ "devDependencies": {
39
+ "prettier": "^3.8.1",
40
+ "typescript": "~6.0.2"
41
+ },
42
+ "engines": {
43
+ "node": ">=20.0.0"
44
+ },
45
+ "exports": {
46
+ ".": {
47
+ "types": "./packages/shared/dist/index.d.ts",
48
+ "import": "./packages/shared/dist/index.js"
49
+ },
50
+ "./shared": {
51
+ "types": "./packages/shared/dist/index.d.ts",
52
+ "import": "./packages/shared/dist/index.js"
53
+ },
54
+ "./react": {
55
+ "types": "./packages/react/dist/index.d.ts",
56
+ "import": "./packages/react/dist/index.js"
57
+ },
58
+ "./solidjs": {
59
+ "types": "./packages/solidjs/dist/index.d.ts",
60
+ "import": "./packages/solidjs/dist/index.js"
61
+ }
62
+ },
63
+ "main": "./packages/shared/dist/index.js",
64
+ "types": "./packages/shared/dist/index.d.ts"
65
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@geenius/db-react",
3
+ "version": "0.2.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Geenius DB — React hooks and providers for database adapters",
7
+ "author": "Antigravity HQ",
8
+ "license": "MIT",
9
+ "publishConfig": {
10
+ "access": "restricted"
11
+ },
12
+ "main": "./dist/index.js",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "clean": "rm -rf dist",
28
+ "type-check": "tsc --noEmit",
29
+ "prepublishOnly": "pnpm clean && pnpm build"
30
+ },
31
+ "peerDependencies": {
32
+ "@geenius/adapters-shared": ">=0.2.0",
33
+ "@geenius/db-shared": ">=0.2.0",
34
+ "react": ">=19.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@geenius/adapters-shared": "link:../../../geenius-adapters/packages/shared",
38
+ "@geenius/db-shared": "workspace:*",
39
+ "@types/react": "^19.1.4",
40
+ "react": "^19.1.0",
41
+ "tsup": "^8.5.1",
42
+ "typescript": "~6.0.2"
43
+ },
44
+ "engines": {
45
+ "node": ">=20.0.0"
46
+ }
47
+ }
@@ -0,0 +1,82 @@
1
+ // @geenius/db-react — React hooks and providers for database adapters
2
+
3
+ 'use client'
4
+
5
+ import { createContext, useContext, useMemo, type ReactNode } from 'react'
6
+ import type { DbAdapter } from '@geenius/adapters-shared'
7
+
8
+ // ─── Context ─────────────────────────────────────────────────────────────────
9
+
10
+ const DbContext = createContext<DbAdapter | null>(null)
11
+
12
+ // ─── Provider ────────────────────────────────────────────────────────────────
13
+
14
+ export interface DbProviderProps {
15
+ adapter: DbAdapter
16
+ children: ReactNode
17
+ }
18
+
19
+ /**
20
+ * Provides a DbAdapter instance to all child components via React context.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * import { DbProvider } from '@geenius/db/react'
25
+ * import { createConvexDbAdapter } from '@geenius/db'
26
+ *
27
+ * function App() {
28
+ * const db = createConvexDbAdapter({ client: convex, functions: myFns })
29
+ * return (
30
+ * <DbProvider adapter={db}>
31
+ * <Router />
32
+ * </DbProvider>
33
+ * )
34
+ * }
35
+ * ```
36
+ */
37
+ export function DbProvider({ adapter, children }: DbProviderProps) {
38
+ const value = useMemo(() => adapter, [adapter])
39
+ return <DbContext.Provider value={value}>{children}</DbContext.Provider>
40
+ }
41
+
42
+ // ─── Hooks ───────────────────────────────────────────────────────────────────
43
+
44
+ /**
45
+ * Access the DbAdapter from context.
46
+ *
47
+ * @throws Error if used outside of a `<DbProvider>`
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * function UserList() {
52
+ * const db = useDb()
53
+ * const [users, setUsers] = useState([])
54
+ *
55
+ * useEffect(() => {
56
+ * db.list('users').then(setUsers)
57
+ * }, [db])
58
+ * }
59
+ * ```
60
+ */
61
+ export function useDb(): DbAdapter {
62
+ const ctx = useContext(DbContext)
63
+ if (!ctx) {
64
+ throw new Error(
65
+ '[@geenius/db] useDb() must be used inside a <DbProvider>. '
66
+ + 'Wrap your app with <DbProvider adapter={...}>.',
67
+ )
68
+ }
69
+ return ctx
70
+ }
71
+
72
+ /**
73
+ * Access the DbAdapter from context, returning null if not available.
74
+ * Useful for optional DB access in shared components.
75
+ */
76
+ export function useDbOptional(): DbAdapter | null {
77
+ return useContext(DbContext)
78
+ }
79
+
80
+ // ─── Re-exports ──────────────────────────────────────────────────────────────
81
+
82
+ export type { DbAdapter } from '@geenius/adapters-shared'
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "ignoreDeprecations": "6.0",
5
+ "outDir": "dist",
6
+ "rootDir": "src",
7
+ "jsx": "react-jsx"
8
+ },
9
+ "include": ["src"]
10
+ }
@@ -0,0 +1,17 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: { index: 'src/index.tsx' },
5
+ outDir: 'dist',
6
+ format: ['esm'],
7
+ dts: true,
8
+ sourcemap: true,
9
+ clean: true,
10
+ treeshake: true,
11
+ external: [
12
+ '@geenius/adapters-shared',
13
+ '@geenius/db-shared',
14
+ 'react',
15
+ 'react/jsx-runtime',
16
+ ],
17
+ })
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@geenius/db-shared",
3
+ "version": "0.2.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Geenius DB — Database provider implementations (Convex, Supabase, Neon, MongoDB, CloudflareKV)",
7
+ "author": "Antigravity HQ",
8
+ "license": "MIT",
9
+ "publishConfig": {
10
+ "access": "restricted"
11
+ },
12
+ "main": "./dist/index.js",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "clean": "rm -rf dist",
28
+ "type-check": "tsc --noEmit",
29
+ "prepublishOnly": "pnpm clean && pnpm build",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "test:coverage": "vitest run --coverage"
33
+ },
34
+ "peerDependencies": {
35
+ "@geenius/adapters-shared": ">=0.2.0"
36
+ },
37
+ "peerDependenciesMeta": {
38
+ "@geenius/adapters-shared": {
39
+ "optional": false
40
+ }
41
+ },
42
+ "devDependencies": {
43
+ "@geenius/adapters-shared": "link:../../../geenius-adapters/packages/shared",
44
+ "@neondatabase/serverless": "^1.0.2",
45
+ "@supabase/supabase-js": "^2.101.1",
46
+ "convex": "^1.34.1",
47
+ "mongodb": "^7.1.1",
48
+ "tsup": "^8.5.1",
49
+ "typescript": "~6.0.2",
50
+ "vitest": "^4.0.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=20.0.0"
54
+ }
55
+ }
@@ -0,0 +1,42 @@
1
+ // @geenius/db-shared — src/index.ts
2
+ //
3
+ // Database provider implementations for the Geenius ecosystem.
4
+ // All providers implement the DbAdapter interface from @geenius/adapters-shared.
5
+ //
6
+ // Usage:
7
+ // import { createConvexDbAdapter } from '@geenius/db'
8
+ // import { createSupabaseDbAdapter } from '@geenius/db'
9
+ // import type { DbAdapter } from '@geenius/adapters-shared'
10
+
11
+ // ─── Re-export DbAdapter interface from @geenius/adapters-shared ─────────────
12
+ // Consumers can import the interface directly from this package for convenience.
13
+
14
+ export type {
15
+ DbAdapter,
16
+ ListOptions,
17
+ QueryOperator,
18
+ QueryCondition,
19
+ QueryFilter,
20
+ } from '@geenius/adapters-shared'
21
+
22
+ export { DbError } from '@geenius/adapters-shared'
23
+ export type { DbErrorCode } from '@geenius/adapters-shared'
24
+
25
+ // ─── Provider Implementations ────────────────────────────────────────────────
26
+
27
+ export { createConvexDbAdapter } from './providers/convex'
28
+ export type { ConvexDbAdapterOptions } from './providers/convex'
29
+
30
+ export { createSupabaseDbAdapter } from './providers/supabase'
31
+ export type { SupabaseDbAdapterOptions } from './providers/supabase'
32
+
33
+ export { createNeonDbAdapter } from './providers/neon'
34
+ export type { NeonDbAdapterOptions, DrizzleOperators } from './providers/neon'
35
+
36
+ export { createMongoDbAdapter } from './providers/mongodb'
37
+ export type { MongoDbAdapterOptions } from './providers/mongodb'
38
+
39
+ export { createCloudflareKVDbAdapter } from './providers/cloudflareKV'
40
+ export type { KVNamespaceLike } from './providers/cloudflareKV'
41
+
42
+ export { createMemoryDbAdapter } from './providers/memory'
@@ -0,0 +1,110 @@
1
+ // @geenius/adapters — Cloudflare KV DB implementation
2
+
3
+ import type { ListOptions, QueryFilter, QueryCondition } from '@geenius/adapters-shared'
4
+ import type { DbAdapter } from '@geenius/adapters-shared'
5
+ import { DbError } from '@geenius/adapters-shared'
6
+
7
+ // Generic typing for the global KVNamespace if @cloudflare/workers-types isn't explicitly imported
8
+ export interface KVNamespaceLike {
9
+ get(key: string, type: 'json'): Promise<unknown>
10
+ put(key: string, value: string): Promise<void>
11
+ }
12
+
13
+ const DB_PREFIX = 'geenius_db_'
14
+
15
+ function matchesCondition(item: Record<string, unknown>, cond: QueryCondition): boolean {
16
+ const val = item[cond.field]
17
+ switch (cond.operator) {
18
+ case 'eq': return val === cond.value
19
+ case 'neq': return val !== cond.value
20
+ case 'gt': return (val as number) > (cond.value as number)
21
+ case 'gte': return (val as number) >= (cond.value as number)
22
+ case 'lt': return (val as number) < (cond.value as number)
23
+ case 'lte': return (val as number) <= (cond.value as number)
24
+ case 'in': return Array.isArray(cond.value) && cond.value.includes(val)
25
+ case 'contains': return typeof val === 'string' && val.includes(cond.value as string)
26
+ default: return false
27
+ }
28
+ }
29
+
30
+ function matchesFilter(item: Record<string, unknown>, filter: QueryFilter): boolean {
31
+ return filter.every(cond => matchesCondition(item, cond))
32
+ }
33
+
34
+ export function createCloudflareKVDbAdapter(kv: KVNamespaceLike): DbAdapter {
35
+ async function getCollection(collection: string): Promise<Record<string, unknown>[]> {
36
+ try {
37
+ const data = await kv.get(DB_PREFIX + collection, 'json')
38
+ return (data as Record<string, unknown>[]) || []
39
+ } catch (err) {
40
+ throw new DbError(`Failed to read collection "${collection}" from KV`, 'CONNECTION_ERROR', err)
41
+ }
42
+ }
43
+
44
+ async function saveCollection(collection: string, data: Record<string, unknown>[]): Promise<void> {
45
+ try {
46
+ await kv.put(DB_PREFIX + collection, JSON.stringify(data))
47
+ } catch (err) {
48
+ throw new DbError(`Failed to write collection "${collection}" to KV`, 'CONNECTION_ERROR', err)
49
+ }
50
+ }
51
+
52
+ return {
53
+ async create<T extends Record<string, unknown>>(collection: string, data: Omit<T, 'id'>) {
54
+ const items = await getCollection(collection)
55
+ const item = { ...data, id: crypto.randomUUID() }
56
+ items.push(item)
57
+ await saveCollection(collection, items)
58
+ return item as T & { id: string }
59
+ },
60
+
61
+ async get<T>(collection: string, id: string) {
62
+ const items = await getCollection(collection)
63
+ const found = items.find(item => item.id === id)
64
+ return (found as T | undefined) ?? null
65
+ },
66
+
67
+ async update<T extends Record<string, unknown>>(collection: string, id: string, data: Partial<T>) {
68
+ const items = await getCollection(collection)
69
+ const idx = items.findIndex(item => item.id === id)
70
+ if (idx === -1) return null
71
+ Object.assign(items[idx], data)
72
+ await saveCollection(collection, items)
73
+ return items[idx] as T | null
74
+ },
75
+
76
+ async delete(collection: string, id: string) {
77
+ const items = await getCollection(collection)
78
+ const idx = items.findIndex(item => item.id === id)
79
+ if (idx === -1) return false
80
+ items.splice(idx, 1)
81
+ await saveCollection(collection, items)
82
+ return true
83
+ },
84
+
85
+ async list<T>(collection: string, options?: ListOptions) {
86
+ let items = await getCollection(collection)
87
+ if (options?.orderBy) {
88
+ const dir = options.order === 'desc' ? -1 : 1
89
+ items.sort((a, b) => {
90
+ const av = a[options.orderBy!] as string | number, bv = b[options.orderBy!] as string | number
91
+ return av < bv ? -dir : av > bv ? dir : 0
92
+ })
93
+ }
94
+ if (options?.offset) items = items.slice(options.offset)
95
+ if (options?.limit) items = items.slice(0, options.limit)
96
+ return items as T[]
97
+ },
98
+
99
+ async query<T>(collection: string, filter: QueryFilter) {
100
+ const items = await getCollection(collection)
101
+ return items.filter(item => matchesFilter(item, filter)) as T[]
102
+ },
103
+
104
+ async count(collection: string, filter?: QueryFilter) {
105
+ const items = await getCollection(collection)
106
+ if (!filter || filter.length === 0) return items.length
107
+ return items.filter(item => matchesFilter(item, filter)).length
108
+ },
109
+ }
110
+ }