hazo_chat 2.0.15 → 2.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 (155) hide show
  1. package/README.md +60 -8
  2. package/SETUP_CHECKLIST.md +37 -0
  3. package/dist/api/index.d.ts +26 -0
  4. package/dist/api/index.d.ts.map +1 -0
  5. package/dist/api/index.js +25 -0
  6. package/dist/api/index.js.map +1 -0
  7. package/dist/api/messages.d.ts +52 -0
  8. package/dist/api/messages.d.ts.map +1 -0
  9. package/dist/api/messages.js +330 -0
  10. package/dist/api/messages.js.map +1 -0
  11. package/dist/api/types.d.ts +69 -0
  12. package/dist/api/types.d.ts.map +1 -0
  13. package/dist/api/types.js +8 -0
  14. package/dist/api/types.js.map +1 -0
  15. package/dist/api/unread_count.d.ts +57 -0
  16. package/dist/api/unread_count.d.ts.map +1 -0
  17. package/dist/api/unread_count.js +86 -0
  18. package/dist/api/unread_count.js.map +1 -0
  19. package/dist/components/hazo_chat/hazo_chat.d.ts +28 -0
  20. package/dist/components/hazo_chat/hazo_chat.d.ts.map +1 -0
  21. package/dist/components/hazo_chat/hazo_chat.js +220 -0
  22. package/dist/components/hazo_chat/hazo_chat.js.map +1 -0
  23. package/dist/components/hazo_chat/hazo_chat_attachment_preview.d.ts +17 -0
  24. package/dist/components/hazo_chat/hazo_chat_attachment_preview.d.ts.map +1 -0
  25. package/dist/components/hazo_chat/hazo_chat_attachment_preview.js +60 -0
  26. package/dist/components/hazo_chat/hazo_chat_attachment_preview.js.map +1 -0
  27. package/dist/components/hazo_chat/hazo_chat_context.d.ts +42 -0
  28. package/dist/components/hazo_chat/hazo_chat_context.d.ts.map +1 -0
  29. package/dist/components/hazo_chat/hazo_chat_context.js +273 -0
  30. package/dist/components/hazo_chat/hazo_chat_context.js.map +1 -0
  31. package/dist/components/hazo_chat/hazo_chat_document_viewer.d.ts +15 -0
  32. package/dist/components/hazo_chat/hazo_chat_document_viewer.d.ts.map +1 -0
  33. package/dist/components/hazo_chat/hazo_chat_document_viewer.js +140 -0
  34. package/dist/components/hazo_chat/hazo_chat_document_viewer.js.map +1 -0
  35. package/dist/components/hazo_chat/hazo_chat_header.d.ts +16 -0
  36. package/dist/components/hazo_chat/hazo_chat_header.d.ts.map +1 -0
  37. package/dist/components/hazo_chat/hazo_chat_header.js +32 -0
  38. package/dist/components/hazo_chat/hazo_chat_header.js.map +1 -0
  39. package/dist/components/hazo_chat/hazo_chat_input.d.ts +16 -0
  40. package/dist/components/hazo_chat/hazo_chat_input.d.ts.map +1 -0
  41. package/dist/components/hazo_chat/hazo_chat_input.js +75 -0
  42. package/dist/components/hazo_chat/hazo_chat_input.js.map +1 -0
  43. package/dist/components/hazo_chat/hazo_chat_messages.d.ts +17 -0
  44. package/dist/components/hazo_chat/hazo_chat_messages.d.ts.map +1 -0
  45. package/dist/components/hazo_chat/hazo_chat_messages.js +215 -0
  46. package/dist/components/hazo_chat/hazo_chat_messages.js.map +1 -0
  47. package/dist/components/hazo_chat/hazo_chat_reference_list.d.ts +16 -0
  48. package/dist/components/hazo_chat/hazo_chat_reference_list.d.ts.map +1 -0
  49. package/dist/components/hazo_chat/hazo_chat_reference_list.js +59 -0
  50. package/dist/components/hazo_chat/hazo_chat_reference_list.js.map +1 -0
  51. package/dist/components/hazo_chat/hazo_chat_sidebar.d.ts +18 -0
  52. package/dist/components/hazo_chat/hazo_chat_sidebar.d.ts.map +1 -0
  53. package/dist/components/hazo_chat/hazo_chat_sidebar.js +72 -0
  54. package/dist/components/hazo_chat/hazo_chat_sidebar.js.map +1 -0
  55. package/dist/components/hazo_chat/index.d.ts +16 -0
  56. package/dist/components/hazo_chat/index.d.ts.map +1 -0
  57. package/dist/components/hazo_chat/index.js +19 -0
  58. package/dist/components/hazo_chat/index.js.map +1 -0
  59. package/dist/components/index.d.ts +9 -0
  60. package/dist/components/index.d.ts.map +1 -0
  61. package/dist/components/index.js +11 -0
  62. package/dist/components/index.js.map +1 -0
  63. package/dist/components/ui/avatar.d.ts +13 -0
  64. package/dist/components/ui/avatar.d.ts.map +1 -0
  65. package/dist/components/ui/avatar.js +28 -0
  66. package/dist/components/ui/avatar.js.map +1 -0
  67. package/dist/components/ui/badge.d.ts +16 -0
  68. package/dist/components/ui/badge.d.ts.map +1 -0
  69. package/dist/components/ui/badge.js +36 -0
  70. package/dist/components/ui/badge.js.map +1 -0
  71. package/dist/components/ui/button.d.ts +18 -0
  72. package/dist/components/ui/button.d.ts.map +1 -0
  73. package/dist/components/ui/button.js +47 -0
  74. package/dist/components/ui/button.js.map +1 -0
  75. package/dist/components/ui/chat_bubble.d.ts +18 -0
  76. package/dist/components/ui/chat_bubble.d.ts.map +1 -0
  77. package/dist/components/ui/chat_bubble.js +130 -0
  78. package/dist/components/ui/chat_bubble.js.map +1 -0
  79. package/dist/components/ui/hover-card.d.ts +13 -0
  80. package/dist/components/ui/hover-card.d.ts.map +1 -0
  81. package/dist/components/ui/hover-card.js +17 -0
  82. package/dist/components/ui/hover-card.js.map +1 -0
  83. package/dist/components/ui/index.d.ts +19 -0
  84. package/dist/components/ui/index.d.ts.map +1 -0
  85. package/dist/components/ui/index.js +21 -0
  86. package/dist/components/ui/index.js.map +1 -0
  87. package/dist/components/ui/input.d.ts +11 -0
  88. package/dist/components/ui/input.d.ts.map +1 -0
  89. package/dist/components/ui/input.js +18 -0
  90. package/dist/components/ui/input.js.map +1 -0
  91. package/dist/components/ui/loading_skeleton.d.ts +19 -0
  92. package/dist/components/ui/loading_skeleton.d.ts.map +1 -0
  93. package/dist/components/ui/loading_skeleton.js +30 -0
  94. package/dist/components/ui/loading_skeleton.js.map +1 -0
  95. package/dist/components/ui/scroll-area.d.ts +12 -0
  96. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  97. package/dist/components/ui/scroll-area.js +25 -0
  98. package/dist/components/ui/scroll-area.js.map +1 -0
  99. package/dist/components/ui/separator.d.ts +11 -0
  100. package/dist/components/ui/separator.d.ts.map +1 -0
  101. package/dist/components/ui/separator.js +18 -0
  102. package/dist/components/ui/separator.js.map +1 -0
  103. package/dist/components/ui/skeleton.d.ts +9 -0
  104. package/dist/components/ui/skeleton.d.ts.map +1 -0
  105. package/dist/components/ui/skeleton.js +16 -0
  106. package/dist/components/ui/skeleton.js.map +1 -0
  107. package/dist/components/ui/textarea.d.ts +11 -0
  108. package/dist/components/ui/textarea.d.ts.map +1 -0
  109. package/dist/components/ui/textarea.js +18 -0
  110. package/dist/components/ui/textarea.js.map +1 -0
  111. package/dist/components/ui/tooltip.d.ts +14 -0
  112. package/dist/components/ui/tooltip.d.ts.map +1 -0
  113. package/dist/components/ui/tooltip.js +30 -0
  114. package/dist/components/ui/tooltip.js.map +1 -0
  115. package/dist/hooks/index.d.ts +10 -0
  116. package/dist/hooks/index.d.ts.map +1 -0
  117. package/dist/hooks/index.js +10 -0
  118. package/dist/hooks/index.js.map +1 -0
  119. package/dist/hooks/use_chat_messages.d.ts +33 -0
  120. package/dist/hooks/use_chat_messages.d.ts.map +1 -0
  121. package/dist/hooks/use_chat_messages.js +485 -0
  122. package/dist/hooks/use_chat_messages.js.map +1 -0
  123. package/dist/hooks/use_chat_references.d.ts +17 -0
  124. package/dist/hooks/use_chat_references.d.ts.map +1 -0
  125. package/dist/hooks/use_chat_references.js +133 -0
  126. package/dist/hooks/use_chat_references.js.map +1 -0
  127. package/dist/hooks/use_file_upload.d.ts +23 -0
  128. package/dist/hooks/use_file_upload.d.ts.map +1 -0
  129. package/dist/hooks/use_file_upload.js +212 -0
  130. package/dist/hooks/use_file_upload.js.map +1 -0
  131. package/dist/index.d.ts +13 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +17 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/lib/config.d.ts +41 -0
  136. package/dist/lib/config.d.ts.map +1 -0
  137. package/dist/lib/config.js +93 -0
  138. package/dist/lib/config.js.map +1 -0
  139. package/dist/lib/constants.d.ts +41 -0
  140. package/dist/lib/constants.d.ts.map +1 -0
  141. package/dist/lib/constants.js +72 -0
  142. package/dist/lib/constants.js.map +1 -0
  143. package/dist/lib/index.d.ts +9 -0
  144. package/dist/lib/index.d.ts.map +1 -0
  145. package/dist/lib/index.js +9 -0
  146. package/dist/lib/index.js.map +1 -0
  147. package/dist/lib/utils.d.ts +17 -0
  148. package/dist/lib/utils.d.ts.map +1 -0
  149. package/dist/lib/utils.js +20 -0
  150. package/dist/lib/utils.js.map +1 -0
  151. package/dist/types/index.d.ts +405 -0
  152. package/dist/types/index.d.ts.map +1 -0
  153. package/dist/types/index.js +11 -0
  154. package/dist/types/index.js.map +1 -0
  155. package/package.json +1 -1
