hazo_ihelp 2.0.9 → 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 (79) hide show
  1. package/SETUP_CHECKLIST.md +131 -0
  2. package/config/hazo_ihelp_config.ini.sample +41 -8
  3. package/db_setup_postgres.sql +52 -0
  4. package/db_setup_sqlite.sql +25 -0
  5. package/dist/api/create_config_handler.d.ts +2 -0
  6. package/dist/api/create_config_handler.d.ts.map +1 -1
  7. package/dist/api/create_config_handler.js +117 -81
  8. package/dist/api/create_config_handler.js.map +1 -1
  9. package/dist/api/create_ihelp_handler.d.ts +4 -12
  10. package/dist/api/create_ihelp_handler.d.ts.map +1 -1
  11. package/dist/api/create_ihelp_handler.js +251 -226
  12. package/dist/api/create_ihelp_handler.js.map +1 -1
  13. package/dist/api/image_upload_handler.d.ts.map +1 -1
  14. package/dist/api/image_upload_handler.js +114 -80
  15. package/dist/api/image_upload_handler.js.map +1 -1
  16. package/dist/components/editor/editor_collapsible_section.js +1 -1
  17. package/dist/components/editor/editor_collapsible_section.js.map +1 -1
  18. package/dist/components/editor/editor_form.js +1 -1
  19. package/dist/components/editor/editor_form.js.map +1 -1
  20. package/dist/components/editor/editor_topic_list_item.js +1 -1
  21. package/dist/components/editor/editor_topic_list_item.js.map +1 -1
  22. package/dist/components/hover_help_icon.d.ts +39 -0
  23. package/dist/components/hover_help_icon.d.ts.map +1 -0
  24. package/dist/components/hover_help_icon.js +29 -0
  25. package/dist/components/hover_help_icon.js.map +1 -0
  26. package/dist/components/ihelp_detail_panel.js +1 -1
  27. package/dist/components/ihelp_detail_panel.js.map +1 -1
  28. package/dist/components/ihelp_editor.js +1 -1
  29. package/dist/components/ihelp_editor.js.map +1 -1
  30. package/dist/components/ihelp_icon.js +1 -1
  31. package/dist/components/ihelp_icon.js.map +1 -1
  32. package/dist/components/ihelp_provider.d.ts.map +1 -1
  33. package/dist/components/ihelp_provider.js +6 -1
  34. package/dist/components/ihelp_provider.js.map +1 -1
  35. package/dist/components/ihelp_rich_editor.js +1 -1
  36. package/dist/components/ihelp_rich_editor.js.map +1 -1
  37. package/dist/components/ihelp_search_dialog.js +1 -1
  38. package/dist/components/ihelp_search_dialog.js.map +1 -1
  39. package/dist/components/index.d.ts +1 -0
  40. package/dist/components/index.d.ts.map +1 -1
  41. package/dist/components/index.js +1 -0
  42. package/dist/components/index.js.map +1 -1
  43. package/dist/components/ui/badge.js +1 -1
  44. package/dist/components/ui/badge.js.map +1 -1
  45. package/dist/components/ui/button.js +1 -1
  46. package/dist/components/ui/button.js.map +1 -1
  47. package/dist/components/ui/dialog.js +1 -1
  48. package/dist/components/ui/dialog.js.map +1 -1
  49. package/dist/components/ui/input.js +1 -1
  50. package/dist/components/ui/input.js.map +1 -1
  51. package/dist/components/ui/label.js +1 -1
  52. package/dist/components/ui/label.js.map +1 -1
  53. package/dist/components/ui/popover.js +1 -1
  54. package/dist/components/ui/popover.js.map +1 -1
  55. package/dist/components/ui/select.js +1 -1
  56. package/dist/components/ui/select.js.map +1 -1
  57. package/dist/components/ui/switch.js +1 -1
  58. package/dist/components/ui/switch.js.map +1 -1
  59. package/dist/components/ui/textarea.js +1 -1
  60. package/dist/components/ui/textarea.js.map +1 -1
  61. package/dist/index.client.d.ts +1 -1
  62. package/dist/index.client.d.ts.map +1 -1
  63. package/dist/index.client.js +1 -1
  64. package/dist/index.client.js.map +1 -1
  65. package/dist/lib/config/hazo_ihelp_config.d.ts +106 -0
  66. package/dist/lib/config/hazo_ihelp_config.d.ts.map +1 -0
  67. package/dist/lib/config/hazo_ihelp_config.js +66 -0
  68. package/dist/lib/config/hazo_ihelp_config.js.map +1 -0
  69. package/dist/utils/logger.d.ts +25 -0
  70. package/dist/utils/logger.d.ts.map +1 -0
  71. package/dist/utils/logger.js +42 -0
  72. package/dist/utils/logger.js.map +1 -0
  73. package/package.json +65 -22
  74. package/config/hazo_ihelp_config.ini +0 -9
  75. package/dist/utils/cn.d.ts +0 -3
  76. package/dist/utils/cn.d.ts.map +0 -1
  77. package/dist/utils/cn.js +0 -6
  78. package/dist/utils/cn.js.map +0 -1
  79. package/migrations/001_create_ihelp_tables.sql +0 -109
