hazo_chat 1.1.0 → 2.0.1
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/README.md +161 -152
- package/SETUP_CHECKLIST.md +191 -587
- package/dist/api/index.d.ts +24 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +24 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/messages.d.ts +34 -0
- package/dist/api/messages.d.ts.map +1 -0
- package/dist/api/messages.js +210 -0
- package/dist/api/messages.js.map +1 -0
- package/dist/api/types.d.ts +69 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +8 -0
- package/dist/api/types.js.map +1 -0
- package/dist/components/hazo_chat/hazo_chat.d.ts +13 -1
- package/dist/components/hazo_chat/hazo_chat.d.ts.map +1 -1
- package/dist/components/hazo_chat/hazo_chat.js +26 -14
- package/dist/components/hazo_chat/hazo_chat.js.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_context.d.ts +11 -5
- package/dist/components/hazo_chat/hazo_chat_context.d.ts.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_context.js +22 -10
- package/dist/components/hazo_chat/hazo_chat_context.js.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_header.d.ts +1 -1
- package/dist/components/hazo_chat/hazo_chat_header.d.ts.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_header.js +3 -3
- package/dist/components/hazo_chat/hazo_chat_header.js.map +1 -1
- package/dist/hooks/use_chat_messages.d.ts +14 -9
- package/dist/hooks/use_chat_messages.d.ts.map +1 -1
- package/dist/hooks/use_chat_messages.js +117 -115
- package/dist/hooks/use_chat_messages.js.map +1 -1
- package/dist/types/index.d.ts +39 -28
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -1
- package/package.json +17 -7
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# hazo_chat Setup Checklist
|
|
1
|
+
# hazo_chat Setup Checklist (v2.0)
|
|
2
2
|
|
|
3
3
|
A comprehensive, step-by-step guide for setting up hazo_chat in a Next.js project. This checklist is designed for both AI assistants and human developers.
|
|
4
4
|
|
|
@@ -8,15 +8,12 @@ A comprehensive, step-by-step guide for setting up hazo_chat in a Next.js projec
|
|
|
8
8
|
|
|
9
9
|
1. [Prerequisites](#1-prerequisites)
|
|
10
10
|
2. [Package Installation](#2-package-installation)
|
|
11
|
-
3. [
|
|
12
|
-
4. [
|
|
13
|
-
5. [
|
|
14
|
-
6. [
|
|
15
|
-
7. [
|
|
16
|
-
8. [
|
|
17
|
-
9. [Component Integration](#9-component-integration)
|
|
18
|
-
10. [Verification Checklist](#10-verification-checklist)
|
|
19
|
-
11. [Troubleshooting](#11-troubleshooting)
|
|
11
|
+
3. [Database Setup](#3-database-setup)
|
|
12
|
+
4. [API Routes](#4-api-routes)
|
|
13
|
+
5. [Component Integration](#5-component-integration)
|
|
14
|
+
6. [Configuration (Optional)](#6-configuration-optional)
|
|
15
|
+
7. [Verification Checklist](#7-verification-checklist)
|
|
16
|
+
8. [Troubleshooting](#8-troubleshooting)
|
|
20
17
|
|
|
21
18
|
---
|
|
22
19
|
|
|
@@ -39,111 +36,25 @@ A comprehensive, step-by-step guide for setting up hazo_chat in a Next.js projec
|
|
|
39
36
|
### Step 2.1: Install Core Packages
|
|
40
37
|
|
|
41
38
|
```bash
|
|
42
|
-
npm install hazo_chat hazo_connect
|
|
39
|
+
npm install hazo_chat hazo_connect
|
|
43
40
|
```
|
|
44
41
|
|
|
45
42
|
### Step 2.2: Install Peer Dependencies (if not already installed)
|
|
46
43
|
|
|
47
44
|
```bash
|
|
48
|
-
npm install react react-dom
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Step 2.3: Install Additional Dependencies
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
# For UUID generation (optional, if not using hazo_auth's ID generation)
|
|
55
|
-
npm install uuid
|
|
56
|
-
npm install -D @types/uuid
|
|
45
|
+
npm install react react-dom next
|
|
57
46
|
```
|
|
58
47
|
|
|
59
48
|
### Verification
|
|
60
|
-
- [ ] `package.json` contains `hazo_chat
|
|
49
|
+
- [ ] `package.json` contains `hazo_chat` and `hazo_connect`
|
|
61
50
|
- [ ] No npm installation errors
|
|
62
51
|
- [ ] `node_modules/hazo_chat` exists
|
|
63
52
|
|
|
64
53
|
---
|
|
65
54
|
|
|
66
|
-
## 3.
|
|
67
|
-
|
|
68
|
-
### Step 3.1: Create hazo_connect_config.ini
|
|
69
|
-
|
|
70
|
-
Create in project root: `hazo_connect_config.ini`
|
|
71
|
-
|
|
72
|
-
```ini
|
|
73
|
-
[database]
|
|
74
|
-
; Database type: sqlite, postgrest, supabase
|
|
75
|
-
type = sqlite
|
|
76
|
-
|
|
77
|
-
; For SQLite - path relative to project root
|
|
78
|
-
sqlite_path = ./data/app.db
|
|
79
|
-
|
|
80
|
-
; For PostgreSQL/Supabase (uncomment if using)
|
|
81
|
-
; postgrest_url = http://localhost:3000
|
|
82
|
-
; supabase_url = https://your-project.supabase.co
|
|
83
|
-
; supabase_anon_key = your-anon-key
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Step 3.2: Create hazo_auth_config.ini
|
|
87
|
-
|
|
88
|
-
Create in project root: `hazo_auth_config.ini`
|
|
55
|
+
## 3. Database Setup
|
|
89
56
|
|
|
90
|
-
|
|
91
|
-
[auth]
|
|
92
|
-
; JWT secret for token signing
|
|
93
|
-
jwt_secret = your-secure-secret-key-here
|
|
94
|
-
jwt_expiry = 7d
|
|
95
|
-
|
|
96
|
-
; Cookie settings
|
|
97
|
-
cookie_name = hazo_auth_token
|
|
98
|
-
cookie_secure = false
|
|
99
|
-
cookie_http_only = true
|
|
100
|
-
cookie_same_site = lax
|
|
101
|
-
|
|
102
|
-
[login]
|
|
103
|
-
enable_remember_me = true
|
|
104
|
-
max_login_attempts = 5
|
|
105
|
-
lockout_duration = 300
|
|
106
|
-
|
|
107
|
-
[registration]
|
|
108
|
-
enable_registration = true
|
|
109
|
-
require_email_verification = false
|
|
110
|
-
default_role = user
|
|
111
|
-
|
|
112
|
-
[ui]
|
|
113
|
-
; Visual panel image for auth pages
|
|
114
|
-
visual_panel_image = /globe.svg
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Step 3.3: Create hazo_chat_config.ini (Optional)
|
|
118
|
-
|
|
119
|
-
Create in project root: `hazo_chat_config.ini`
|
|
120
|
-
|
|
121
|
-
```ini
|
|
122
|
-
[chat]
|
|
123
|
-
; Polling interval in milliseconds (default: 5000)
|
|
124
|
-
polling_interval = 5000
|
|
125
|
-
|
|
126
|
-
; Messages to load per page (default: 20)
|
|
127
|
-
messages_per_page = 20
|
|
128
|
-
|
|
129
|
-
[uploads]
|
|
130
|
-
; Maximum file size in MB (default: 10)
|
|
131
|
-
max_file_size_mb = 10
|
|
132
|
-
|
|
133
|
-
; Allowed file extensions
|
|
134
|
-
allowed_types = pdf,png,jpg,jpeg,gif,txt,doc,docx
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Verification
|
|
138
|
-
- [ ] `hazo_connect_config.ini` exists in project root
|
|
139
|
-
- [ ] `hazo_auth_config.ini` exists in project root
|
|
140
|
-
- [ ] Database path directory exists (create `./data/` if using SQLite)
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
## 4. Database Setup
|
|
145
|
-
|
|
146
|
-
### Step 4.1: Create hazo_chat Table
|
|
57
|
+
### Step 3.1: Create hazo_chat Table
|
|
147
58
|
|
|
148
59
|
Run this SQL to create the chat messages table:
|
|
149
60
|
|
|
@@ -170,21 +81,17 @@ CREATE INDEX IF NOT EXISTS idx_hazo_chat_receiver ON hazo_chat(receiver_user_id)
|
|
|
170
81
|
CREATE INDEX IF NOT EXISTS idx_hazo_chat_created ON hazo_chat(created_at DESC);
|
|
171
82
|
```
|
|
172
83
|
|
|
173
|
-
### Step
|
|
84
|
+
### Step 3.2: Ensure Users Table Exists
|
|
174
85
|
|
|
175
|
-
|
|
86
|
+
You need a users table with at least these fields:
|
|
176
87
|
|
|
177
88
|
```sql
|
|
178
|
-
-- hazo_users table (created by hazo_auth)
|
|
179
89
|
CREATE TABLE IF NOT EXISTS hazo_users (
|
|
180
90
|
id TEXT PRIMARY KEY,
|
|
181
91
|
email_address TEXT UNIQUE NOT NULL,
|
|
182
|
-
password_hash TEXT NOT NULL,
|
|
183
92
|
name TEXT,
|
|
184
93
|
profile_picture_url TEXT,
|
|
185
|
-
profile_source TEXT DEFAULT 'default',
|
|
186
94
|
is_active INTEGER DEFAULT 1,
|
|
187
|
-
email_verified INTEGER DEFAULT 0,
|
|
188
95
|
created_at TEXT NOT NULL,
|
|
189
96
|
changed_at TEXT NOT NULL
|
|
190
97
|
);
|
|
@@ -192,313 +99,87 @@ CREATE TABLE IF NOT EXISTS hazo_users (
|
|
|
192
99
|
|
|
193
100
|
### Verification
|
|
194
101
|
- [ ] `hazo_chat` table exists in database
|
|
195
|
-
- [ ]
|
|
102
|
+
- [ ] Users table exists with at least one user
|
|
196
103
|
- [ ] Can query: `SELECT * FROM hazo_chat LIMIT 1`
|
|
197
104
|
|
|
198
105
|
---
|
|
199
106
|
|
|
200
|
-
##
|
|
201
|
-
|
|
202
|
-
### Step 5.1: Create .env.local
|
|
203
|
-
|
|
204
|
-
```env
|
|
205
|
-
# Database (if not using config.ini)
|
|
206
|
-
HAZO_CONNECT_TYPE=sqlite
|
|
207
|
-
HAZO_CONNECT_SQLITE_PATH=./data/app.db
|
|
208
|
-
|
|
209
|
-
# Auth secrets
|
|
210
|
-
HAZO_AUTH_JWT_SECRET=your-secure-secret-key-min-32-chars
|
|
211
|
-
|
|
212
|
-
# Optional: Supabase/PostgreSQL
|
|
213
|
-
# HAZO_CONNECT_POSTGREST_URL=http://localhost:3000
|
|
214
|
-
# SUPABASE_URL=https://your-project.supabase.co
|
|
215
|
-
# SUPABASE_ANON_KEY=your-anon-key
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Step 5.2: Add to .gitignore
|
|
219
|
-
|
|
220
|
-
```gitignore
|
|
221
|
-
# Environment files
|
|
222
|
-
.env
|
|
223
|
-
.env.local
|
|
224
|
-
.env.*.local
|
|
225
|
-
|
|
226
|
-
# Database files (if using SQLite)
|
|
227
|
-
*.db
|
|
228
|
-
*.sqlite
|
|
229
|
-
data/
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Verification
|
|
233
|
-
- [ ] `.env.local` exists
|
|
234
|
-
- [ ] `.env.local` is in `.gitignore`
|
|
235
|
-
- [ ] Secrets are not committed to git
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## 6. Next.js Configuration
|
|
240
|
-
|
|
241
|
-
### Step 6.1: Update next.config.js
|
|
107
|
+
## 4. API Routes
|
|
242
108
|
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Next.js Configuration with hazo_chat support
|
|
246
|
-
*/
|
|
247
|
-
|
|
248
|
-
const path = require('path');
|
|
249
|
-
|
|
250
|
-
/** @type {import('next').NextConfig} */
|
|
251
|
-
const nextConfig = {
|
|
252
|
-
// Transpile the hazo packages for ES module support
|
|
253
|
-
transpilePackages: ['hazo_chat', 'hazo_connect', 'hazo_auth'],
|
|
254
|
-
|
|
255
|
-
// Webpack configuration
|
|
256
|
-
webpack: (config, { isServer }) => {
|
|
257
|
-
// Configure module resolution
|
|
258
|
-
config.resolve.extensionAlias = {
|
|
259
|
-
'.js': ['.js', '.ts', '.tsx'],
|
|
260
|
-
'.jsx': ['.jsx', '.tsx'],
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
// Enable package exports resolution
|
|
264
|
-
config.resolve.conditionNames = ['import', 'require', 'default'];
|
|
265
|
-
|
|
266
|
-
// Server-side externals
|
|
267
|
-
if (isServer) {
|
|
268
|
-
config.externals = config.externals || [];
|
|
269
|
-
if (Array.isArray(config.externals)) {
|
|
270
|
-
config.externals.push("sql.js");
|
|
271
|
-
config.externals.push("hazo_notify");
|
|
272
|
-
}
|
|
273
|
-
}
|
|
109
|
+
Create the following API routes in your Next.js app:
|
|
274
110
|
|
|
275
|
-
|
|
276
|
-
config.experiments = {
|
|
277
|
-
...(config.experiments ?? {}),
|
|
278
|
-
asyncWebAssembly: true,
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
return config;
|
|
282
|
-
},
|
|
283
|
-
|
|
284
|
-
// Experimental features
|
|
285
|
-
experimental: {
|
|
286
|
-
serverComponentsExternalPackages: [
|
|
287
|
-
"sql.js",
|
|
288
|
-
"better-sqlite3",
|
|
289
|
-
"hazo_notify",
|
|
290
|
-
],
|
|
291
|
-
},
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
module.exports = nextConfig;
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### Verification
|
|
298
|
-
- [ ] `next.config.js` includes transpilePackages
|
|
299
|
-
- [ ] Server externals configured for sql.js
|
|
300
|
-
- [ ] No build errors with `npm run build`
|
|
301
|
-
|
|
302
|
-
---
|
|
303
|
-
|
|
304
|
-
## 7. API Routes
|
|
305
|
-
|
|
306
|
-
Create the following API routes in `src/app/api/`:
|
|
307
|
-
|
|
308
|
-
### Step 7.1: Chat Messages API
|
|
111
|
+
### Step 4.1: Messages API (Using Exportable Handler)
|
|
309
112
|
|
|
310
113
|
**File: `src/app/api/hazo_chat/messages/route.ts`**
|
|
311
114
|
|
|
312
115
|
```typescript
|
|
313
116
|
/**
|
|
314
117
|
* API route for chat message operations
|
|
118
|
+
* Uses the exportable handler from hazo_chat
|
|
315
119
|
*/
|
|
316
120
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
import { NextRequest, NextResponse } from "next/server";
|
|
320
|
-
import { cookies } from "next/headers";
|
|
321
|
-
import { createCrudService } from "hazo_connect/server";
|
|
322
|
-
import { getHazoConnectSingleton } from "hazo_connect/nextjs/setup";
|
|
323
|
-
import { v4 as uuid_v4 } from "uuid";
|
|
324
|
-
|
|
325
|
-
interface ChatMessageDB {
|
|
326
|
-
id: string;
|
|
327
|
-
reference_id: string;
|
|
328
|
-
reference_type: string;
|
|
329
|
-
sender_user_id: string;
|
|
330
|
-
receiver_user_id: string;
|
|
331
|
-
message_text: string | null;
|
|
332
|
-
reference_list: string | null;
|
|
333
|
-
read_at: string | null;
|
|
334
|
-
deleted_at: string | null;
|
|
335
|
-
created_at: string;
|
|
336
|
-
changed_at: string;
|
|
337
|
-
[key: string]: unknown;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// GET - Fetch messages
|
|
341
|
-
export async function GET(request: NextRequest) {
|
|
342
|
-
try {
|
|
343
|
-
const cookieStore = cookies();
|
|
344
|
-
const current_user_id = cookieStore.get("hazo_auth_user_id")?.value;
|
|
345
|
-
|
|
346
|
-
if (!current_user_id) {
|
|
347
|
-
return NextResponse.json(
|
|
348
|
-
{ success: false, error: "Not authenticated" },
|
|
349
|
-
{ status: 401 }
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const { searchParams } = new URL(request.url);
|
|
354
|
-
const receiver_user_id = searchParams.get("receiver_user_id");
|
|
355
|
-
const reference_id = searchParams.get("reference_id");
|
|
356
|
-
const reference_type = searchParams.get("reference_type");
|
|
357
|
-
|
|
358
|
-
if (!receiver_user_id) {
|
|
359
|
-
return NextResponse.json(
|
|
360
|
-
{ success: false, error: "receiver_user_id is required" },
|
|
361
|
-
{ status: 400 }
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const hazoConnect = getHazoConnectSingleton();
|
|
366
|
-
const chatService = createCrudService<ChatMessageDB>(hazoConnect, "hazo_chat");
|
|
367
|
-
|
|
368
|
-
const messages = await chatService.list((query) => {
|
|
369
|
-
let filteredQuery = query.whereOr([
|
|
370
|
-
{ field: "sender_user_id", operator: "eq", value: current_user_id },
|
|
371
|
-
{ field: "receiver_user_id", operator: "eq", value: current_user_id },
|
|
372
|
-
]);
|
|
373
|
-
|
|
374
|
-
if (reference_id) {
|
|
375
|
-
filteredQuery = filteredQuery.where("reference_id", "eq", reference_id);
|
|
376
|
-
}
|
|
377
|
-
if (reference_type) {
|
|
378
|
-
filteredQuery = filteredQuery.where("reference_type", "eq", reference_type);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return filteredQuery.order("created_at", "asc");
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
return NextResponse.json({
|
|
385
|
-
success: true,
|
|
386
|
-
messages: messages || [],
|
|
387
|
-
current_user_id,
|
|
388
|
-
});
|
|
389
|
-
} catch (error) {
|
|
390
|
-
console.error("[hazo_chat/messages GET] Error:", error);
|
|
391
|
-
return NextResponse.json(
|
|
392
|
-
{ success: false, error: "Failed to fetch messages" },
|
|
393
|
-
{ status: 500 }
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// POST - Create message
|
|
399
|
-
export async function POST(request: NextRequest) {
|
|
400
|
-
try {
|
|
401
|
-
const cookieStore = cookies();
|
|
402
|
-
const sender_user_id = cookieStore.get("hazo_auth_user_id")?.value;
|
|
121
|
+
import { createMessagesHandler } from 'hazo_chat/api';
|
|
122
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
403
123
|
|
|
404
|
-
|
|
405
|
-
return NextResponse.json(
|
|
406
|
-
{ success: false, error: "Not authenticated" },
|
|
407
|
-
{ status: 401 }
|
|
408
|
-
);
|
|
409
|
-
}
|
|
124
|
+
export const dynamic = 'force-dynamic';
|
|
410
125
|
|
|
411
|
-
|
|
412
|
-
|
|
126
|
+
const { GET, POST } = createMessagesHandler({
|
|
127
|
+
getHazoConnect: () => getHazoConnectSingleton()
|
|
128
|
+
});
|
|
413
129
|
|
|
414
|
-
|
|
415
|
-
return NextResponse.json(
|
|
416
|
-
{ success: false, error: "receiver_user_id and message_text are required" },
|
|
417
|
-
{ status: 400 }
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
const hazoConnect = getHazoConnectSingleton();
|
|
422
|
-
const chatService = createCrudService<ChatMessageDB>(hazoConnect, "hazo_chat");
|
|
423
|
-
|
|
424
|
-
const message_id = uuid_v4();
|
|
425
|
-
const now = new Date().toISOString();
|
|
426
|
-
|
|
427
|
-
const message_record: ChatMessageDB = {
|
|
428
|
-
id: message_id,
|
|
429
|
-
reference_id: reference_id || message_id,
|
|
430
|
-
reference_type: reference_type || "chat",
|
|
431
|
-
sender_user_id,
|
|
432
|
-
receiver_user_id,
|
|
433
|
-
message_text: message_text.trim(),
|
|
434
|
-
reference_list: reference_list ? JSON.stringify(reference_list) : null,
|
|
435
|
-
read_at: null,
|
|
436
|
-
deleted_at: null,
|
|
437
|
-
created_at: now,
|
|
438
|
-
changed_at: now,
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
await chatService.insert(message_record);
|
|
442
|
-
|
|
443
|
-
return NextResponse.json({
|
|
444
|
-
success: true,
|
|
445
|
-
message: message_record,
|
|
446
|
-
});
|
|
447
|
-
} catch (error) {
|
|
448
|
-
console.error("[hazo_chat/messages POST] Error:", error);
|
|
449
|
-
return NextResponse.json(
|
|
450
|
-
{ success: false, error: "Failed to send message" },
|
|
451
|
-
{ status: 500 }
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
130
|
+
export { GET, POST };
|
|
455
131
|
```
|
|
456
132
|
|
|
457
|
-
### Step
|
|
133
|
+
### Step 4.2: Auth Me API
|
|
458
134
|
|
|
459
135
|
**File: `src/app/api/hazo_auth/me/route.ts`**
|
|
460
136
|
|
|
461
137
|
```typescript
|
|
462
138
|
/**
|
|
463
139
|
* API route to get current authenticated user
|
|
140
|
+
* Adapt this to your authentication system
|
|
464
141
|
*/
|
|
465
142
|
|
|
466
|
-
export const dynamic =
|
|
143
|
+
export const dynamic = 'force-dynamic';
|
|
467
144
|
|
|
468
|
-
import { NextRequest, NextResponse } from
|
|
469
|
-
import {
|
|
145
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
146
|
+
import { cookies } from 'next/headers';
|
|
470
147
|
|
|
471
148
|
export async function GET(request: NextRequest) {
|
|
472
149
|
try {
|
|
473
|
-
const
|
|
150
|
+
const cookieStore = cookies();
|
|
151
|
+
const user_id = cookieStore.get('hazo_auth_user_id')?.value;
|
|
474
152
|
|
|
475
|
-
if (!
|
|
153
|
+
if (!user_id) {
|
|
476
154
|
return NextResponse.json({
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
email: null,
|
|
155
|
+
authenticated: false,
|
|
156
|
+
user: null
|
|
480
157
|
});
|
|
481
158
|
}
|
|
482
159
|
|
|
160
|
+
// TODO: Fetch user from your database
|
|
161
|
+
// const user = await fetchUserById(user_id);
|
|
162
|
+
|
|
483
163
|
return NextResponse.json({
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
164
|
+
authenticated: true,
|
|
165
|
+
user: {
|
|
166
|
+
id: user_id,
|
|
167
|
+
name: 'User Name', // Replace with actual user data
|
|
168
|
+
email: 'user@example.com',
|
|
169
|
+
profile_picture_url: null
|
|
170
|
+
}
|
|
489
171
|
});
|
|
490
172
|
} catch (error) {
|
|
491
|
-
console.error(
|
|
173
|
+
console.error('[hazo_auth/me] Error:', error);
|
|
492
174
|
return NextResponse.json({
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
email: null,
|
|
175
|
+
authenticated: false,
|
|
176
|
+
user: null
|
|
496
177
|
});
|
|
497
178
|
}
|
|
498
179
|
}
|
|
499
180
|
```
|
|
500
181
|
|
|
501
|
-
### Step
|
|
182
|
+
### Step 4.3: User Profiles API
|
|
502
183
|
|
|
503
184
|
**File: `src/app/api/hazo_auth/profiles/route.ts`**
|
|
504
185
|
|
|
@@ -507,18 +188,11 @@ export async function GET(request: NextRequest) {
|
|
|
507
188
|
* API route to fetch user profiles by IDs
|
|
508
189
|
*/
|
|
509
190
|
|
|
510
|
-
export const dynamic =
|
|
191
|
+
export const dynamic = 'force-dynamic';
|
|
511
192
|
|
|
512
|
-
import { NextRequest, NextResponse } from
|
|
513
|
-
import { createCrudService } from
|
|
514
|
-
import { getHazoConnectSingleton } from
|
|
515
|
-
|
|
516
|
-
interface UserProfile {
|
|
517
|
-
id: string;
|
|
518
|
-
name: string;
|
|
519
|
-
email: string;
|
|
520
|
-
avatar_url?: string;
|
|
521
|
-
}
|
|
193
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
194
|
+
import { createCrudService } from 'hazo_connect/server';
|
|
195
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
522
196
|
|
|
523
197
|
export async function POST(request: NextRequest) {
|
|
524
198
|
try {
|
|
@@ -527,299 +201,238 @@ export async function POST(request: NextRequest) {
|
|
|
527
201
|
|
|
528
202
|
if (!Array.isArray(user_ids) || user_ids.length === 0) {
|
|
529
203
|
return NextResponse.json(
|
|
530
|
-
{ success: false, error:
|
|
204
|
+
{ success: false, error: 'user_ids array is required' },
|
|
531
205
|
{ status: 400 }
|
|
532
206
|
);
|
|
533
207
|
}
|
|
534
208
|
|
|
535
209
|
const hazoConnect = getHazoConnectSingleton();
|
|
536
|
-
const usersService = createCrudService(hazoConnect,
|
|
210
|
+
const usersService = createCrudService(hazoConnect, 'hazo_users');
|
|
537
211
|
|
|
538
212
|
const users = await usersService.list((query) =>
|
|
539
|
-
query.whereIn(
|
|
213
|
+
query.whereIn('id', user_ids)
|
|
540
214
|
);
|
|
541
215
|
|
|
542
|
-
const profiles
|
|
216
|
+
const profiles = users.map((user) => ({
|
|
543
217
|
id: user.id as string,
|
|
544
|
-
name: (user.name as string) || (user.email_address as string)
|
|
218
|
+
name: (user.name as string) || (user.email_address as string)?.split('@')[0] || 'User',
|
|
545
219
|
email: user.email_address as string,
|
|
546
220
|
avatar_url: user.profile_picture_url as string | undefined,
|
|
547
221
|
}));
|
|
548
222
|
|
|
549
223
|
return NextResponse.json({ success: true, profiles });
|
|
550
224
|
} catch (error) {
|
|
551
|
-
console.error(
|
|
225
|
+
console.error('[hazo_auth/profiles] Error:', error);
|
|
552
226
|
return NextResponse.json(
|
|
553
|
-
{ success: false, error:
|
|
227
|
+
{ success: false, error: 'Failed to fetch profiles' },
|
|
554
228
|
{ status: 500 }
|
|
555
229
|
);
|
|
556
230
|
}
|
|
557
231
|
}
|
|
558
232
|
```
|
|
559
233
|
|
|
560
|
-
###
|
|
234
|
+
### API Routes Summary
|
|
561
235
|
|
|
562
|
-
|
|
236
|
+
| Endpoint | Method | File | Purpose |
|
|
237
|
+
|----------|--------|------|---------|
|
|
238
|
+
| `/api/hazo_chat/messages` | GET, POST | `api/hazo_chat/messages/route.ts` | Message CRUD |
|
|
239
|
+
| `/api/hazo_auth/me` | GET | `api/hazo_auth/me/route.ts` | Get current user |
|
|
240
|
+
| `/api/hazo_auth/profiles` | POST | `api/hazo_auth/profiles/route.ts` | Get user profiles |
|
|
563
241
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
| Users List | `api/hazo_auth/users/route.ts` | List all users |
|
|
242
|
+
### Verification
|
|
243
|
+
- [ ] All API route files exist
|
|
244
|
+
- [ ] `GET /api/hazo_auth/me` returns user data when logged in
|
|
245
|
+
- [ ] `POST /api/hazo_auth/profiles` returns profiles for given IDs
|
|
246
|
+
- [ ] `GET /api/hazo_chat/messages?receiver_user_id=xxx` works
|
|
570
247
|
|
|
571
|
-
|
|
248
|
+
---
|
|
572
249
|
|
|
573
|
-
|
|
574
|
-
- [ ] `api/hazo_chat/messages/route.ts` exists
|
|
575
|
-
- [ ] `api/hazo_auth/me/route.ts` exists
|
|
576
|
-
- [ ] `api/hazo_auth/profiles/route.ts` exists
|
|
577
|
-
- [ ] API routes return 200 when tested with curl
|
|
250
|
+
## 5. Component Integration
|
|
578
251
|
|
|
579
|
-
|
|
252
|
+
### Step 5.1: Basic Usage
|
|
580
253
|
|
|
581
|
-
|
|
254
|
+
**File: `src/app/chat/page.tsx`**
|
|
582
255
|
|
|
583
|
-
|
|
256
|
+
```typescript
|
|
257
|
+
'use client';
|
|
584
258
|
|
|
585
|
-
|
|
259
|
+
import { HazoChat } from 'hazo_chat';
|
|
586
260
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
261
|
+
export default function ChatPage() {
|
|
262
|
+
return (
|
|
263
|
+
<div className="h-screen">
|
|
264
|
+
<HazoChat
|
|
265
|
+
receiver_user_id="recipient-uuid-here"
|
|
266
|
+
title="Chat"
|
|
267
|
+
subtitle="Direct Message"
|
|
268
|
+
/>
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
595
273
|
|
|
596
|
-
|
|
274
|
+
### Step 5.2: With All Options
|
|
597
275
|
|
|
598
|
-
|
|
276
|
+
```typescript
|
|
277
|
+
'use client';
|
|
599
278
|
|
|
600
|
-
|
|
279
|
+
import { HazoChat } from 'hazo_chat';
|
|
601
280
|
|
|
602
|
-
|
|
281
|
+
export default function ChatPage() {
|
|
282
|
+
return (
|
|
283
|
+
<HazoChat
|
|
284
|
+
receiver_user_id="user-123"
|
|
285
|
+
reference_id="project-456"
|
|
286
|
+
reference_type="project_chat"
|
|
287
|
+
api_base_url="/api/hazo_chat"
|
|
288
|
+
timezone="Australia/Sydney"
|
|
289
|
+
title="Project Discussion"
|
|
290
|
+
subtitle="Design Review"
|
|
291
|
+
additional_references={[
|
|
292
|
+
{
|
|
293
|
+
id: 'doc-1',
|
|
294
|
+
type: 'document',
|
|
295
|
+
scope: 'field',
|
|
296
|
+
name: 'Design.pdf',
|
|
297
|
+
url: '/files/design.pdf'
|
|
298
|
+
}
|
|
299
|
+
]}
|
|
300
|
+
on_close={() => window.history.back()}
|
|
301
|
+
className="h-[600px]"
|
|
302
|
+
/>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
603
306
|
|
|
604
|
-
|
|
307
|
+
---
|
|
605
308
|
|
|
606
|
-
|
|
607
|
-
/**
|
|
608
|
-
* Client-side hazo_auth service wrapper
|
|
609
|
-
*/
|
|
309
|
+
## 6. Configuration (Optional)
|
|
610
310
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
export const hazo_auth_client: HazoAuthInstance = {
|
|
614
|
-
hazo_get_auth: async () => {
|
|
615
|
-
try {
|
|
616
|
-
const response = await fetch('/api/hazo_auth/me');
|
|
617
|
-
const data = await response.json();
|
|
618
|
-
|
|
619
|
-
if (data.is_authenticated) {
|
|
620
|
-
return {
|
|
621
|
-
id: data.user_id,
|
|
622
|
-
email: data.email,
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
return null;
|
|
626
|
-
} catch (error) {
|
|
627
|
-
console.error('Failed to get auth:', error);
|
|
628
|
-
return null;
|
|
629
|
-
}
|
|
630
|
-
},
|
|
311
|
+
### hazo_connect Configuration
|
|
631
312
|
|
|
632
|
-
|
|
633
|
-
try {
|
|
634
|
-
const response = await fetch('/api/hazo_auth/profiles', {
|
|
635
|
-
method: 'POST',
|
|
636
|
-
headers: { 'Content-Type': 'application/json' },
|
|
637
|
-
body: JSON.stringify({ user_ids }),
|
|
638
|
-
});
|
|
639
|
-
const data = await response.json();
|
|
640
|
-
|
|
641
|
-
if (data.success) {
|
|
642
|
-
return data.profiles;
|
|
643
|
-
}
|
|
644
|
-
return [];
|
|
645
|
-
} catch (error) {
|
|
646
|
-
console.error('Failed to get profiles:', error);
|
|
647
|
-
return [];
|
|
648
|
-
}
|
|
649
|
-
},
|
|
650
|
-
};
|
|
651
|
-
```
|
|
313
|
+
Create `hazo_connect_config.ini` in project root:
|
|
652
314
|
|
|
653
|
-
|
|
315
|
+
```ini
|
|
316
|
+
[database]
|
|
317
|
+
type = sqlite
|
|
318
|
+
sqlite_path = ./data/app.db
|
|
319
|
+
```
|
|
654
320
|
|
|
655
|
-
|
|
321
|
+
### hazo_chat Configuration
|
|
656
322
|
|
|
657
|
-
|
|
658
|
-
'use client';
|
|
323
|
+
Create `hazo_chat_config.ini` in project root (optional):
|
|
659
324
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
import { hazo_auth_client } from '@/lib/hazo_auth_client';
|
|
325
|
+
```ini
|
|
326
|
+
[chat]
|
|
327
|
+
polling_interval = 5000
|
|
328
|
+
messages_per_page = 20
|
|
665
329
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
const [recipient_id, set_recipient_id] = useState<string>('');
|
|
671
|
-
|
|
672
|
-
// Check authentication on mount
|
|
673
|
-
useEffect(() => {
|
|
674
|
-
async function check_auth() {
|
|
675
|
-
const user = await hazo_auth_client.hazo_get_auth();
|
|
676
|
-
if (!user) {
|
|
677
|
-
router.push('/hazo_auth/login');
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
set_is_authenticated(true);
|
|
681
|
-
set_is_loading(false);
|
|
682
|
-
}
|
|
683
|
-
check_auth();
|
|
684
|
-
}, [router]);
|
|
330
|
+
[uploads]
|
|
331
|
+
max_file_size_mb = 10
|
|
332
|
+
allowed_types = pdf,png,jpg,jpeg,gif
|
|
333
|
+
```
|
|
685
334
|
|
|
686
|
-
|
|
687
|
-
return <div>Loading...</div>;
|
|
688
|
-
}
|
|
335
|
+
### Next.js Configuration
|
|
689
336
|
|
|
690
|
-
|
|
691
|
-
return <div>Select a user to chat with</div>;
|
|
692
|
-
}
|
|
337
|
+
Update `next.config.js` if needed:
|
|
693
338
|
|
|
694
|
-
|
|
339
|
+
```javascript
|
|
340
|
+
/** @type {import('next').NextConfig} */
|
|
341
|
+
const nextConfig = {
|
|
342
|
+
transpilePackages: ['hazo_chat', 'hazo_connect'],
|
|
343
|
+
experimental: {
|
|
344
|
+
serverComponentsExternalPackages: ['sql.js', 'better-sqlite3'],
|
|
345
|
+
},
|
|
346
|
+
};
|
|
695
347
|
|
|
696
|
-
|
|
697
|
-
<div className="h-screen">
|
|
698
|
-
<HazoChat
|
|
699
|
-
hazo_connect={hazo_connect}
|
|
700
|
-
hazo_auth={hazo_auth_client}
|
|
701
|
-
receiver_user_id={recipient_id}
|
|
702
|
-
document_save_location="/uploads/chat"
|
|
703
|
-
reference_id={`chat-${recipient_id}`}
|
|
704
|
-
reference_type="direct_message"
|
|
705
|
-
title="Chat"
|
|
706
|
-
on_close={() => router.back()}
|
|
707
|
-
/>
|
|
708
|
-
</div>
|
|
709
|
-
);
|
|
710
|
-
}
|
|
348
|
+
module.exports = nextConfig;
|
|
711
349
|
```
|
|
712
350
|
|
|
713
351
|
---
|
|
714
352
|
|
|
715
|
-
##
|
|
353
|
+
## 7. Verification Checklist
|
|
716
354
|
|
|
717
355
|
### Installation Verification
|
|
718
356
|
- [ ] All packages installed without errors
|
|
719
357
|
- [ ] `npm run build` completes successfully
|
|
720
358
|
- [ ] No TypeScript errors
|
|
721
359
|
|
|
722
|
-
### Configuration Verification
|
|
723
|
-
- [ ] `hazo_connect_config.ini` exists and is readable
|
|
724
|
-
- [ ] Database file/connection is accessible
|
|
725
|
-
- [ ] Environment variables are set
|
|
726
|
-
|
|
727
360
|
### Database Verification
|
|
728
361
|
- [ ] `hazo_chat` table exists
|
|
729
|
-
- [ ]
|
|
362
|
+
- [ ] Users table exists with test users
|
|
730
363
|
- [ ] Can insert and query messages
|
|
731
364
|
|
|
732
365
|
### API Verification
|
|
733
366
|
|
|
734
|
-
Test with curl
|
|
367
|
+
Test with curl:
|
|
735
368
|
|
|
736
369
|
```bash
|
|
737
|
-
# Test auth endpoint
|
|
370
|
+
# Test auth endpoint (should return user data if logged in)
|
|
738
371
|
curl http://localhost:3000/api/hazo_auth/me
|
|
739
372
|
|
|
740
|
-
# Test profiles endpoint
|
|
373
|
+
# Test profiles endpoint
|
|
741
374
|
curl -X POST http://localhost:3000/api/hazo_auth/profiles \
|
|
742
375
|
-H "Content-Type: application/json" \
|
|
743
376
|
-d '{"user_ids": ["user-id-here"]}'
|
|
744
377
|
|
|
745
|
-
# Test messages endpoint
|
|
378
|
+
# Test messages endpoint
|
|
746
379
|
curl "http://localhost:3000/api/hazo_chat/messages?receiver_user_id=user-id"
|
|
747
380
|
```
|
|
748
381
|
|
|
749
|
-
Expected responses:
|
|
750
|
-
- [ ] `/api/hazo_auth/me` returns user data or `is_authenticated: false`
|
|
751
|
-
- [ ] `/api/hazo_auth/profiles` returns user profiles array
|
|
752
|
-
- [ ] `/api/hazo_chat/messages` returns messages array
|
|
753
|
-
|
|
754
382
|
### UI Verification
|
|
755
383
|
- [ ] Chat component renders without errors
|
|
384
|
+
- [ ] No "Module not found: Can't resolve 'fs'" errors
|
|
756
385
|
- [ ] Messages load and display correctly
|
|
757
386
|
- [ ] Can send new messages
|
|
758
387
|
- [ ] Messages appear in real-time (within polling interval)
|
|
759
|
-
- [ ] File upload works (if configured)
|
|
760
388
|
|
|
761
389
|
---
|
|
762
390
|
|
|
763
|
-
##
|
|
764
|
-
|
|
765
|
-
### Error: "hazo_connect.from is not a function"
|
|
766
|
-
|
|
767
|
-
**Cause:** Using wrong adapter type or import.
|
|
768
|
-
|
|
769
|
-
**Solution:**
|
|
770
|
-
```typescript
|
|
771
|
-
// Wrong
|
|
772
|
-
import hazo_connect from 'hazo_connect';
|
|
773
|
-
|
|
774
|
-
// Correct
|
|
775
|
-
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
776
|
-
const hazo_connect = getHazoConnectSingleton();
|
|
777
|
-
```
|
|
778
|
-
|
|
779
|
-
### Error: "Module not found"
|
|
391
|
+
## 8. Troubleshooting
|
|
780
392
|
|
|
781
|
-
|
|
393
|
+
### Error: "Module not found: Can't resolve 'fs'"
|
|
782
394
|
|
|
783
|
-
**
|
|
784
|
-
```javascript
|
|
785
|
-
transpilePackages: ['hazo_chat', 'hazo_connect', 'hazo_auth'],
|
|
786
|
-
```
|
|
787
|
-
|
|
788
|
-
### Error: "Hydration failed"
|
|
789
|
-
|
|
790
|
-
**Cause:** Server/client rendering mismatch.
|
|
395
|
+
**Cause:** Server-side code imported in client component.
|
|
791
396
|
|
|
792
|
-
**Solution:**
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
if (!mounted) return null;
|
|
797
|
-
```
|
|
397
|
+
**Solution:** This shouldn't happen with v2.0. Ensure:
|
|
398
|
+
1. You're using `hazo_chat` version 2.0+
|
|
399
|
+
2. You're not importing from `hazo_connect/server` in client components
|
|
400
|
+
3. API routes use server-side imports only
|
|
798
401
|
|
|
799
|
-
### Error: "
|
|
402
|
+
### Error: "401 Unauthorized"
|
|
800
403
|
|
|
801
|
-
**Cause:**
|
|
404
|
+
**Cause:** User not authenticated.
|
|
802
405
|
|
|
803
406
|
**Solution:**
|
|
804
|
-
1.
|
|
805
|
-
2.
|
|
806
|
-
3.
|
|
407
|
+
1. Check `/api/hazo_auth/me` returns authenticated user
|
|
408
|
+
2. Ensure `hazo_auth_user_id` cookie is set
|
|
409
|
+
3. Check cookie settings (httpOnly, sameSite, secure)
|
|
807
410
|
|
|
808
|
-
### Messages
|
|
411
|
+
### Error: "Messages not loading"
|
|
809
412
|
|
|
810
413
|
**Checklist:**
|
|
811
414
|
1. Is user authenticated? Check `/api/hazo_auth/me`
|
|
812
|
-
2. Is `
|
|
813
|
-
3.
|
|
814
|
-
4. Check
|
|
415
|
+
2. Is `receiver_user_id` provided?
|
|
416
|
+
3. Check browser console for errors
|
|
417
|
+
4. Check network tab for API responses
|
|
815
418
|
5. Check server logs for API errors
|
|
816
419
|
|
|
817
|
-
###
|
|
420
|
+
### Error: "Profiles not loading"
|
|
421
|
+
|
|
422
|
+
**Cause:** `/api/hazo_auth/profiles` not returning data.
|
|
423
|
+
|
|
424
|
+
**Solution:**
|
|
425
|
+
1. Check the API route exists
|
|
426
|
+
2. Verify users exist in database
|
|
427
|
+
3. Check API response format matches expected
|
|
428
|
+
|
|
429
|
+
### Error: "Polling not working"
|
|
818
430
|
|
|
819
431
|
**Checklist:**
|
|
820
432
|
1. Check network tab for `/api/hazo_chat/messages` requests
|
|
821
|
-
2. Verify
|
|
433
|
+
2. Verify polling interval (default: 5000ms)
|
|
822
434
|
3. Check for JavaScript errors in console
|
|
435
|
+
4. Verify API returns `{ success: true, messages: [] }` format
|
|
823
436
|
|
|
824
437
|
---
|
|
825
438
|
|
|
@@ -827,32 +440,23 @@ if (!mounted) return null;
|
|
|
827
440
|
|
|
828
441
|
```bash
|
|
829
442
|
# 1. Install packages
|
|
830
|
-
npm install hazo_chat hazo_connect
|
|
831
|
-
|
|
832
|
-
# 2. Create config files
|
|
833
|
-
touch hazo_connect_config.ini hazo_auth_config.ini
|
|
443
|
+
npm install hazo_chat hazo_connect
|
|
834
444
|
|
|
835
|
-
#
|
|
836
|
-
mkdir -p ./data
|
|
837
|
-
|
|
838
|
-
# 4. Create API routes
|
|
445
|
+
# 2. Create API routes
|
|
839
446
|
mkdir -p src/app/api/hazo_chat/messages
|
|
840
447
|
mkdir -p src/app/api/hazo_auth/me
|
|
841
448
|
mkdir -p src/app/api/hazo_auth/profiles
|
|
842
449
|
|
|
843
|
-
#
|
|
844
|
-
|
|
845
|
-
# 6. Run database migrations (create hazo_chat table)
|
|
450
|
+
# 3. Create database table (run SQL)
|
|
846
451
|
|
|
847
|
-
#
|
|
452
|
+
# 4. Start development server
|
|
848
453
|
npm run dev
|
|
849
454
|
|
|
850
|
-
#
|
|
455
|
+
# 5. Test API endpoints
|
|
851
456
|
|
|
852
|
-
#
|
|
457
|
+
# 6. Use HazoChat component
|
|
853
458
|
```
|
|
854
459
|
|
|
855
460
|
---
|
|
856
461
|
|
|
857
462
|
For more information, see the [README.md](./README.md) and [test-app](./test-app) for complete working examples.
|
|
858
|
-
|