package/README.md CHANGED
@@ -12,7 +12,7 @@ A full-featured React chat component library for 1-1 communication with document
12
12
  - 📄 **Document Viewer** - Built-in PDF and image viewer with expand/collapse toggle, download, and open in new tab actions
13
13
  - 👤 **User Profiles** - Avatar display and user information
14
14
  - 🔄 **Infinite Scroll** - Cursor-based pagination for message history
15
- - ✅ **Read Receipts** - Track message read status
15
+ - ✅ **Read Receipts** - Automatic mark-as-read when messages become visible using Intersection Observer
16
16
  - 🗑️ **Soft Delete** - Delete messages with undo capability
17
17
  - 🎨 **Customizable** - TailwindCSS-based theming
18
18
  - 🚀 **API-First** - No server-side dependencies in client components
@@ -242,19 +242,28 @@ This section defines the visual design standards and component behavior specific
242
242
 
243
243
  **Message Timestamp Display:**
244
244
  - Location: Chat bubble footer (`ChatBubble`)
245
- - Only timestamp is displayed (no status icons for sent/unread messages)
246
245
  - Font size: `text-xs`
247
246
  - Color: `text-muted-foreground`
248
- - Format: 24-hour format (e.g., "10:37 AM", "15:51")
247
+ - Time format: 24-hour format (e.g., "10:37", "15:51")
248
+ - Date prefix: Messages before today show date in `dd/MMM` format (e.g., "02/Dec 10:37")
249
249
  - Timezone: Respects `timezone` prop (default: "GMT+10")