@@ -0,0 +1,131 @@
1
+ # hazo_ihelp — Setup Checklist
2
+
3
+ Step-by-step guide for adding hazo_ihelp to a consuming Next.js app.
4
+
5
+ ## 1. Install
6
+
7
+ ```bash
8
+ npm install hazo_ihelp hazo_core hazo_ui hazo_connect
9
+ ```
10
+
11
+ `hazo_core` and `hazo_ui` are required peer deps. `hazo_connect` is the
12
+ database adapter used by the API handlers (mark as a peer dep, mark
13
+ optional only if you bring your own adapter implementing the same shape).
14
+
15
+ For image-upload support, optionally install `sharp` for server-side
16
+ resizing (the handler degrades gracefully without it):
17
+
18
+ ```bash
19
+ npm install sharp
20
+ ```
21
+
22
+ ## 2. Configure
23
+
24
+ Copy the sample INI into your app:
25
+
26
+ ```bash
27
+ mkdir -p config
28
+ cp node_modules/hazo_ihelp/config/hazo_ihelp_config.ini.sample config/hazo_ihelp_config.ini
29
+ ```
30
+
31
+ Adjust `upload_dir`, `upload_url_prefix`, and the size / MIME limits to
32
+ match your hosting setup. Any value can also be overridden via env vars
33
+ (`HAZO_IHELP_IMAGE_UPLOAD_MAX_FILE_SIZE_MB=10`) or layered with a
34
+ per-environment overlay file (`hazo_ihelp_config.<HAZO_ENV>.ini`).
35
+
36
+ ## 3. Run the schema setup
37
+
38
+ Pick the file that matches your database and run it once:
39
+
40
+ ```bash
41
+ psql "$DATABASE_URL" -f node_modules/hazo_ihelp/db_setup_postgres.sql
42
+ # or
43
+ sqlite3 path/to/app.sqlite < node_modules/hazo_ihelp/db_setup_sqlite.sql
44
+ ```
45
+
46
+ The script is idempotent — safe to re-run. The PostgreSQL version ends
47
+ with `SELECT pg_notify('pgrst', 'reload schema');` so PostgREST picks
48
+ up the new tables without a restart.
49
+
50
+ The shared `hazo_config` table is created by the `hazo_config` package's
51
+ own setup script — make sure it's been run too.
52
+
53
+ ## 4. Mount the API routes
54
+
55
+ Three routes are needed (paths shown match the defaults the hooks use):
56
+
57
+ ```ts
58
+ // app/api/ihelp/topics/route.ts
59
+ import { createIhelpHandler } from 'hazo_ihelp/api';
60
+ import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
61
+ export const dynamic = 'force-dynamic';
62
+ const { GET, POST } = createIhelpHandler({
63
+ getHazoConnect: () => getHazoConnectSingleton(),
64
+ });
65
+ export { GET, POST };
66
+
67
+ // app/api/ihelp/topics/[id]/route.ts
68
+ import { createIhelpHandler } from 'hazo_ihelp/api';
69
+ import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
70
+ export const dynamic = 'force-dynamic';
71
+ const { PATCH, DELETE } = createIhelpHandler({
72
+ getHazoConnect: () => getHazoConnectSingleton(),
73
+ });
74
+ export { PATCH, DELETE };
75
+
76
+ // app/api/ihelp/config/route.ts
77
+ import { createConfigHandler } from 'hazo_ihelp/api';
78
+ import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
79
+ export const dynamic = 'force-dynamic';
80
+ const handler = createConfigHandler({
81
+ getHazoConnect: () => getHazoConnectSingleton(),
82
+ });
83
+ export const GET = handler.GET;
84
+ export const PUT = handler.PUT;
85
+
86
+ // app/api/ihelp/upload/route.ts
87
+ import { createImageUploadHandler } from 'hazo_ihelp/api';
88
+ export const runtime = 'nodejs';
89
+ const { POST } = createImageUploadHandler();
90
+ export { POST };
91
+ ```
92
+
93
+ ## 5. Wrap the React tree
94
+
95
+ ```tsx
96
+ import { IhelpProvider } from 'hazo_ihelp';
97
+
98
+ export default function RootLayout({ children }) {
99
+ return (
100
+ <html><body>
101
+ <IhelpProvider scope_id={current_org_id}>
102
+ {children}
103
+ </IhelpProvider>
104
+ </body></html>
105
+ );
106
+ }
107
+ ```
108
+
109
+ ## 6. Drop in triggers near the UI they explain
110
+
111
+ ```tsx
112
+ import { IhelpIcon } from 'hazo_ihelp';
113
+
114
+ <label>
115
+ Work-from-home deduction <IhelpIcon context_key="deductions.work_from_home" />
116
+ </label>
117
+ ```
118
+
119
+ ## 7. Author topics
120
+
121
+ Either through the bundled `<IhelpEditor>` admin surface or by POSTing
122
+ to `/api/ihelp/topics` directly. Topics are unpublished by default —
123
+ set `is_published: true` once they're ready for end users.
124
+
125
+ ## 8. (Optional) Verify
126
+
127
+ - [ ] `npm run build` — package builds clean
128
+ - [ ] Open `/your/page/with/<IhelpIcon>` in dev — clicking opens the search dialog
129
+ - [ ] Press Cmd/Ctrl+K — search dialog toggles
130
+ - [ ] POST a topic with a `context_key` you used → the icon resolves to it
131
+ - [ ] Check server logs for `topic.created` events tagged with `correlationId`
@@ -1,23 +1,56 @@
1
- ; hazo_ihelp configuration
2
- ; Copy this file to config/hazo_ihelp_config.ini and adjust values.
1
+ # hazo_ihelp Configuration File
2
+ # This file controls runtime behaviour of hazo_ihelp.
3
+ # All values are commented out by default - uncomment and modify as needed.
4
+ #
5
+ # Per hazo workspace standard S7, values may also be overridden via env vars:
6
+ # HAZO_IHELP_<SECTION>_<KEY>=value
7
+ # e.g. HAZO_IHELP_IMAGE_UPLOAD_MAX_FILE_SIZE_MB=10
8
+ #
9
+ # Per D-019, a per-environment overlay file at config/hazo_ihelp_config.<HAZO_ENV>.ini
10
+ # is layered on top of this base file when HAZO_ENV is set.
3
11
 
