@open-mercato/core 0.4.2-canary-dfe4d5e386 → 0.4.2-canary-3bc476d868

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.
@@ -1,5 +1,5 @@
1
1
  import { executeActionSchema } from "../../../data/validators.js";
2
- import { actionResultResponseSchema } from "../../openapi.js";
2
+ import { actionResultResponseSchema, errorResponseSchema } from "../../openapi.js";
3
3
  import { resolveNotificationContext } from "../../../lib/routeHelpers.js";
4
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
5
  const metadata = {
@@ -56,7 +56,12 @@ const openApi = {
56
56
  }
57
57
  },
58
58
  400: {
59
- description: "Action not found or failed"
59
+ description: "Action not found or failed",
60
+ content: {
61
+ "application/json": {
62
+ schema: errorResponseSchema
63
+ }
64
+ }
60
65
  }
61
66
  }
62
67
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/notifications/api/%5Bid%5D/action/route.ts"],
4
- "sourcesContent": ["import { executeActionSchema } from '../../../data/validators'\nimport { actionResultResponseSchema } from '../../openapi'\nimport { resolveNotificationContext } from '../../../lib/routeHelpers'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nexport const metadata = {\n POST: { requireAuth: true },\n}\n\nexport async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {\n const { id } = await params\n const { service, scope } = await resolveNotificationContext(req)\n\n const body = await req.json().catch(() => ({}))\n const input = executeActionSchema.parse(body)\n\n try {\n const { notification, result } = await service.executeAction(id, input, scope)\n\n const action = notification.actionData?.actions?.find((a) => a.id === input.actionId)\n const href = action?.href?.replace('{sourceEntityId}', notification.sourceEntityId ?? '')\n\n return Response.json({\n ok: true,\n result,\n href,\n })\n } catch (error) {\n const { t } = await resolveTranslations()\n const fallback = t('notifications.error.action', 'Failed to execute action')\n const message = error instanceof Error && error.message ? error.message : fallback\n return Response.json({ error: message }, { status: 400 })\n }\n}\n\nexport const openApi = {\n POST: {\n summary: 'Execute notification action',\n tags: ['Notifications'],\n parameters: [\n {\n name: 'id',\n in: 'path',\n required: true,\n schema: { type: 'string', format: 'uuid' },\n },\n ],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: executeActionSchema,\n },\n },\n },\n responses: {\n 200: {\n description: 'Action executed successfully',\n content: {\n 'application/json': {\n schema: actionResultResponseSchema,\n },\n },\n },\n 400: {\n description: 'Action not found or failed',\n },\n },\n },\n}\n"],
5
- "mappings": "AAAA,SAAS,2BAA2B;AACpC,SAAS,kCAAkC;AAC3C,SAAS,kCAAkC;AAC3C,SAAS,2BAA2B;AAE7B,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,KAAK;AAC5B;AAEA,eAAsB,KAAK,KAAc,EAAE,OAAO,GAAwC;AACxF,QAAM,EAAE,GAAG,IAAI,MAAM;AACrB,QAAM,EAAE,SAAS,MAAM,IAAI,MAAM,2BAA2B,GAAG;AAE/D,QAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,QAAM,QAAQ,oBAAoB,MAAM,IAAI;AAE5C,MAAI;AACF,UAAM,EAAE,cAAc,OAAO,IAAI,MAAM,QAAQ,cAAc,IAAI,OAAO,KAAK;AAE7E,UAAM,SAAS,aAAa,YAAY,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,QAAQ;AACpF,UAAM,OAAO,QAAQ,MAAM,QAAQ,oBAAoB,aAAa,kBAAkB,EAAE;AAExF,WAAO,SAAS,KAAK;AAAA,MACnB,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,UAAM,WAAW,EAAE,8BAA8B,0BAA0B;AAC3E,UAAM,UAAU,iBAAiB,SAAS,MAAM,UAAU,MAAM,UAAU;AAC1E,WAAO,SAAS,KAAK,EAAE,OAAO,QAAQ,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC1D;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM;AAAA,IACJ,SAAS;AAAA,IACT,MAAM,CAAC,eAAe;AAAA,IACtB,YAAY;AAAA,MACV;AAAA,QACE,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,QAAQ,EAAE,MAAM,UAAU,QAAQ,OAAO;AAAA,MAC3C;AAAA,IACF;AAAA,IACA,aAAa;AAAA,MACX,UAAU;AAAA,MACV,SAAS;AAAA,QACP,oBAAoB;AAAA,UAClB,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,IACA,WAAW;AAAA,MACT,KAAK;AAAA,QACH,aAAa;AAAA,QACb,SAAS;AAAA,UACP,oBAAoB;AAAA,YAClB,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,MACA,KAAK;AAAA,QACH,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { executeActionSchema } from '../../../data/validators'\nimport { actionResultResponseSchema, errorResponseSchema } from '../../openapi'\nimport { resolveNotificationContext } from '../../../lib/routeHelpers'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nexport const metadata = {\n POST: { requireAuth: true },\n}\n\nexport async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {\n const { id } = await params\n const { service, scope } = await resolveNotificationContext(req)\n\n const body = await req.json().catch(() => ({}))\n const input = executeActionSchema.parse(body)\n\n try {\n const { notification, result } = await service.executeAction(id, input, scope)\n\n const action = notification.actionData?.actions?.find((a) => a.id === input.actionId)\n const href = action?.href?.replace('{sourceEntityId}', notification.sourceEntityId ?? '')\n\n return Response.json({\n ok: true,\n result,\n href,\n })\n } catch (error) {\n const { t } = await resolveTranslations()\n const fallback = t('notifications.error.action', 'Failed to execute action')\n const message = error instanceof Error && error.message ? error.message : fallback\n return Response.json({ error: message }, { status: 400 })\n }\n}\n\nexport const openApi = {\n POST: {\n summary: 'Execute notification action',\n tags: ['Notifications'],\n parameters: [\n {\n name: 'id',\n in: 'path',\n required: true,\n schema: { type: 'string', format: 'uuid' },\n },\n ],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: executeActionSchema,\n },\n },\n },\n responses: {\n 200: {\n description: 'Action executed successfully',\n content: {\n 'application/json': {\n schema: actionResultResponseSchema,\n },\n },\n },\n 400: {\n description: 'Action not found or failed',\n content: {\n 'application/json': {\n schema: errorResponseSchema,\n },\n },\n },\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,2BAA2B;AACpC,SAAS,4BAA4B,2BAA2B;AAChE,SAAS,kCAAkC;AAC3C,SAAS,2BAA2B;AAE7B,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,KAAK;AAC5B;AAEA,eAAsB,KAAK,KAAc,EAAE,OAAO,GAAwC;AACxF,QAAM,EAAE,GAAG,IAAI,MAAM;AACrB,QAAM,EAAE,SAAS,MAAM,IAAI,MAAM,2BAA2B,GAAG;AAE/D,QAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,QAAM,QAAQ,oBAAoB,MAAM,IAAI;AAE5C,MAAI;AACF,UAAM,EAAE,cAAc,OAAO,IAAI,MAAM,QAAQ,cAAc,IAAI,OAAO,KAAK;AAE7E,UAAM,SAAS,aAAa,YAAY,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,QAAQ;AACpF,UAAM,OAAO,QAAQ,MAAM,QAAQ,oBAAoB,aAAa,kBAAkB,EAAE;AAExF,WAAO,SAAS,KAAK;AAAA,MACnB,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,UAAM,WAAW,EAAE,8BAA8B,0BAA0B;AAC3E,UAAM,UAAU,iBAAiB,SAAS,MAAM,UAAU,MAAM,UAAU;AAC1E,WAAO,SAAS,KAAK,EAAE,OAAO,QAAQ,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC1D;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM;AAAA,IACJ,SAAS;AAAA,IACT,MAAM,CAAC,eAAe;AAAA,IACtB,YAAY;AAAA,MACV;AAAA,QACE,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,QAAQ,EAAE,MAAM,UAAU,QAAQ,OAAO;AAAA,MAC3C;AAAA,IACF;AAAA,IACA,aAAa;AAAA,MACX,UAAU;AAAA,MACV,SAAS;AAAA,QACP,oBAAoB;AAAA,UAClB,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,IACA,WAAW;AAAA,MACT,KAAK;AAAA,QACH,aAAa;AAAA,QACb,SAAS;AAAA,UACP,oBAAoB;AAAA,YAClB,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,MACA,KAAK;AAAA,QACH,aAAa;AAAA,QACb,SAAS;AAAA,UACP,oBAAoB;AAAA,YAClB,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,11 @@
1
1
  import { z } from "zod";