250
250
 
251
- **Read Receipt Indicator:**
251
+ **Message Status Indicators (Sender's Messages Only):**
252
252
  - Location: Chat bubble footer, after timestamp
253
- - Icon: `IoCheckmarkDoneSharp` (from `react-icons/io5`)
254
- - Size: `h-4 w-4` (16px × 16px)
255
- - Color: `text-green-500`
256
- - Display condition: Only shown when `read_at` is not null AND message is from sender
257
253
  - Position: After timestamp with `gap-1` spacing
254
+ - Size: `h-4 w-4` (16px × 16px)
255
+
256
+ **Sent Indicator (Grey Single Check):**
257
+ - Icon: `IoCheckmark` (from `react-icons/io5`)
258
+ - Color: `text-muted-foreground` (grey)
259
+ - Display condition: Shown when message is sent but `read_at` is null
260
+ - Meaning: Message delivered but not yet read by recipient
261
+
262
+ **Read Receipt (Green Double Check):**
263
+ - Icon: `IoCheckmarkDoneSharp` (from `react-icons/io5`)
264
+ - Color: `text-green-500` (green)
265
+ - Display condition: Only shown when `read_at` is not null
266
+ - Meaning: Message has been read by recipient
258
267
 
259
268
  #### Component Behavior
260
269
 
@@ -293,6 +302,20 @@ This section defines the visual design standards and component behavior specific
293
302
  - Indicator: Chevron icon (`IoChevronDown` when collapsed, `IoChevronUp` when expanded)
294
303
  - Default state: Collapsed when no references, expanded when references exist
295
304
 
305
+ **Automatic Mark-as-Read:**
306
+ - Detection: Uses Intersection Observer API to detect when messages become visible
307
+ - Trigger threshold: Messages marked as read when 50% visible in the ScrollArea viewport
308
+ - Scope: Only marks messages where the current user is the receiver (not the sender)
309
+ - State tracking: Prevents duplicate marking using in-memory Set
310
+ - API endpoint: Requires `PATCH /api/hazo_chat/messages/[id]/read` route
311
+ - Visual indicator: Green double-checkmark (IoCheckmarkDoneSharp) appears after timestamp
312
+ - Automatic: No user action required - messages are marked as read automatically when scrolled into view
313
+
314
+ **Note:** The mark-as-read functionality requires:
315
+ 1. The `HazoChat` component (includes all hooks and logic)
316
+ 2. The API route for marking messages as read (see API Routes Setup below)
317
+ 3. Messages must be received by the current user (messages sent by current user are not marked)
318
+
296
319
  #### Layout Standards
297
320
 
298
321
  **Chat Input Area:**
@@ -476,6 +499,7 @@ hazo_chat requires these API endpoints:
476
499
  |----------|--------|-------------|
477
500
  | `/api/hazo_chat/messages` | GET | Fetch chat messages |
478
501
  | `/api/hazo_chat/messages` | POST | Send a new message |
502
+ | `/api/hazo_chat/messages/[id]/read` | PATCH | Mark a message as read (automatic) |
479
503
  | `/api/hazo_chat/unread_count` | GET | Get unread message counts by reference_id (optional) |
480
504
  | `/api/hazo_auth/me` | GET | Get current authenticated user |
481
505
  | `/api/hazo_auth/profiles` | POST | Fetch user profiles by IDs |
@@ -501,6 +525,34 @@ const { GET, POST } = createMessagesHandler({
501
525
  export { GET, POST };
502
526
  ```
503
527
 
528
+ ```typescript
529
+ // app/api/hazo_chat/messages/[id]/read/route.ts
530
+ import { NextRequest } from 'next/server';
531
+ import { createMarkAsReadHandler } from 'hazo_chat/api';
532
+ import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
533
+
534
+ export const dynamic = 'force-dynamic';
535
+
536
+ const { PATCH } = createMarkAsReadHandler({
537
+ getHazoConnect: () => getHazoConnectSingleton(),
538
+ // Optional: custom authentication
539
+ getUserIdFromRequest: async (request) => {
540
+ // Return user ID from your auth system
541
+ return request.cookies.get('user_id')?.value || null;
542
+ }
543
+ });
544
+
545
+ // Wrapper to handle Next.js App Router params
546
+ async function handlePATCH(
547
+ request: NextRequest,
548
+ context: { params: { id: string } | Promise<{ id: string }> }
549
+ ) {
550
+ return PATCH(request, context);
551
+ }
552
+
553
+ export { handlePATCH as PATCH };
554
+ ```
555
+
504
556
  ### Custom Implementation
505
557
 
506
558
  If you need more control, implement the endpoints manually. See [SETUP_CHECKLIST.md](./SETUP_CHECKLIST.md) for detailed examples.
@@ -132,6 +132,41 @@ const { GET, POST } = createMessagesHandler({
132
132
  export { GET, POST };
133
133
  ```
134
134
 
135
+ ### Step 4.1.5: Mark as Read API (Automatic Read Receipts)
136
+
137
+ **File: `src/app/api/hazo_chat/messages/[id]/read/route.ts`**
138
+
139
+ ```typescript
140
+ /**
141
+ * API route to mark a chat message as read
142
+ * Uses the exportable handler from hazo_chat package
143
+ * Supports PATCH for marking messages as read
144
+ */
145
+
146
+ export const dynamic = 'force-dynamic';
147
+
148
+ import { NextRequest } from 'next/server';
149
+ import { createMarkAsReadHandler } from 'hazo_chat/api';
150
+ import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
151
+
152
+ // Create handler using the exportable factory from hazo_chat
153
+ const { PATCH: patchHandler } = createMarkAsReadHandler({
154
+ getHazoConnect: () => getHazoConnectSingleton()
155
+ });
156
+
157
+ // Wrapper to handle Next.js App Router params
158
+ async function PATCH(
159
+ request: NextRequest,
160
+ context: { params: { id: string } | Promise<{ id: string }> }
161
+ ) {
162
+ return patchHandler(request, context);
163
+ }
164
+
165
+ export { PATCH };
166
+ ```
167
+
168
+ **Note:** This endpoint is called automatically by the `HazoChat` component when messages become visible in the viewport. It uses the Intersection Observer API to detect visibility and marks messages as read when they are at least 50% visible.
169
+
135
170
  ### Step 4.2: Auth Me API
136
171
 
137
172
  **File: `src/app/api/hazo_auth/me/route.ts`**
@@ -327,6 +362,7 @@ export async function GET(request: NextRequest) {
327
362
  | Endpoint | Method | File | Purpose |
328
363
  |----------|--------|------|---------|
329
364
  | `/api/hazo_chat/messages` | GET, POST | `api/hazo_chat/messages/route.ts` | Message CRUD |
365
+ | `/api/hazo_chat/messages/[id]/read` | PATCH | `api/hazo_chat/messages/[id]/read/route.ts` | Mark message as read (automatic) |
330
366
  | `/api/hazo_chat/unread_count` | GET | `api/hazo_chat/unread_count/route.ts` | Get unread counts (optional) |
331
367
  | `/api/hazo_auth/me` | GET | `api/hazo_auth/me/route.ts` | Get current user |
332
368
  | `/api/hazo_auth/profiles` | POST | `api/hazo_auth/profiles/route.ts` | Get user profiles |
@@ -336,6 +372,7 @@ export async function GET(request: NextRequest) {
336
372
  - [ ] `GET /api/hazo_auth/me` returns user data when logged in
337
373
  - [ ] `POST /api/hazo_auth/profiles` returns profiles for given IDs
338
374
  - [ ] `GET /api/hazo_chat/messages?receiver_user_id=xxx` works
375
+ - [ ] `PATCH /api/hazo_chat/messages/[message-id]/read` marks message as read
339
376
  - [ ] `GET /api/hazo_chat/unread_count?receiver_user_id=xxx` returns unread counts (if implemented)
340
377
 
341
378
  ---
@@ -0,0 +1,26 @@
1
+ /**
2
+ * hazo_chat API Module
3
+ *
4
+ * Provides exportable API route handlers for Next.js applications.
5
+ * These handlers can be imported and re-exported in your API routes.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // app/api/hazo_chat/messages/route.ts
10
+ * import { createMessagesHandler } from 'hazo_chat/api';
11
+ * import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
12
+ *
13
+ * export const dynamic = 'force-dynamic';
14
+ *
15
+ * const { GET, POST } = createMessagesHandler({
16
+ * getHazoConnect: () => getHazoConnectSingleton()
17
+ * });
18
+ *
19
+ * export { GET, POST };
20
+ * ```
21
+ */
22
+ export { createMessagesHandler, createMarkAsReadHandler } from './messages.js';
23
+ export { createUnreadCountFunction } from './unread_count.js';
24
+ export type { MessagesHandlerOptions, ChatMessageInput, ChatMessageRecord } from './types.js';
25
+ export type { UnreadCountFunctionOptions, UnreadCountResult } from './unread_count.js';
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,YAAY,EACV,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,0BAA0B,EAC1B,iBAAiB,EAClB,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * hazo_chat API Module
3
+ *
4
+ * Provides exportable API route handlers for Next.js applications.
5
+ * These handlers can be imported and re-exported in your API routes.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // app/api/hazo_chat/messages/route.ts
10
+ * import { createMessagesHandler } from 'hazo_chat/api';
11
+ * import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
12
+ *
13
+ * export const dynamic = 'force-dynamic';
14
+ *
15
+ * const { GET, POST } = createMessagesHandler({
16
+ * getHazoConnect: () => getHazoConnectSingleton()
17
+ * });
18
+ *
19
+ * export { GET, POST };
20
+ * ```
21
+ */
22
+ // Export handler factories
23
+ export { createMessagesHandler, createMarkAsReadHandler } from './messages.js';
24
+ export { createUnreadCountFunction } from './unread_count.js';
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,2BAA2B;AAC3B,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Messages API Handler Factory
3
+ *
4
+ * Creates GET and POST handlers for the /api/hazo_chat/messages endpoint.
5
+ * These handlers should be used in a Next.js API route.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // app/api/hazo_chat/messages/route.ts
10
+ * import { createMessagesHandler } from 'hazo_chat/api';
11
+ * import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
12
+ *
13
+ * export const dynamic = 'force-dynamic';
14
+ *
15
+ * const { GET, POST } = createMessagesHandler({
16
+ * getHazoConnect: () => getHazoConnectSingleton()
17
+ * });
18
+ *
19
+ * export { GET, POST };
20
+ * ```
21
+ */
22
+ import { NextRequest, NextResponse } from 'next/server';
23
+ import type { MessagesHandlerOptions } from './types.js';
24
+ /**
25
+ * Creates GET and POST handlers for chat messages
26
+ *
27
+ * @param options - Configuration options
28
+ * @returns Object with GET and POST handlers
29
+ */
30
+ export declare function createMessagesHandler(options: MessagesHandlerOptions): {
31
+ GET: (request: NextRequest) => Promise<NextResponse>;
32
+ POST: (request: NextRequest) => Promise<NextResponse>;
33
+ };
34
+ /**
35
+ * Creates a PATCH handler for marking a message as read
36
+ *
37
+ * This handler should be used in a Next.js API route like:
38
+ * /api/hazo_chat/messages/[id]/read/route.ts
39
+ *
40
+ * @param options - Configuration options
41
+ * @returns PATCH handler function
42
+ */
43
+ export declare function createMarkAsReadHandler(options: MessagesHandlerOptions): {
44
+ PATCH: (request: NextRequest, context: {
45
+ params: {
46
+ id: string;
47
+ } | Promise<{
48
+ id: string;
49
+ }>;
50
+ }) => Promise<NextResponse>;
51
+ };
52
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/api/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD,OAAO,KAAK,EAAE,sBAAsB,EAAuC,MAAM,YAAY,CAAC;AAmB9F;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB;mBAWvC,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC;oBA+FlC,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC;EA0GjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,sBAAsB;qBAY1D,WAAW,WACX;QAAE,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KAC5D,OAAO,CAAC,YAAY,CAAC;EA8HzB"}
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Messages API Handler Factory
3
+ *
4
+ * Creates GET and POST handlers for the /api/hazo_chat/messages endpoint.
5
+ * These handlers should be used in a Next.js API route.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // app/api/hazo_chat/messages/route.ts
10
+ * import { createMessagesHandler } from 'hazo_chat/api';
11
+ * import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
12
+ *
13
+ * export const dynamic = 'force-dynamic';
14
+ *
15
+ * const { GET, POST } = createMessagesHandler({
16
+ * getHazoConnect: () => getHazoConnectSingleton()
17
+ * });
18
+ *
19
+ * export { GET, POST };
20
+ * ```
21
+ */
22
+ import { NextResponse } from 'next/server';
23
+ import { cookies } from 'next/headers';
24
+ import { createCrudService, getSqliteAdminService } from 'hazo_connect/server';
25
+ // UUID generation for message IDs
26
+ function generateUUID() {
27
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
28
+ const r = Math.random() * 16 | 0;
29
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
30
+ return v.toString(16);
31
+ });
32
+ }
33
+ /**
34
+ * Default function to get user ID from request cookies
35
+ */
36
+ async function defaultGetUserIdFromRequest() {
37
+ const cookieStore = await cookies();
38
+ return cookieStore.get('hazo_auth_user_id')?.value || null;
39
+ }
40
+ /**
41
+ * Creates GET and POST handlers for chat messages
42
+ *
43
+ * @param options - Configuration options
44
+ * @returns Object with GET and POST handlers
45
+ */
46
+ export function createMessagesHandler(options) {
47
+ const { getHazoConnect, getUserIdFromRequest } = options;
48
+ /**
49
+ * GET handler - Fetch chat messages
50
+ *
51
+ * Query params:
52
+ * - receiver_user_id (required): The other user in the conversation
53
+ * - reference_id (optional): Filter by reference ID
54
+ * - reference_type (optional): Filter by reference type
55
+ */
56
+ async function GET(request) {
57
+ try {
58
+ // Get current user ID
59
+ const current_user_id = getUserIdFromRequest
60
+ ? await getUserIdFromRequest(request)
61
+ : await defaultGetUserIdFromRequest();
62
+ if (!current_user_id) {
63
+ console.error('[hazo_chat/messages GET] No user ID - not authenticated');
64
+ return NextResponse.json({ success: false, error: 'User not authenticated', messages: [] }, { status: 401 });
65
+ }
66
+ // Get query params
67
+ const { searchParams } = new URL(request.url);
68
+ const receiver_user_id = searchParams.get('receiver_user_id');
69
+ const reference_id = searchParams.get('reference_id') || '';
70
+ const reference_type = searchParams.get('reference_type') || '';
71
+ if (!receiver_user_id) {
72
+ console.error('[hazo_chat/messages GET] Missing receiver_user_id');
73
+ return NextResponse.json({ success: false, error: 'receiver_user_id is required', messages: [] }, { status: 400 });
74
+ }
75
+ console.log('[hazo_chat/messages GET] Fetching messages:', {
76
+ current_user_id,
77
+ receiver_user_id,
78
+ reference_id,
79
+ reference_type,
80
+ });
81
+ // Get hazo_connect instance and create CRUD service
82
+ const hazoConnect = getHazoConnect();
83
+ const chatService = createCrudService(hazoConnect, 'hazo_chat');
84
+ let messages = [];
85
+ try {
86
+ // Fetch all messages with reference filters
87
+ const all_messages = await chatService.list((qb) => {
88
+ let builder = qb.select('*');
89
+ if (reference_id) {
90
+ builder = builder.where('reference_id', 'eq', reference_id);
91
+ }
92
+ if (reference_type) {
93
+ builder = builder.where('reference_type', 'eq', reference_type);
94
+ }
95
+ return builder.order('created_at', 'asc');
96
+ });
97
+ // Filter to only messages between current user and receiver
98
+ messages = all_messages.filter((msg) => {
99
+ const is_sent_by_me = msg.sender_user_id === current_user_id && msg.receiver_user_id === receiver_user_id;
100
+ const is_sent_to_me = msg.sender_user_id === receiver_user_id && msg.receiver_user_id === current_user_id;
101
+ return is_sent_by_me || is_sent_to_me;
102
+ });
103
+ }
104
+ catch (dbError) {
105
+ console.error('[hazo_chat/messages GET] Database error:', dbError);
106
+ throw dbError;
107
+ }
108
+ console.log('[hazo_chat/messages GET] Found messages:', messages.length);
109
+ return NextResponse.json({
110
+ success: true,
111
+ messages,
112
+ current_user_id,
113
+ });
114
+ }
115
+ catch (error) {
116
+ const error_message = error instanceof Error ? error.message : 'Unknown error';
117
+ console.error('[hazo_chat/messages GET] Error:', error_message, error);
118
+ return NextResponse.json({ success: false, error: 'Failed to fetch messages', messages: [] }, { status: 500 });
119
+ }
120
+ }
121
+ /**
122
+ * POST handler - Create a new chat message
123
+ *
124
+ * Request body:
125
+ * - receiver_user_id (required): The recipient user ID
126
+ * - message_text (required): The message content
127
+ * - reference_id (optional): Reference ID for context grouping
128
+ * - reference_type (optional): Reference type (default: 'chat')
129
+ */
130
+ async function POST(request) {
131
+ try {
132
+ // Get current user ID (sender)
133
+ const sender_user_id = getUserIdFromRequest
134
+ ? await getUserIdFromRequest(request)
135
+ : await defaultGetUserIdFromRequest();
136
+ if (!sender_user_id) {
137
+ console.error('[hazo_chat/messages POST] No user ID - not authenticated');
138
+ return NextResponse.json({ success: false, error: 'User not authenticated' }, { status: 401 });
139
+ }
140
+ // Parse request body
141
+ const body = await request.json();
142
+ const { receiver_user_id, message_text, reference_id, reference_type } = body;
143
+ // Validate required fields
144
+ if (!receiver_user_id) {
145
+ console.error('[hazo_chat/messages POST] Missing receiver_user_id');
146
+ return NextResponse.json({ success: false, error: 'receiver_user_id is required' }, { status: 400 });
147
+ }
148
+ if (!message_text || message_text.trim() === '') {
149
+ console.error('[hazo_chat/messages POST] Missing or empty message_text');
150
+ return NextResponse.json({ success: false, error: 'message_text is required' }, { status: 400 });
151
+ }
152
+ // Get hazo_connect instance and create CRUD service
153
+ const hazoConnect = getHazoConnect();
154
+ const chatService = createCrudService(hazoConnect, 'hazo_chat');
155
+ // Generate message ID and timestamps
156
+ const message_id = generateUUID();
157
+ const now = new Date().toISOString();
158
+ // Create message record
159
+ const message_record = {
160
+ id: message_id,
161
+ reference_id: reference_id || '',
162
+ reference_type: reference_type || 'chat',
163
+ sender_user_id,
164
+ receiver_user_id,
165
+ message_text: message_text.trim(),
166
+ reference_list: null,
167
+ read_at: null,
168
+ deleted_at: null,
169
+ created_at: now,
170
+ changed_at: now,
171
+ };
172
+ console.log('[hazo_chat/messages POST] Saving message:', {
173
+ id: message_id,
174
+ sender_user_id,
175
+ receiver_user_id,
176
+ reference_id: reference_id || '',
177
+ reference_type: reference_type || 'chat',
178
+ message_length: message_text.length,
179
+ });
180
+ // Save to database
181
+ try {
182
+ await chatService.insert(message_record);
183
+ }
184
+ catch (dbError) {
185
+ console.error('[hazo_chat/messages POST] Database error:', dbError);
186
+ throw dbError;
187
+ }
188
+ console.log('[hazo_chat/messages POST] Message saved successfully:', message_id);
189
+ return NextResponse.json({
190
+ success: true,
191
+ message: {
192
+ id: message_id,
193
+ sender_user_id,
194
+ receiver_user_id,
195
+ reference_id: reference_id || '',
196
+ reference_type: reference_type || 'chat',
197
+ message_text: message_text.trim(),
198
+ reference_list: null,
199
+ read_at: null,
200
+ deleted_at: null,
201
+ created_at: now,
202
+ changed_at: now,
203
+ },
204
+ });
205
+ }
206
+ catch (error) {
207
+ const error_message = error instanceof Error ? error.message : 'Unknown error';
208
+ console.error('[hazo_chat/messages POST] Error:', error_message, error);
209
+ return NextResponse.json({ success: false, error: 'Failed to save message' }, { status: 500 });
210
+ }
211
+ }
212
+ return { GET, POST };
213
+ }
214
+ /**
215
+ * Creates a PATCH handler for marking a message as read
216
+ *
217
+ * This handler should be used in a Next.js API route like:
218
+ * /api/hazo_chat/messages/[id]/read/route.ts
219
+ *
220
+ * @param options - Configuration options
221
+ * @returns PATCH handler function
222
+ */
223
+ export function createMarkAsReadHandler(options) {
224
+ const { getHazoConnect, getUserIdFromRequest } = options;
225
+ /**
226
+ * PATCH handler - Mark a message as read
227
+ *
228
+ * Route params:
229
+ * - id (required): The message ID to mark as read
230
+ *
231
+ * Note: In Next.js 13+ App Router, params may be a Promise
232
+ */
233
+ async function PATCH(request, context) {
234
+ try {
235
+ // Get current user ID
236
+ const current_user_id = getUserIdFromRequest
237
+ ? await getUserIdFromRequest(request)
238
+ : await defaultGetUserIdFromRequest();
239
+ if (!current_user_id) {
240
+ console.error('[hazo_chat/messages/[id]/read PATCH] No user ID - not authenticated');
241
+ return NextResponse.json({ success: false, error: 'User not authenticated' }, { status: 401 });
242
+ }
243
+ // Handle params as Promise (Next.js 15+) or direct object (Next.js 13-14)
244
+ const params = context.params instanceof Promise ? await context.params : context.params;
245
+ const message_id = params.id;
246
+ if (!message_id) {
247
+ console.error('[hazo_chat/messages/[id]/read PATCH] Missing message ID');
248
+ return NextResponse.json({ success: false, error: 'Message ID is required' }, { status: 400 });
249
+ }
250
+ console.log('[hazo_chat/messages/[id]/read PATCH] Marking message as read:', {
251
+ message_id,
252
+ current_user_id,
253
+ });
254
+ // Get hazo_connect instance and create CRUD service
255
+ const hazoConnect = getHazoConnect();
256
+ const chatService = createCrudService(hazoConnect, 'hazo_chat');
257
+ // First, fetch the message to verify ownership
258
+ let message = null;
259
+ try {
260
+ const messages = await chatService.list((qb) => qb.select('*').where('id', 'eq', message_id));
261
+ message = messages[0] || null;
262
+ }
263
+ catch (dbError) {
264
+ console.error('[hazo_chat/messages/[id]/read PATCH] Database error fetching message:', dbError);
265
+ throw dbError;
266
+ }
267
+ if (!message) {
268
+ console.error('[hazo_chat/messages/[id]/read PATCH] Message not found:', message_id);
269
+ return NextResponse.json({ success: false, error: 'Message not found' }, { status: 404 });
270
+ }
271
+ // Verify that the current user is the receiver (only receivers can mark as read)
272
+ if (message.receiver_user_id !== current_user_id) {
273
+ console.error('[hazo_chat/messages/[id]/read PATCH] User is not the receiver:', {
274
+ message_id,
275
+ current_user_id,
276
+ receiver_user_id: message.receiver_user_id,
277
+ });
278
+ return NextResponse.json({ success: false, error: 'Unauthorized - only the receiver can mark messages as read' }, { status: 403 });
279
+ }
280
+ // Don't update if already read
281
+ if (message.read_at) {
282
+ console.log('[hazo_chat/messages/[id]/read PATCH] Message already read:', message_id);
283
+ return NextResponse.json({
284
+ success: true,
285
+ message: {
286
+ ...message,
287
+ read_at: message.read_at,
288
+ },
289
+ });
290
+ }
291
+ // Update the read_at timestamp
292
+ // Use SQLite admin service's updateRows method for reliable updates
293
+ const now = new Date().toISOString();
294
+ try {
295
+ // Use the SQLite admin service which has updateRows method
296
+ const sqliteService = getSqliteAdminService();
297
+ const updated_rows = await sqliteService.updateRows('hazo_chat', { id: message_id }, // criteria: update where id matches
298
+ { read_at: now, changed_at: now } // data to update
299
+ );
300
+ if (updated_rows.length === 0) {
301
+ console.warn('[hazo_chat/messages/[id]/read PATCH] No rows updated - message may not exist:', message_id);
302
+ // Don't throw error, just log warning - message might have been deleted
303
+ }
304
+ else {
305
+ console.log('[hazo_chat/messages/[id]/read PATCH] Successfully updated', updated_rows.length, 'row(s)');
306
+ }
307
+ }
308
+ catch (dbError) {
309
+ console.error('[hazo_chat/messages/[id]/read PATCH] Database error updating message:', dbError);
310
+ throw dbError;
311
+ }
312
+ console.log('[hazo_chat/messages/[id]/read PATCH] Message marked as read successfully:', message_id);
313
+ return NextResponse.json({
314
+ success: true,
315
+ message: {
316
+ ...message,
317
+ read_at: now,
318
+ changed_at: now,
319
+ },
320
+ });
321
+ }
322
+ catch (error) {
323
+ const error_message = error instanceof Error ? error.message : 'Unknown error';
324
+ console.error('[hazo_chat/messages/[id]/read PATCH] Error:', error_message, error);
325
+ return NextResponse.json({ success: false, error: 'Failed to mark message as read' }, { status: 500 });
326
+ }
327
+ }
328
+ return { PATCH };
329
+ }
330
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/api/messages.ts"],"names":[],"mappings":"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"}