12
+ # =============================================================================
13
+ # [general] - Workspace-standard general configuration
14
+ # =============================================================================
15
+ [general]
16
+
17
+ # Deployment environment label. Falls back to NODE_ENV, then 'development'.
18
+ # env = production
19
+
20
+ # Default base URL for ihelp API requests on the server side.
21
+ # api_base_url = /api/ihelp
22
+
23
+ # =============================================================================
24
+ # [log.overrides] - Per-namespace log level overrides (workspace standard)
25
+ # Format: <namespace> = trace|debug|info|warn|error
26
+ # =============================================================================
27
+ [log.overrides]
28
+
29
+ # hazo_ihelp = info
30
+ # hazo_ihelp/topics = warn
31
+ # hazo_ihelp/upload = debug
32
+
33
+ # =============================================================================
34
+ # [image_upload] - Image upload handler defaults
35
+ # =============================================================================
4
36
  [image_upload]
5
- ; Maximum file size in MB
37
+
38
+ # Maximum file size in MB
6
39
  max_file_size_mb = 5
7
40
 
8
- ; Allowed MIME types (comma-separated)
41
+ # Allowed MIME types (comma-separated)
9
42
  allowed_types = image/jpeg, image/png, image/gif, image/webp, image/svg+xml, image/avif
10
43
 
