hazo_connect 2.2.0 → 2.3.2
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 +21 -0
- package/README.md +563 -0
- package/dist/adapters/sqlite-adapter.d.ts.map +1 -1
- package/dist/adapters/sqlite-adapter.js +37 -2
- package/dist/adapters/sqlite-adapter.js.map +1 -1
- package/dist/factory.d.ts +1 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +51 -9
- package/dist/factory.js.map +1 -1
- package/dist/nextjs/index.d.ts +2 -0
- package/dist/nextjs/index.d.ts.map +1 -1
- package/dist/nextjs/index.js +10 -1
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/route-setup.d.ts +46 -0
- package/dist/nextjs/route-setup.d.ts.map +1 -0
- package/dist/nextjs/route-setup.js +141 -0
- package/dist/nextjs/route-setup.js.map +1 -0
- package/dist/nextjs/setup-helpers.d.ts +86 -0
- package/dist/nextjs/setup-helpers.d.ts.map +1 -0
- package/dist/nextjs/setup-helpers.js +174 -0
- package/dist/nextjs/setup-helpers.js.map +1 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +7 -1
- package/dist/server/index.js.map +1 -1
- package/dist/sqlite/admin-service.d.ts +8 -0
- package/dist/sqlite/admin-service.d.ts.map +1 -1
- package/dist/sqlite/admin-service.js +39 -1
- package/dist/sqlite/admin-service.js.map +1 -1
- package/dist/utils/config-validator.d.ts +39 -0
- package/dist/utils/config-validator.d.ts.map +1 -0
- package/dist/utils/config-validator.js +78 -0
- package/dist/utils/config-validator.js.map +1 -0
- package/docs/examples/nextjs-admin-ui-setup.ts +199 -0
- package/docs/examples/nextjs-api-route.ts +205 -0
- package/docs/examples/nextjs-crud-service.ts +257 -0
- package/docs/examples/nextjs-server-component.tsx +123 -0
- package/docs/examples/nextjs-singleton-pattern.ts +166 -0
- package/docs/migration-guide.md +272 -0
- package/docs/nextjs-setup.md +471 -0
- package/docs/techdoc.md +824 -0
- package/docs/troubleshooting.md +442 -0
- package/docs/types.md +490 -0
- package/package.json +16 -4
- package/scripts/postinstall-setup.js +72 -0
- package/scripts/setup-routes.js +123 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Singleton Pattern for hazo_connect in Next.js
|
|
3
|
+
*
|
|
4
|
+
* This example shows how to use a singleton pattern to share
|
|
5
|
+
* a single hazo_connect instance across multiple API routes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Step 1: Create singleton instance
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
// lib/hazo_connect.ts
|
|
13
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup'
|
|
14
|
+
import type { HazoConnectAdapter } from 'hazo_connect/server'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the singleton hazo_connect adapter instance
|
|
18
|
+
*
|
|
19
|
+
* This instance is created on first call and reused for all subsequent calls.
|
|
20
|
+
* Thread-safe for Next.js serverless environment.
|
|
21
|
+
*/
|
|
22
|
+
export const hazo: HazoConnectAdapter = getHazoConnectSingleton()
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Step 2: Use singleton in API routes
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
// app/api/users/route.ts
|
|
29
|
+
import { NextResponse } from 'next/server'
|
|
30
|
+
import { hazo } from '@/lib/hazo_connect'
|
|
31
|
+
import { QueryBuilder } from 'hazo_connect/server'
|
|
32
|
+
|
|
33
|
+
export async function GET() {
|
|
34
|
+
try {
|
|
35
|
+
// Use the shared singleton instance
|
|
36
|
+
const users = await hazo.query(
|
|
37
|
+
new QueryBuilder()
|
|
38
|
+
.from('users')
|
|
39
|
+
.select('*')
|
|
40
|
+
.order('name', 'asc')
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
return NextResponse.json({ data: users })
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return NextResponse.json(
|
|
46
|
+
{ error: error instanceof Error ? error.message : 'Unknown error' },
|
|
47
|
+
{ status: 500 }
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// app/api/posts/route.ts
|
|
53
|
+
import { NextResponse } from 'next/server'
|
|
54
|
+
import { hazo } from '@/lib/hazo_connect'
|
|
55
|
+
import { QueryBuilder } from 'hazo_connect/server'
|
|
56
|
+
|
|
57
|
+
export async function GET() {
|
|
58
|
+
try {
|
|
59
|
+
// Same singleton instance, different query
|
|
60
|
+
const posts = await hazo.query(
|
|
61
|
+
new QueryBuilder()
|
|
62
|
+
.from('posts')
|
|
63
|
+
.select('*')
|
|
64
|
+
.order('created_at', 'desc')
|
|
65
|
+
.limit(10)
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
return NextResponse.json({ data: posts })
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return NextResponse.json(
|
|
71
|
+
{ error: error instanceof Error ? error.message : 'Unknown error' },
|
|
72
|
+
{ status: 500 }
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// app/api/comments/route.ts
|
|
78
|
+
import { NextRequest, NextResponse } from 'next/server'
|
|
79
|
+
import { hazo } from '@/lib/hazo_connect'
|
|
80
|
+
import { QueryBuilder } from 'hazo_connect/server'
|
|
81
|
+
|
|
82
|
+
export async function GET(request: NextRequest) {
|
|
83
|
+
try {
|
|
84
|
+
const { searchParams } = new URL(request.url)
|
|
85
|
+
const postId = searchParams.get('post_id')
|
|
86
|
+
|
|
87
|
+
let builder = new QueryBuilder()
|
|
88
|
+
.from('comments')
|
|
89
|
+
.select('*')
|
|
90
|
+
|
|
91
|
+
if (postId) {
|
|
92
|
+
builder = builder.where('post_id', 'eq', postId)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Same singleton instance, filtered query
|
|
96
|
+
const comments = await hazo.query(builder)
|
|
97
|
+
|
|
98
|
+
return NextResponse.json({ data: comments })
|
|
99
|
+
} catch (error) {
|
|
100
|
+
return NextResponse.json(
|
|
101
|
+
{ error: error instanceof Error ? error.message : 'Unknown error' },
|
|
102
|
+
{ status: 500 }
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ============================================================================
|
|
108
|
+
// Alternative: Manual Singleton Pattern
|
|
109
|
+
// ============================================================================
|
|
110
|
+
|
|
111
|
+
// lib/hazo_connect-manual.ts
|
|
112
|
+
import { createHazoConnect } from 'hazo_connect/server'
|
|
113
|
+
import type { HazoConnectAdapter } from 'hazo_connect/server'
|
|
114
|
+
import path from 'path'
|
|
115
|
+
|
|
116
|
+
let hazoInstance: HazoConnectAdapter | null = null
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get or create the singleton hazo_connect adapter instance
|
|
120
|
+
*/
|
|
121
|
+
export function getHazoConnect(): HazoConnectAdapter {
|
|
122
|
+
if (!hazoInstance) {
|
|
123
|
+
hazoInstance = createHazoConnect({
|
|
124
|
+
type: 'sqlite',
|
|
125
|
+
sqlite: {
|
|
126
|
+
database_path: process.env.HAZO_CONNECT_SQLITE_PATH
|
|
127
|
+
? path.resolve(process.env.HAZO_CONNECT_SQLITE_PATH)
|
|
128
|
+
: path.resolve(process.cwd(), 'database.sqlite'),
|
|
129
|
+
read_only: process.env.HAZO_CONNECT_SQLITE_READONLY === 'true'
|
|
130
|
+
},
|
|
131
|
+
enable_admin_ui: process.env.HAZO_CONNECT_ENABLE_ADMIN_UI === 'true'
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return hazoInstance
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Reset the singleton (useful for testing)
|
|
140
|
+
*/
|
|
141
|
+
export function resetHazoConnect(): void {
|
|
142
|
+
hazoInstance = null
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Usage:
|
|
146
|
+
// import { getHazoConnect } from '@/lib/hazo_connect-manual'
|
|
147
|
+
// const hazo = getHazoConnect()
|
|
148
|
+
|
|
149
|
+
// ============================================================================
|
|
150
|
+
// Benefits of Singleton Pattern
|
|
151
|
+
// ============================================================================
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Benefits:
|
|
155
|
+
*
|
|
156
|
+
* 1. Single database connection shared across all API routes
|
|
157
|
+
* 2. Reduced memory usage (one instance instead of many)
|
|
158
|
+
* 3. Faster response times (no connection overhead per request)
|
|
159
|
+
* 4. Thread-safe in Next.js serverless environment
|
|
160
|
+
* 5. Configuration is centralized in one place
|
|
161
|
+
*
|
|
162
|
+
* Note: The singleton is automatically created on first use and
|
|
163
|
+
* reused for all subsequent calls. If configuration changes,
|
|
164
|
+
* a new instance will be created automatically.
|
|
165
|
+
*/
|
|
166
|
+
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Migration Guide for hazo_connect
|
|
2
|
+
|
|
3
|
+
This guide helps you migrate existing code to use the new server-side entry points and patterns.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [From Old Import Paths](#from-old-import-paths)
|
|
8
|
+
- [From Client-Side to Server-Side](#from-client-side-to-server-side)
|
|
9
|
+
- [From Direct Calls to API Routes](#from-direct-calls-to-api-routes)
|
|
10
|
+
- [Testing Considerations](#testing-considerations)
|
|
11
|
+
|
|
12
|
+
## From Old Import Paths
|
|
13
|
+
|
|
14
|
+
### Before (Old Import)
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { createHazoConnect, QueryBuilder } from 'hazo_connect'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### After (New Import)
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// For server-side code (API routes, Server Components, Server Actions)
|
|
24
|
+
import { createHazoConnect, QueryBuilder } from 'hazo_connect/server'
|
|
25
|
+
|
|
26
|
+
// For types in client components
|
|
27
|
+
import type { HazoConnectConfig, HazoConnectAdapter } from 'hazo_connect'
|
|
28
|
+
import type { TableSummary } from 'hazo_connect/ui'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Migration Steps
|
|
32
|
+
|
|
33
|
+
1. **Find all imports** of `hazo_connect` in your codebase
|
|
34
|
+
2. **Replace server-side imports** with `hazo_connect/server`
|
|
35
|
+
3. **Replace type imports** in client components with `hazo_connect` or `hazo_connect/ui`
|
|
36
|
+
4. **Update test files** to use `hazo_connect/server`
|
|
37
|
+
|
|
38
|
+
## From Client-Side to Server-Side
|
|
39
|
+
|
|
40
|
+
### Before (Client Component - Won't Work)
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
'use client'
|
|
44
|
+
|
|
45
|
+
import { createHazoConnect } from 'hazo_connect' // ❌ Old import
|
|
46
|
+
|
|
47
|
+
export function MyComponent() {
|
|
48
|
+
const [data, setData] = useState([])
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const hazo = createHazoConnect({ ... })
|
|
52
|
+
hazo.query(...).then(setData)
|
|
53
|
+
}, [])
|
|
54
|
+
|
|
55
|
+
return <div>{/* render data */}</div>
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### After (Client Component - Correct Pattern)
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
'use client'
|
|
63
|
+
|
|
64
|
+
export function MyComponent() {
|
|
65
|
+
const [data, setData] = useState([])
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
// Fetch from API route instead
|
|
69
|
+
fetch('/api/data')
|
|
70
|
+
.then(res => res.json())
|
|
71
|
+
.then(json => setData(json.data))
|
|
72
|
+
}, [])
|
|
73
|
+
|
|
74
|
+
return <div>{/* render data */}</div>
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// app/api/data/route.ts
|
|
80
|
+
import { createHazoConnect } from 'hazo_connect/server'
|
|
81
|
+
import { QueryBuilder } from 'hazo_connect/server'
|
|
82
|
+
|
|
83
|
+
export async function GET() {
|
|
84
|
+
const hazo = createHazoConnect({ ... })
|
|
85
|
+
const data = await hazo.query(new QueryBuilder().from('table'))
|
|
86
|
+
return NextResponse.json({ data })
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## From Direct Calls to API Routes
|
|
91
|
+
|
|
92
|
+
### Before (Direct Call in Server Component)
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// app/users/page.tsx
|
|
96
|
+
import { createHazoConnect } from 'hazo_connect' // ❌ Old import
|
|
97
|
+
|
|
98
|
+
export default async function UsersPage() {
|
|
99
|
+
const hazo = createHazoConnect({ ... })
|
|
100
|
+
const users = await hazo.query(...)
|
|
101
|
+
|
|
102
|
+
return <div>{/* render users */}</div>
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### After (Fetch from API Route)
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// app/users/page.tsx
|
|
110
|
+
import { headers } from 'next/headers'
|
|
111
|
+
|
|
112
|
+
export default async function UsersPage() {
|
|
113
|
+
const headersList = await headers()
|
|
114
|
+
const host = headersList.get('host') || 'localhost:3000'
|
|
115
|
+
|
|
116
|
+
const response = await fetch(`http://${host}/api/users`, {
|
|
117
|
+
cache: 'no-store'
|
|
118
|
+
})
|
|
119
|
+
const { data: users } = await response.json()
|
|
120
|
+
|
|
121
|
+
return <div>{/* render users */}</div>
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// app/api/users/route.ts
|
|
127
|
+
import { createHazoConnect } from 'hazo_connect/server'
|
|
128
|
+
import { QueryBuilder } from 'hazo_connect/server'
|
|
129
|
+
|
|
130
|
+
export async function GET() {
|
|
131
|
+
const hazo = createHazoConnect({ ... })
|
|
132
|
+
const users = await hazo.query(new QueryBuilder().from('users'))
|
|
133
|
+
return NextResponse.json({ data: users })
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Testing Considerations
|
|
138
|
+
|
|
139
|
+
### Unit Tests
|
|
140
|
+
|
|
141
|
+
Update test imports:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Before
|
|
145
|
+
import { createHazoConnect } from 'hazo_connect'
|
|
146
|
+
|
|
147
|
+
// After
|
|
148
|
+
import { createHazoConnect } from 'hazo_connect/server'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Integration Tests
|
|
152
|
+
|
|
153
|
+
No changes needed - integration tests already use relative imports:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// tests/integration/test.ts
|
|
157
|
+
import { createHazoConnect } from '../../src/lib/factory' // ✅ Still works
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Mocking in Tests
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// tests/setup.ts
|
|
164
|
+
import { resetHazoConnectSingleton } from 'hazo_connect/nextjs/setup'
|
|
165
|
+
|
|
166
|
+
beforeEach(() => {
|
|
167
|
+
resetHazoConnectSingleton() // Reset singleton between tests
|
|
168
|
+
})
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Common Migration Patterns
|
|
172
|
+
|
|
173
|
+
### Pattern 1: API Route Migration
|
|
174
|
+
|
|
175
|
+
**Before:**
|
|
176
|
+
```typescript
|
|
177
|
+
// pages/api/users.ts (Pages Router)
|
|
178
|
+
import { createHazoConnect } from 'hazo_connect'
|
|
179
|
+
|
|
180
|
+
export default async function handler(req, res) {
|
|
181
|
+
const hazo = createHazoConnect({ ... })
|
|
182
|
+
const users = await hazo.query(...)
|
|
183
|
+
res.json({ data: users })
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**After:**
|
|
188
|
+
```typescript
|
|
189
|
+
// app/api/users/route.ts (App Router)
|
|
190
|
+
import { createHazoConnect } from 'hazo_connect/server'
|
|
191
|
+
import { QueryBuilder } from 'hazo_connect/server'
|
|
192
|
+
import { NextResponse } from 'next/server'
|
|
193
|
+
|
|
194
|
+
export async function GET() {
|
|
195
|
+
const hazo = createHazoConnect({ ... })
|
|
196
|
+
const users = await hazo.query(new QueryBuilder().from('users'))
|
|
197
|
+
return NextResponse.json({ data: users })
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Pattern 2: Server Component Migration
|
|
202
|
+
|
|
203
|
+
**Before:**
|
|
204
|
+
```typescript
|
|
205
|
+
// components/UsersList.tsx
|
|
206
|
+
import { createHazoConnect } from 'hazo_connect'
|
|
207
|
+
|
|
208
|
+
export async function UsersList() {
|
|
209
|
+
const hazo = createHazoConnect({ ... })
|
|
210
|
+
const users = await hazo.query(...)
|
|
211
|
+
return <ul>{/* render */}</ul>
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**After:**
|
|
216
|
+
```typescript
|
|
217
|
+
// app/users/page.tsx
|
|
218
|
+
import { headers } from 'next/headers'
|
|
219
|
+
|
|
220
|
+
export default async function UsersPage() {
|
|
221
|
+
const headersList = await headers()
|
|
222
|
+
const host = headersList.get('host') || 'localhost:3000'
|
|
223
|
+
const response = await fetch(`http://${host}/api/users`, { cache: 'no-store' })
|
|
224
|
+
const { data: users } = await response.json()
|
|
225
|
+
return <ul>{/* render */}</ul>
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Pattern 3: Singleton Pattern Migration
|
|
230
|
+
|
|
231
|
+
**Before:**
|
|
232
|
+
```typescript
|
|
233
|
+
// Multiple API routes each creating their own instance
|
|
234
|
+
// app/api/users/route.ts
|
|
235
|
+
const hazo = createHazoConnect({ ... })
|
|
236
|
+
|
|
237
|
+
// app/api/posts/route.ts
|
|
238
|
+
const hazo = createHazoConnect({ ... }) // New instance each time
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**After:**
|
|
242
|
+
```typescript
|
|
243
|
+
// lib/hazo_connect.ts
|
|
244
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup'
|
|
245
|
+
export const hazo = getHazoConnectSingleton()
|
|
246
|
+
|
|
247
|
+
// app/api/users/route.ts
|
|
248
|
+
import { hazo } from '@/lib/hazo_connect' // Shared instance
|
|
249
|
+
|
|
250
|
+
// app/api/posts/route.ts
|
|
251
|
+
import { hazo } from '@/lib/hazo_connect' // Same shared instance
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Checklist
|
|
255
|
+
|
|
256
|
+
When migrating:
|
|
257
|
+
|
|
258
|
+
- [ ] Update all imports from `hazo_connect` to `hazo_connect/server` for runtime code
|
|
259
|
+
- [ ] Update type imports in client components to `hazo_connect` or `hazo_connect/ui`
|
|
260
|
+
- [ ] Move direct `hazo_connect` calls from Server Components to API routes
|
|
261
|
+
- [ ] Update client components to fetch from API routes instead of calling `hazo_connect`
|
|
262
|
+
- [ ] Update test files to use `hazo_connect/server`
|
|
263
|
+
- [ ] Consider using singleton pattern for multiple API routes
|
|
264
|
+
- [ ] Update Next.js configuration (see [Next.js Setup Guide](./nextjs-setup.md))
|
|
265
|
+
- [ ] Test in development and production environments
|
|
266
|
+
|
|
267
|
+
## Need Help?
|
|
268
|
+
|
|
269
|
+
- See [Troubleshooting Guide](./troubleshooting.md) for common issues
|
|
270
|
+
- See [Next.js Setup Guide](./nextjs-setup.md) for configuration
|
|
271
|
+
- See [Code Examples](./examples/) for working patterns
|
|
272
|
+
|