2
2
  import { createCrudOpenApiFactory, createPagedListResponseSchema } from "@open-mercato/shared/lib/openapi/crud";
3
- import { listNotificationsSchema, createNotificationSchema, executeActionSchema } from "../data/validators.js";
3
+ import {
4
+ listNotificationsSchema,
5
+ createNotificationSchema,
6
+ executeActionSchema,
7
+ notificationDeliveryConfigSchema
8
+ } from "../data/validators.js";
4
9
  const buildNotificationsCrudOpenApi = createCrudOpenApiFactory({
5
10
  defaultTag: "Notifications"
6
11
  });
@@ -35,6 +40,9 @@ const notificationItemSchema = z.object({
35
40
  const okResponseSchema = z.object({
36
41
  ok: z.boolean()
37
42
  });
43
+ const errorResponseSchema = z.object({
44
+ error: z.string()
45
+ });
38
46
  const unreadCountResponseSchema = z.object({
39
47
  unreadCount: z.number()
40
48
  });
@@ -43,14 +51,25 @@ const actionResultResponseSchema = z.object({
43
51
  result: z.unknown().optional(),
44
52
  href: z.string().optional()
45
53
  });
54
+ const notificationSettingsResponseSchema = z.object({
55
+ settings: notificationDeliveryConfigSchema
56
+ });
57
+ const notificationSettingsUpdateResponseSchema = z.object({
58
+ ok: z.boolean(),
59
+ settings: notificationDeliveryConfigSchema
60
+ });
46
61
  export {
47
62
  actionResultResponseSchema,
48
63
  buildNotificationsCrudOpenApi,
49
64
  createNotificationSchema,
50
65
  createPagedListResponseSchema,
66
+ errorResponseSchema,
51
67
  executeActionSchema,
52
68
  listNotificationsSchema,
69
+ notificationDeliveryConfigSchema,
53
70
  notificationItemSchema,
71
+ notificationSettingsResponseSchema,
72
+ notificationSettingsUpdateResponseSchema,
54
73
  okResponseSchema,
55
74
  unreadCountResponseSchema
56
75
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/notifications/api/openapi.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { createCrudOpenApiFactory, createPagedListResponseSchema } from '@open-mercato/shared/lib/openapi/crud'\nimport { listNotificationsSchema, createNotificationSchema, executeActionSchema } from '../data/validators'\n\nexport const buildNotificationsCrudOpenApi = createCrudOpenApiFactory({\n defaultTag: 'Notifications',\n})\n\nexport const notificationItemSchema = z.object({\n id: z.string().uuid(),\n type: z.string(),\n title: z.string(),\n body: z.string().nullable().optional(),\n titleKey: z.string().nullable().optional(),\n bodyKey: z.string().nullable().optional(),\n titleVariables: z.record(z.string(), z.string()).nullable().optional(),\n bodyVariables: z.record(z.string(), z.string()).nullable().optional(),\n icon: z.string().nullable().optional(),\n severity: z.string(),\n status: z.string(),\n actions: z.array(z.object({\n id: z.string(),\n label: z.string(),\n labelKey: z.string().optional(),\n variant: z.string().optional(),\n icon: z.string().optional(),\n })),\n primaryActionId: z.string().optional(),\n sourceModule: z.string().nullable().optional(),\n sourceEntityType: z.string().nullable().optional(),\n sourceEntityId: z.string().uuid().nullable().optional(),\n linkHref: z.string().nullable().optional(),\n createdAt: z.string(),\n readAt: z.string().nullable().optional(),\n actionTaken: z.string().nullable().optional(),\n})\n\nexport const okResponseSchema = z.object({\n ok: z.boolean(),\n})\n\nexport const unreadCountResponseSchema = z.object({\n unreadCount: z.number(),\n})\n\nexport const actionResultResponseSchema = z.object({\n ok: z.boolean(),\n result: z.unknown().optional(),\n href: z.string().optional(),\n})\n\nexport { createPagedListResponseSchema, listNotificationsSchema, createNotificationSchema, executeActionSchema }\n"],
5
- "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,0BAA0B,qCAAqC;AACxE,SAAS,yBAAyB,0BAA0B,2BAA2B;AAEhF,MAAM,gCAAgC,yBAAyB;AAAA,EACpE,YAAY;AACd,CAAC;AAEM,MAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACrC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACzC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACxC,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,EACrE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,EACpE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACrC,UAAU,EAAE,OAAO;AAAA,EACnB,QAAQ,EAAE,OAAO;AAAA,EACjB,SAAS,EAAE,MAAM,EAAE,OAAO;AAAA,IACxB,IAAI,EAAE,OAAO;AAAA,IACb,OAAO,EAAE,OAAO;AAAA,IAChB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,CAAC,CAAC;AAAA,EACF,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC7C,kBAAkB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACjD,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,EACtD,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACzC,WAAW,EAAE,OAAO;AAAA,EACpB,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACvC,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC9C,CAAC;AAEM,MAAM,mBAAmB,EAAE,OAAO;AAAA,EACvC,IAAI,EAAE,QAAQ;AAChB,CAAC;AAEM,MAAM,4BAA4B,EAAE,OAAO;AAAA,EAChD,aAAa,EAAE,OAAO;AACxB,CAAC;AAEM,MAAM,6BAA6B,EAAE,OAAO;AAAA,EACjD,IAAI,EAAE,QAAQ;AAAA,EACd,QAAQ,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC7B,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { createCrudOpenApiFactory, createPagedListResponseSchema } from '@open-mercato/shared/lib/openapi/crud'\nimport {\n listNotificationsSchema,\n createNotificationSchema,\n executeActionSchema,\n notificationDeliveryConfigSchema,\n} from '../data/validators'\n\nexport const buildNotificationsCrudOpenApi = createCrudOpenApiFactory({\n defaultTag: 'Notifications',\n})\n\nexport const notificationItemSchema = z.object({\n id: z.string().uuid(),\n type: z.string(),\n title: z.string(),\n body: z.string().nullable().optional(),\n titleKey: z.string().nullable().optional(),\n bodyKey: z.string().nullable().optional(),\n titleVariables: z.record(z.string(), z.string()).nullable().optional(),\n bodyVariables: z.record(z.string(), z.string()).nullable().optional(),\n icon: z.string().nullable().optional(),\n severity: z.string(),\n status: z.string(),\n actions: z.array(z.object({\n id: z.string(),\n label: z.string(),\n labelKey: z.string().optional(),\n variant: z.string().optional(),\n icon: z.string().optional(),\n })),\n primaryActionId: z.string().optional(),\n sourceModule: z.string().nullable().optional(),\n sourceEntityType: z.string().nullable().optional(),\n sourceEntityId: z.string().uuid().nullable().optional(),\n linkHref: z.string().nullable().optional(),\n createdAt: z.string(),\n readAt: z.string().nullable().optional(),\n actionTaken: z.string().nullable().optional(),\n})\n\nexport const okResponseSchema = z.object({\n ok: z.boolean(),\n})\n\nexport const errorResponseSchema = z.object({\n error: z.string(),\n})\n\nexport const unreadCountResponseSchema = z.object({\n unreadCount: z.number(),\n})\n\nexport const actionResultResponseSchema = z.object({\n ok: z.boolean(),\n result: z.unknown().optional(),\n href: z.string().optional(),\n})\n\nexport const notificationSettingsResponseSchema = z.object({\n settings: notificationDeliveryConfigSchema,\n})\n\nexport const notificationSettingsUpdateResponseSchema = z.object({\n ok: z.boolean(),\n settings: notificationDeliveryConfigSchema,\n})\n\nexport {\n createPagedListResponseSchema,\n listNotificationsSchema,\n createNotificationSchema,\n executeActionSchema,\n notificationDeliveryConfigSchema,\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,0BAA0B,qCAAqC;AACxE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,gCAAgC,yBAAyB;AAAA,EACpE,YAAY;AACd,CAAC;AAEM,MAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACrC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACzC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACxC,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,EACrE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,EACpE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACrC,UAAU,EAAE,OAAO;AAAA,EACnB,QAAQ,EAAE,OAAO;AAAA,EACjB,SAAS,EAAE,MAAM,EAAE,OAAO;AAAA,IACxB,IAAI,EAAE,OAAO;AAAA,IACb,OAAO,EAAE,OAAO;AAAA,IAChB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,CAAC,CAAC;AAAA,EACF,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC7C,kBAAkB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACjD,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,EACtD,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACzC,WAAW,EAAE,OAAO;AAAA,EACpB,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACvC,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC9C,CAAC;AAEM,MAAM,mBAAmB,EAAE,OAAO;AAAA,EACvC,IAAI,EAAE,QAAQ;AAChB,CAAC;AAEM,MAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,OAAO,EAAE,OAAO;AAClB,CAAC;AAEM,MAAM,4BAA4B,EAAE,OAAO;AAAA,EAChD,aAAa,EAAE,OAAO;AACxB,CAAC;AAEM,MAAM,6BAA6B,EAAE,OAAO;AAAA,EACjD,IAAI,EAAE,QAAQ;AAAA,EACd,QAAQ,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC7B,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAEM,MAAM,qCAAqC,EAAE,OAAO;AAAA,EACzD,UAAU;AACZ,CAAC;AAEM,MAAM,2CAA2C,EAAE,OAAO;AAAA,EAC/D,IAAI,EAAE,QAAQ;AAAA,EACd,UAAU;AACZ,CAAC;",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,11 @@ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
3
3
  import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
5
  import { notificationDeliveryConfigSchema } from "../../data/validators.js";
6
+ import {
7
+ errorResponseSchema,
8
+ notificationSettingsResponseSchema,
9
+ notificationSettingsUpdateResponseSchema
10
+ } from "../openapi.js";
6
11
  import {
7
12
  DEFAULT_NOTIFICATION_DELIVERY_CONFIG,
8
13
  resolveNotificationDeliveryConfig,
@@ -76,14 +81,68 @@ const openApi = {
76
81
  summary: "Get notification delivery settings",
77
82
  tags: ["Notifications"],
78
83
  responses: {
79
- 200: { description: "Current delivery settings" }
84
+ 200: {
85
+ description: "Current delivery settings",
86
+ content: {
87
+ "application/json": {
88
+ schema: notificationSettingsResponseSchema
89
+ }
90
+ }
91
+ },
92
+ 401: {
93
+ description: "Unauthorized",
94
+ content: {
95
+ "application/json": {
96
+ schema: errorResponseSchema
97
+ }
98
+ }
99
+ }
80
100
  }
81
101
  },
82
102
  POST: {
83
103
  summary: "Update notification delivery settings",
84
104
  tags: ["Notifications"],
105
+ requestBody: {
106
+ required: true,
107
+ content: {
108
+ "application/json": {
109
+ schema: notificationDeliveryConfigSchema
110
+ }
111
+ }
112
+ },
85
113
  responses: {
86
- 200: { description: "Delivery settings updated" }
114
+ 200: {
115
+ description: "Delivery settings updated",
116
+ content: {
117
+ "application/json": {
118
+ schema: notificationSettingsUpdateResponseSchema
119
+ }
120
+ }
121
+ },
122
+ 400: {
123
+ description: "Invalid request body",
124
+ content: {
125
+ "application/json": {
126
+ schema: errorResponseSchema
127
+ }
128
+ }
129
+ },
130
+ 401: {
131
+ description: "Unauthorized",
132
+ content: {
133
+ "application/json": {
134
+ schema: errorResponseSchema
135
+ }
136
+ }
137
+ },
138
+ 500: {
139
+ description: "Internal error",
140
+ content: {
141
+ "application/json": {
142
+ schema: errorResponseSchema
143
+ }
144
+ }
145
+ }
87
146
  }
88
147
  }
89
148
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/notifications/api/settings/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { notificationDeliveryConfigSchema } from '../../data/validators'\nimport {\n DEFAULT_NOTIFICATION_DELIVERY_CONFIG,\n resolveNotificationDeliveryConfig,\n saveNotificationDeliveryConfig,\n} from '../../lib/deliveryConfig'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['notifications.manage'] },\n POST: { requireAuth: true, requireFeatures: ['notifications.manage'] },\n}\n\nconst unauthorized = async () => {\n const { t } = await resolveTranslations()\n return NextResponse.json({ error: t('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) return await unauthorized()\n\n const container = await createRequestContainer()\n try {\n const settings = await resolveNotificationDeliveryConfig(container, {\n defaultValue: DEFAULT_NOTIFICATION_DELIVERY_CONFIG,\n })\n return NextResponse.json({ settings })\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n}\n\nexport async function POST(req: Request) {\n const { t } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) return await unauthorized()\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return NextResponse.json(\n { error: t('api.errors.invalidPayload', 'Invalid request body') },\n { status: 400 }\n )\n }\n\n const parsed = notificationDeliveryConfigSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json(\n { error: t('notifications.delivery.settings.invalid', 'Invalid delivery settings') },\n { status: 400 }\n )\n }\n\n const container = await createRequestContainer()\n try {\n await saveNotificationDeliveryConfig(container, parsed.data)\n const settings = await resolveNotificationDeliveryConfig(container, {\n defaultValue: DEFAULT_NOTIFICATION_DELIVERY_CONFIG,\n })\n return NextResponse.json({ ok: true, settings })\n } catch (error) {\n return NextResponse.json(\n { error: error instanceof Error ? error.message : t('api.errors.internal', 'Internal error') },\n { status: 500 }\n )\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n}\n\nexport const openApi = {\n GET: {\n summary: 'Get notification delivery settings',\n tags: ['Notifications'],\n responses: {\n 200: { description: 'Current delivery settings' },\n },\n },\n POST: {\n summary: 'Update notification delivery settings',\n tags: ['Notifications'],\n responses: {\n 200: { description: 'Delivery settings updated' },\n },\n },\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,2BAA2B;AACpC,SAAS,wCAAwC;AACjD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AAAA,EACpE,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AACvE;AAEA,MAAM,eAAe,YAAY;AAC/B,QAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,SAAO,aAAa,KAAK,EAAE,OAAO,EAAE,2BAA2B,cAAc,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AACnG;AAEA,eAAsB,IAAI,KAAc;AACtC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,IAAK,QAAO,MAAM,aAAa;AAE1C,QAAM,YAAY,MAAM,uBAAuB;AAC/C,MAAI;AACF,UAAM,WAAW,MAAM,kCAAkC,WAAW;AAAA,MAClE,cAAc;AAAA,IAChB,CAAC;AACD,WAAO,aAAa,KAAK,EAAE,SAAS,CAAC;AAAA,EACvC,UAAE;AACA,UAAM,aAAa;AACnB,QAAI,OAAO,WAAW,YAAY,YAAY;AAC5C,YAAM,WAAW,QAAQ;AAAA,IAC3B;AAAA,EACF;AACF;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,IAAK,QAAO,MAAM,aAAa;AAE1C,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AACN,WAAO,aAAa;AAAA,MAClB,EAAE,OAAO,EAAE,6BAA6B,sBAAsB,EAAE;AAAA,MAChE,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,SAAS,iCAAiC,UAAU,IAAI;AAC9D,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,aAAa;AAAA,MAClB,EAAE,OAAO,EAAE,2CAA2C,2BAA2B,EAAE;AAAA,MACnF,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,MAAI;AACF,UAAM,+BAA+B,WAAW,OAAO,IAAI;AAC3D,UAAM,WAAW,MAAM,kCAAkC,WAAW;AAAA,MAClE,cAAc;AAAA,IAChB,CAAC;AACD,WAAO,aAAa,KAAK,EAAE,IAAI,MAAM,SAAS,CAAC;AAAA,EACjD,SAAS,OAAO;AACd,WAAO,aAAa;AAAA,MAClB,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,EAAE,uBAAuB,gBAAgB,EAAE;AAAA,MAC7F,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF,UAAE;AACA,UAAM,aAAa;AACnB,QAAI,OAAO,WAAW,YAAY,YAAY;AAC5C,YAAM,WAAW,QAAQ;AAAA,IAC3B;AAAA,EACF;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,KAAK;AAAA,IACH,SAAS;AAAA,IACT,MAAM,CAAC,eAAe;AAAA,IACtB,WAAW;AAAA,MACT,KAAK,EAAE,aAAa,4BAA4B;AAAA,IAClD;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ,SAAS;AAAA,IACT,MAAM,CAAC,eAAe;AAAA,IACtB,WAAW;AAAA,MACT,KAAK,EAAE,aAAa,4BAA4B;AAAA,IAClD;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { notificationDeliveryConfigSchema } from '../../data/validators'\nimport {\n errorResponseSchema,\n notificationSettingsResponseSchema,\n notificationSettingsUpdateResponseSchema,\n} from '../openapi'\nimport {\n DEFAULT_NOTIFICATION_DELIVERY_CONFIG,\n resolveNotificationDeliveryConfig,\n saveNotificationDeliveryConfig,\n} from '../../lib/deliveryConfig'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['notifications.manage'] },\n POST: { requireAuth: true, requireFeatures: ['notifications.manage'] },\n}\n\nconst unauthorized = async () => {\n const { t } = await resolveTranslations()\n return NextResponse.json({ error: t('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) return await unauthorized()\n\n const container = await createRequestContainer()\n try {\n const settings = await resolveNotificationDeliveryConfig(container, {\n defaultValue: DEFAULT_NOTIFICATION_DELIVERY_CONFIG,\n })\n return NextResponse.json({ settings })\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n}\n\nexport async function POST(req: Request) {\n const { t } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) return await unauthorized()\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return NextResponse.json(\n { error: t('api.errors.invalidPayload', 'Invalid request body') },\n { status: 400 }\n )\n }\n\n const parsed = notificationDeliveryConfigSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json(\n { error: t('notifications.delivery.settings.invalid', 'Invalid delivery settings') },\n { status: 400 }\n )\n }\n\n const container = await createRequestContainer()\n try {\n await saveNotificationDeliveryConfig(container, parsed.data)\n const settings = await resolveNotificationDeliveryConfig(container, {\n defaultValue: DEFAULT_NOTIFICATION_DELIVERY_CONFIG,\n })\n return NextResponse.json({ ok: true, settings })\n } catch (error) {\n return NextResponse.json(\n { error: error instanceof Error ? error.message : t('api.errors.internal', 'Internal error') },\n { status: 500 }\n )\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n}\n\nexport const openApi = {\n GET: {\n summary: 'Get notification delivery settings',\n tags: ['Notifications'],\n responses: {\n 200: {\n description: 'Current delivery settings',\n content: {\n 'application/json': {\n schema: notificationSettingsResponseSchema,\n },\n },\n },\n 401: {\n description: 'Unauthorized',\n content: {\n 'application/json': {\n schema: errorResponseSchema,\n },\n },\n },\n },\n },\n POST: {\n summary: 'Update notification delivery settings',\n tags: ['Notifications'],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: notificationDeliveryConfigSchema,\n },\n },\n },\n responses: {\n 200: {\n description: 'Delivery settings updated',\n content: {\n 'application/json': {\n schema: notificationSettingsUpdateResponseSchema,\n },\n },\n },\n 400: {\n description: 'Invalid request body',\n content: {\n 'application/json': {\n schema: errorResponseSchema,\n },\n },\n },\n 401: {\n description: 'Unauthorized',\n content: {\n 'application/json': {\n schema: errorResponseSchema,\n },\n },\n },\n 500: {\n description: 'Internal error',\n content: {\n 'application/json': {\n schema: errorResponseSchema,\n },\n },\n },\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.4.2-canary-dfe4d5e386",
3
+ "version": "0.4.2-canary-3bc476d868",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -207,7 +207,7 @@
207
207
  }
208
208
  },
209
209
  "dependencies": {
210
- "@open-mercato/shared": "0.4.2-canary-dfe4d5e386",
210
+ "@open-mercato/shared": "0.4.2-canary-3bc476d868",
211
211
  "@xyflow/react": "^12.6.0",
212
212
  "date-fns": "^4.1.0",
213
213
  "date-fns-tz": "^3.2.0"
@@ -1,5 +1,5 @@
1
1
  import { executeActionSchema } from '../../../data/validators'
2
- import { actionResultResponseSchema } from '../../openapi'
2
+ import { actionResultResponseSchema, errorResponseSchema } from '../../openapi'
3
3
  import { resolveNotificationContext } from '../../../lib/routeHelpers'
4
4
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
5
5
 
@@ -64,6 +64,11 @@ export const openApi = {
64
64
  },
65
65
  400: {
66
66
  description: 'Action not found or failed',
67
+ content: {
68
+ 'application/json': {
69
+ schema: errorResponseSchema,
70
+ },
71
+ },
67
72
  },
68
73
  },
69
74
  },