11
- ; Filesystem path where uploaded images are saved (relative to project root)
44
+ # Filesystem path where uploaded images are saved (relative to project root)
12
45
  upload_dir = public/ihelp/images
13
46
 
14
- ; URL prefix returned in API responses (must match how upload_dir is served)
47
+ # URL prefix returned in API responses (must match how upload_dir is served)
15
48
  upload_url_prefix = /ihelp/images
16
49
 
17
- ; Resize images that exceed max dimensions (skips SVG)
50
+ # Resize images that exceed max dimensions (skips SVG)
18
51
  resize_enabled = true
19
52
  resize_max_width = 1200
20
53
  resize_max_height = 1200
21
54
 
22
- ; JPEG/WebP quality (1-100)
55
+ # JPEG/WebP quality (1-100)
23
56
  resize_quality = 80
@@ -0,0 +1,52 @@
1
+ -- hazo_ihelp — PostgreSQL setup
2
+ -- Idempotent — safe to re-run. PostgreSQL uses native UUID, JSONB,
3
+ -- BOOLEAN, and TIMESTAMPTZ types.
4
+ --
5
+ -- Requires extension:
6
+ -- CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- for gen_random_uuid()
7
+
8
+ -- =============================================================================
9
+ -- hazo_ihelp_topics
10
+ -- =============================================================================
11
+ CREATE TABLE IF NOT EXISTS hazo_ihelp_topics (
12
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
13
+ parent_id UUID REFERENCES hazo_ihelp_topics(id) ON DELETE SET NULL,
14
+ scope_id UUID, -- NULL = global, UUID = org-specific
15
+ category TEXT NOT NULL DEFAULT 'General',
16
+ title TEXT NOT NULL,
17
+ description TEXT, -- short summary for search cards
18
+ content TEXT, -- rich HTML from Tiptap editor
19
+ icon TEXT, -- Lucide icon name
20
+ sort_order INTEGER NOT NULL DEFAULT 0,
21
+ is_published BOOLEAN NOT NULL DEFAULT TRUE,
22
+ tags JSONB NOT NULL DEFAULT '[]', -- [{label, variant, icon}]
23
+ contexts JSONB NOT NULL DEFAULT '[]', -- [{key, priority}]
24
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
25
+ changed_at TIMESTAMPTZ
26
+ );
27
+
28
+ CREATE INDEX IF NOT EXISTS idx_hazo_ihelp_topics_scope ON hazo_ihelp_topics(scope_id);
29
+ CREATE INDEX IF NOT EXISTS idx_hazo_ihelp_topics_parent ON hazo_ihelp_topics(parent_id);
30
+ CREATE INDEX IF NOT EXISTS idx_hazo_ihelp_topics_tags ON hazo_ihelp_topics USING GIN (tags);
31
+ CREATE INDEX IF NOT EXISTS idx_hazo_ihelp_topics_contexts ON hazo_ihelp_topics USING GIN (contexts);
32
+
33
+ -- =============================================================================
34
+ -- JSON column shapes
35
+ -- =============================================================================
36
+ -- tags: [{ "label": "Receipt Required", "variant": "warning", "icon": "AlertTriangle" }]
37
+ -- contexts: [{ "key": "deductions.work_from_home", "priority": 0 }]
38
+
39
+ -- =============================================================================
40
+ -- Example queries
41
+ -- =============================================================================
42
+ -- -- Find topics mapped to a context key, priority-ordered:
43
+ -- SELECT * FROM hazo_ihelp_topics
44
+ -- WHERE contexts @> '[{"key": "deductions.work_from_home"}]'
45
+ -- ORDER BY (SELECT MIN((ctx->>'priority')::int)
46
+ -- FROM jsonb_array_elements(contexts) ctx
47
+ -- WHERE ctx->>'key' = 'deductions.work_from_home');
48
+ --
49
+ -- -- Find topics with a specific tag label:
50
+ -- SELECT * FROM hazo_ihelp_topics WHERE tags @> '[{"label": "Pre-filled"}]';
51
+
52
+ SELECT pg_notify('pgrst', 'reload schema');
@@ -0,0 +1,25 @@
1
+ -- hazo_ihelp — SQLite setup
2
+ -- Idempotent — safe to re-run. SQLite stores UUIDs as TEXT and JSON as TEXT.
3
+ -- No native UUID, JSONB, BOOLEAN, or TIMESTAMPTZ types — see the PostgreSQL
4
+ -- companion file at db_setup_postgres.sql for the equivalent native typing.
5
+
6
+ CREATE TABLE IF NOT EXISTS hazo_ihelp_topics (
7
+ id TEXT PRIMARY KEY, -- UUID as text
8
+ parent_id TEXT, -- UUID ref → hazo_ihelp_topics(id)
9
+ scope_id TEXT, -- UUID, NULL = global
10
+ category TEXT NOT NULL DEFAULT 'General',
11
+ title TEXT NOT NULL,
12
+ description TEXT,
13
+ content TEXT, -- rich HTML from Tiptap editor
14
+ icon TEXT, -- Lucide icon name
15
+ sort_order INTEGER NOT NULL DEFAULT 0,
16
+ is_published INTEGER NOT NULL DEFAULT 1, -- SQLite boolean (0/1)
17
+ tags TEXT NOT NULL DEFAULT '[]', -- JSON array: [{label, variant, icon}]
18
+ contexts TEXT NOT NULL DEFAULT '[]', -- JSON array: [{key, priority}]
19
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
20
+ changed_at TEXT,
21
+ FOREIGN KEY (parent_id) REFERENCES hazo_ihelp_topics(id) ON DELETE SET NULL
22
+ );
23
+
24
+ CREATE INDEX IF NOT EXISTS idx_hazo_ihelp_topics_scope ON hazo_ihelp_topics(scope_id);
25
+ CREATE INDEX IF NOT EXISTS idx_hazo_ihelp_topics_parent ON hazo_ihelp_topics(parent_id);
@@ -2,6 +2,8 @@
2
2
  * Config API Handler Factory
3
3
  *
4
4
  * Creates GET and PUT handlers for the hazo_config key-value table.
5
+ * Each handler wraps its body in hazo_core's `withContext` so correlation
6
+ * IDs flow through every downstream call.
5
7
  *
6
8
  * @example
7
9
  * ```typescript
@@ -1 +1 @@
1
- {"version":3,"file":"create_config_handler.d.ts","sourceRoot":"","sources":["../../src/api/create_config_handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAgBzE,MAAM,WAAW,0BAA0B;IACzC,cAAc,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC1C;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B;mBAIzC,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;mBAyCrD,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;EAyDlF"}
1
+ {"version":3,"file":"create_config_handler.d.ts","sourceRoot":"","sources":["../../src/api/create_config_handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAUxD,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AA0BzE,MAAM,WAAW,0BAA0B;IACzC,cAAc,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC1C;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B;mBAKzC,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;mBAiDrD,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;EAwElF"}
@@ -2,6 +2,8 @@
2
2
  * Config API Handler Factory
3
3
  *
4
4
  * Creates GET and PUT handlers for the hazo_config key-value table.
5
+ * Each handler wraps its body in hazo_core's `withContext` so correlation
6
+ * IDs flow through every downstream call.
5
7
  *
6
8
  * @example
7
9
  * ```typescript