@@ -1,6 +1,11 @@
1
1
  import { z } from 'zod'
2
2
  import { createCrudOpenApiFactory, createPagedListResponseSchema } from '@open-mercato/shared/lib/openapi/crud'
3
- import { listNotificationsSchema, createNotificationSchema, executeActionSchema } from '../data/validators'
3
+ import {
4
+ listNotificationsSchema,
5
+ createNotificationSchema,
6
+ executeActionSchema,
7
+ notificationDeliveryConfigSchema,
8
+ } from '../data/validators'
4
9
 
5
10
  export const buildNotificationsCrudOpenApi = createCrudOpenApiFactory({
6
11
  defaultTag: 'Notifications',
@@ -39,6 +44,10 @@ export const okResponseSchema = z.object({
39
44
  ok: z.boolean(),
40
45
  })
41
46
 
47
+ export const errorResponseSchema = z.object({
48
+ error: z.string(),
49
+ })
50
+
42
51
  export const unreadCountResponseSchema = z.object({
43
52
  unreadCount: z.number(),
44
53
  })
@@ -49,4 +58,19 @@ export const actionResultResponseSchema = z.object({
49
58
  href: z.string().optional(),
50
59
  })
51
60
 
52
- export { createPagedListResponseSchema, listNotificationsSchema, createNotificationSchema, executeActionSchema }
61
+ export const notificationSettingsResponseSchema = z.object({
62
+ settings: notificationDeliveryConfigSchema,
63
+ })
64
+
65
+ export const notificationSettingsUpdateResponseSchema = z.object({
66
+ ok: z.boolean(),
67
+ settings: notificationDeliveryConfigSchema,
68
+ })
69
+
70
+ export {
71
+ createPagedListResponseSchema,
72
+ listNotificationsSchema,
73
+ createNotificationSchema,
74
+ executeActionSchema,
75
+ notificationDeliveryConfigSchema,
76
+ }
@@ -3,6 +3,11 @@ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
3
3
  import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
4
4
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
5
5
  import { notificationDeliveryConfigSchema } from '../../data/validators'
6
+ import {
7
+ errorResponseSchema,
8
+ notificationSettingsResponseSchema,
9
+ notificationSettingsUpdateResponseSchema,
10
+ } from '../openapi'
6
11
  import {
7
12
  DEFAULT_NOTIFICATION_DELIVERY_CONFIG,
8
13
  resolveNotificationDeliveryConfig,
@@ -85,14 +90,68 @@ export const openApi = {
85
90
  summary: 'Get notification delivery settings',
86
91
  tags: ['Notifications'],
87
92
  responses: {
88
- 200: { description: 'Current delivery settings' },
93
+ 200: {
94
+ description: 'Current delivery settings',
95
+ content: {
96
+ 'application/json': {
97
+ schema: notificationSettingsResponseSchema,
98
+ },
99
+ },
100
+ },
101
+ 401: {
102
+ description: 'Unauthorized',
103
+ content: {
104
+ 'application/json': {
105
+ schema: errorResponseSchema,
106
+ },
107
+ },
108
+ },
89
109
  },
90
110
  },
91
111
  POST: {
92
112
  summary: 'Update notification delivery settings',
93
113
  tags: ['Notifications'],
114
+ requestBody: {
115
+ required: true,
116
+ content: {
117
+ 'application/json': {
118
+ schema: notificationDeliveryConfigSchema,
119
+ },
120
+ },
121
+ },
94
122
  responses: {
95
- 200: { description: 'Delivery settings updated' },
123
+ 200: {
124
+ description: 'Delivery settings updated',
125
+ content: {
126
+ 'application/json': {
127
+ schema: notificationSettingsUpdateResponseSchema,
128
+ },
129
+ },
130
+ },
131
+ 400: {
132
+ description: 'Invalid request body',
133
+ content: {
134
+ 'application/json': {
135
+ schema: errorResponseSchema,
136
+ },
137
+ },
138
+ },
139
+ 401: {
140
+ description: 'Unauthorized',
141
+ content: {
142
+ 'application/json': {
143
+ schema: errorResponseSchema,
144
+ },
145
+ },
146
+ },
147
+ 500: {
148
+ description: 'Internal error',
149
+ content: {
150
+ 'application/json': {
151
+ schema: errorResponseSchema,
152
+ },
153
+ },
154
+ },
96
155
  },
97
156
  },
98
157
  }