@@ -17,105 +19,139 @@
17
19
  */
18
20
  import { NextResponse } from 'next/server';
19
21
  import { createCrudService } from 'hazo_connect/server';
22
+ import { HazoError, HazoValidationError, generateRequestId, getCorrelationId, withContext, } from 'hazo_core';
23
+ import { get_logger } from '../utils/logger.js';
20
24
  function generateUUID() {
21
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
22
- const r = (Math.random() * 16) | 0;
23
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
24
- return v.toString(16);
25
- });
25
+ return generateRequestId().slice(4);
26
26
  }
27
27
  function errResponse(error, status) {
28
28
  return NextResponse.json({ success: false, error }, { status });
29
29
  }
30
+ function handleError(logger, event, error) {
31
+ if (HazoError.is(error)) {
32
+ const status = error.httpStatus ?? 500;
33
+ if (status >= 500) {
34
+ logger.error(event, { code: error.code, message: error.message, context: error.context });
35
+ }
36
+ else {
37
+ logger.warn(event, { code: error.code, message: error.message });
38
+ }
39
+ return errResponse(error.message, status);
40
+ }
41
+ logger.error(event, { error: error instanceof Error ? error.message : String(error) });
42
+ return errResponse(error instanceof Error ? error.message : 'Internal server error', 500);
43
+ }
30
44
  export function createConfigHandler(options) {
31
45
  const { getHazoConnect } = options;
46
+ const logger = get_logger();
32
47
  // GET ?config_key=context_keys&scope_id=...
33
48
  async function GET(request) {
34
- try {
35
- const adapter = await getHazoConnect();
36
- const configService = createCrudService(adapter, 'hazo_config');
37
- const url = new URL(request.url);
38
- const config_key = url.searchParams.get('config_key');
39
- const scope_id = url.searchParams.get('scope_id') || null;
40
- if (!config_key) {
41
- return errResponse('config_key query parameter is required', 400);
42
- }
43
- // Try scoped first, then fall back to global (scope_id = null)
44
- let rows = await configService.findBy({ config_key, scope_id });
45
- if (rows.length === 0 && scope_id) {
46
- rows = await configService.findBy({ config_key, scope_id: null });
47
- }
48
- if (rows.length === 0) {
49
- return NextResponse.json({ success: true, data: null });
50
- }
51
- const row = rows[0];
52
- let parsed;
49
+ return withContext({ correlationId: getCorrelationId() ?? generateRequestId() }, async () => {
53
50
  try {
54
- parsed = JSON.parse(row.config_value);
51
+ const adapter = await getHazoConnect();
52
+ const configService = createCrudService(adapter, 'hazo_config');
53
+ const url = new URL(request.url);
54
+ const config_key = url.searchParams.get('config_key');
55
+ const scope_id = url.searchParams.get('scope_id') || null;
56
+ if (!config_key) {
57
+ throw new HazoValidationError({
58
+ code: 'HAZO_IHELP_VALIDATION_ERROR',
59
+ pkg: 'hazo_ihelp',
60
+ message: 'config_key query parameter is required',
61
+ });
62
+ }
63
+ logger.debug('config.get.request', { config_key, scope_id });
64
+ // Try scoped first, then fall back to global (scope_id = null)
65
+ let rows = await configService.findBy({ config_key, scope_id });
66
+ if (rows.length === 0 && scope_id) {
67
+ rows = await configService.findBy({ config_key, scope_id: null });
68
+ }
69
+ if (rows.length === 0) {
70
+ return NextResponse.json({ success: true, data: null });
71
+ }
72
+ const row = rows[0];
73
+ let parsed;
74
+ try {
75
+ parsed = JSON.parse(row.config_value);
76
+ }
77
+ catch {
78
+ parsed = row.config_value;
79
+ }
80
+ return NextResponse.json({
81
+ success: true,
82
+ data: { id: row.id, config_key: row.config_key, value: parsed, scope_id: row.scope_id },
83
+ });
55
84
  }
56
- catch {
57
- parsed = row.config_value;
85
+ catch (err) {
86
+ return handleError(logger, 'config.get.failed', err);
58
87
  }
59
- return NextResponse.json({
60
- success: true,
61
- data: { id: row.id, config_key: row.config_key, value: parsed, scope_id: row.scope_id },
62
- });
63
- }
64
- catch (err) {
65
- return errResponse(err?.message || 'Failed to fetch config', 500);
66
- }
88
+ });
67
89
  }
68
90
  // PUT — upsert config entry
69
91
  async function PUT(request) {
70
- try {
71
- const adapter = await getHazoConnect();
72
- const configService = createCrudService(adapter, 'hazo_config');
73
- const body = await request.json();
74
- const { config_key, value, scope_id = null } = body;
75
- if (!config_key) {
76
- return errResponse('config_key is required', 400);
77
- }
78
- if (value === undefined) {
79
- return errResponse('value is required', 400);
80
- }
81
- const config_value = typeof value === 'string' ? value : JSON.stringify(value);
82
- const now = new Date().toISOString();
83
- // Find existing row for this key+scope
84
- const existing = await configService.findBy({ config_key, scope_id });
85
- let row;
86
- if (existing.length > 0) {
87
- const updated = await configService.updateById(existing[0].id, {
88
- config_value,
89
- changed_at: now,
90
- });
91
- row = Array.isArray(updated) ? updated[0] : updated;
92
- }
93
- else {
94
- const inserted = await configService.insert({
95
- id: generateUUID(),
96
- config_key,
97
- config_value,
98
- scope_id,
99
- created_at: now,
100
- changed_at: null,
101
- });
102
- row = Array.isArray(inserted) ? inserted[0] : inserted;
103
- }
104
- let parsed;
92
+ return withContext({ correlationId: getCorrelationId() ?? generateRequestId() }, async () => {
105
93
  try {
106
- parsed = JSON.parse(row.config_value);
94
+ const adapter = await getHazoConnect();
95
+ const configService = createCrudService(adapter, 'hazo_config');
96
+ const body = await request.json();
97
+ const { config_key, value, scope_id = null } = body;
98
+ if (!config_key) {
99
+ throw new HazoValidationError({
100
+ code: 'HAZO_IHELP_VALIDATION_ERROR',
101
+ pkg: 'hazo_ihelp',
102
+ message: 'config_key is required',
103
+ });
104
+ }
105
+ if (value === undefined) {
106
+ throw new HazoValidationError({
107
+ code: 'HAZO_IHELP_VALIDATION_ERROR',
108
+ pkg: 'hazo_ihelp',
109
+ message: 'value is required',
110
+ });
111
+ }
112
+ const config_value = typeof value === 'string' ? value : JSON.stringify(value);
113
+ const now = new Date().toISOString();
114
+ // Find existing row for this key+scope
115
+ const existing = await configService.findBy({ config_key, scope_id });
116
+ let row;
117
+ let action;
118
+ if (existing.length > 0) {
119
+ const updated = await configService.updateById(existing[0].id, {
120
+ config_value,
121
+ changed_at: now,
122
+ });
123
+ row = Array.isArray(updated) ? updated[0] : updated;
124
+ action = 'updated';
125
+ }
126
+ else {
127
+ const inserted = await configService.insert({
128
+ id: generateUUID(),
129
+ config_key,
130
+ config_value,
131
+ scope_id,
132
+ created_at: now,
133
+ changed_at: null,
134
+ });
135
+ row = Array.isArray(inserted) ? inserted[0] : inserted;
136
+ action = 'created';
137
+ }
138
+ logger.info(`config.${action}`, { config_key, scope_id, config_id: row.id });
139
+ let parsed;
140
+ try {
141
+ parsed = JSON.parse(row.config_value);
142
+ }
143
+ catch {
144
+ parsed = row.config_value;
145
+ }
146
+ return NextResponse.json({
147
+ success: true,
148
+ data: { id: row.id, config_key: row.config_key, value: parsed, scope_id: row.scope_id },
149
+ });
107
150
  }
108
- catch {
109
- parsed = row.config_value;
151
+ catch (err) {
152
+ return handleError(logger, 'config.put.failed', err);
110
153
  }
111
- return NextResponse.json({
112
- success: true,
113
- data: { id: row.id, config_key: row.config_key, value: parsed, scope_id: row.scope_id },
114
- });
115
- }
116
- catch (err) {
117
- return errResponse(err?.message || 'Failed to save config', 500);
118
- }
154
+ });
119
155
  }
120
156
  return { GET, PUT };
121
157
  }
@@ -1 +1 @@
1
- {"version":3,"file":"create_config_handler.js","sourceRoot":"","sources":["../../src/api/create_config_handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create_config_handler.js","sourceRoot":"","sources":["../../src/api/create_config_handler.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,10 @@
5
5
  * Tags and context mappings are stored as JSON columns directly on the
6
6
  * topics table — no separate join tables required.
7
7
  *
8
+ * Every handler wraps its body with hazo_core's `withContext` so the
9
+ * correlation ID flows through every nested log call and downstream
10
+ * `fetchWithRequestId` outbound request.
11
+ *
8
12
  * @example
9
13
  * ```typescript
10
14
  * // app/api/ihelp/topics/route.ts
@@ -18,18 +22,6 @@
18
22
  * });
19
23
  *
20
24
  * export { GET, POST };
21
- *
22
- * // app/api/ihelp/topics/[id]/route.ts
23
- * import { createIhelpHandler } from 'hazo_ihelp/api';
24
- * import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
25
- *
26
- * export const dynamic = 'force-dynamic';
27
- *
28
- * const { PATCH, DELETE } = createIhelpHandler({
29
- * getHazoConnect: () => getHazoConnectSingleton(),
30
- * });
31
- *
32
- * export { PATCH, DELETE };
33
25
  * ```
34
26
  */
35
27
  import { NextRequest, NextResponse } from 'next/server';
@@ -1 +1 @@
1
- {"version":3,"file":"create_ihelp_handler.d.ts","sourceRoot":"","sources":["../../src/api/create_ihelp_handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EACV,yBAAyB,EACzB,gBAAgB,EAChB,UAAU,EAIX,MAAM,mBAAmB,CAAC;AAwD3B;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB;mBAmCxD,WAAW,KACnB,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC;oBAgG1D,WAAW,KACnB,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;qBAiF3C,WAAW,WACX;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,EAAE,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KAC5C,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;sBAgF3C,WAAW,WACX;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,EAAE,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KAC5C,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;EA6BjD"}
1
+ {"version":3,"file":"create_ihelp_handler.d.ts","sourceRoot":"","sources":["../../src/api/create_ihelp_handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAWxD,OAAO,KAAK,EACV,yBAAyB,EACzB,gBAAgB,EAChB,UAAU,EAIX,MAAM,mBAAmB,CAAC;AA+D3B;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB;mBAuCxD,WAAW,KACnB,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC;oBAoG1D,WAAW,KACnB,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;qBAuF3C,WAAW,WACX;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,EAAE,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KAC5C,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;sBA2F3C,WAAW,WACX;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,EAAE,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KAC5C,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;EAkCjD"}