@pfm-platform/notifications-data-access 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +42 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -79
- package/dist/index.d.ts +26 -79
- package/dist/index.js +44 -35
- package/dist/index.js.map +1 -1
- package/package.json +7 -8
package/dist/index.cjs
CHANGED
|
@@ -2,19 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var reactQuery = require('@tanstack/react-query');
|
|
4
4
|
var shared = require('@pfm-platform/shared');
|
|
5
|
-
var axios = require('axios');
|
|
6
|
-
|
|
7
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
-
|
|
9
|
-
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
10
5
|
|
|
11
6
|
// src/queries/useNotifications.ts
|
|
12
|
-
var api = axios__default.default.create({
|
|
13
|
-
baseURL: "http://localhost:3000/api",
|
|
14
|
-
headers: {
|
|
15
|
-
"Content-Type": "application/json"
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
7
|
|
|
19
8
|
// src/keys.ts
|
|
20
9
|
var notificationKeys = {
|
|
@@ -29,9 +18,9 @@ function useNotifications({ userId }, options) {
|
|
|
29
18
|
return reactQuery.useQuery({
|
|
30
19
|
queryKey: notificationKeys.list(userId),
|
|
31
20
|
queryFn: async () => {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
return
|
|
21
|
+
const { data, error } = await shared.supabase.from("notifications").select("*").eq("user_id", userId).order("created_at", { ascending: false });
|
|
22
|
+
if (error) throw new Error(error.message);
|
|
23
|
+
return shared.NotificationsResponseSchema.parse(data);
|
|
35
24
|
},
|
|
36
25
|
staleTime: 1e3 * 60 * 2,
|
|
37
26
|
// 2 minutes (notifications change frequently)
|
|
@@ -42,9 +31,14 @@ function useNotificationPreferences({ userId }, options) {
|
|
|
42
31
|
return reactQuery.useQuery({
|
|
43
32
|
queryKey: notificationKeys.preferences(userId),
|
|
44
33
|
queryFn: async () => {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
const { data, error } = await shared.supabase.from("notification_preferences").select("*").eq("user_id", userId).single();
|
|
35
|
+
if (error) throw new Error(error.message);
|
|
36
|
+
const row = shared.NotificationPreferencesRowSchema.parse(data);
|
|
37
|
+
return {
|
|
38
|
+
emailNotifications: row.email_notifications,
|
|
39
|
+
pushNotifications: row.push_notifications,
|
|
40
|
+
frequency: row.frequency
|
|
41
|
+
};
|
|
48
42
|
},
|
|
49
43
|
staleTime: 1e3 * 60 * 5,
|
|
50
44
|
// 5 minutes (preferences change infrequently)
|
|
@@ -53,16 +47,16 @@ function useNotificationPreferences({ userId }, options) {
|
|
|
53
47
|
}
|
|
54
48
|
function useCreateNotification(options) {
|
|
55
49
|
const queryClient = reactQuery.useQueryClient();
|
|
56
|
-
const { mode } = shared.useAppMode();
|
|
57
50
|
return reactQuery.useMutation({
|
|
58
51
|
mutationFn: async ({ userId, data }) => {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
);
|
|
65
|
-
|
|
52
|
+
const { data: row, error } = await shared.supabase.from("notifications").insert({
|
|
53
|
+
user_id: userId,
|
|
54
|
+
message: data.message,
|
|
55
|
+
alert_type: data.alert_type,
|
|
56
|
+
...data.created_at ? { created_at: data.created_at } : {}
|
|
57
|
+
}).select().single();
|
|
58
|
+
if (error) throw new Error(error.message);
|
|
59
|
+
return shared.NotificationRowSchema.parse(row);
|
|
66
60
|
},
|
|
67
61
|
onSuccess: (_, { userId }) => {
|
|
68
62
|
queryClient.invalidateQueries({
|
|
@@ -74,20 +68,15 @@ function useCreateNotification(options) {
|
|
|
74
68
|
}
|
|
75
69
|
function useUpdateNotification(options) {
|
|
76
70
|
const queryClient = reactQuery.useQueryClient();
|
|
77
|
-
const { mode } = shared.useAppMode();
|
|
78
71
|
return reactQuery.useMutation({
|
|
79
72
|
mutationFn: async ({
|
|
80
73
|
userId,
|
|
81
74
|
notificationId,
|
|
82
75
|
data
|
|
83
76
|
}) => {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`/users/${userId}/alerts/notifications/${notificationId}`,
|
|
88
|
-
validated
|
|
89
|
-
);
|
|
90
|
-
return shared.NotificationSchema.parse(response.data);
|
|
77
|
+
const { data: row, error } = await shared.supabase.from("notifications").update(data).eq("id", notificationId).eq("user_id", userId).select().single();
|
|
78
|
+
if (error) throw new Error(error.message);
|
|
79
|
+
return shared.NotificationRowSchema.parse(row);
|
|
91
80
|
},
|
|
92
81
|
onSuccess: (_, { userId }) => {
|
|
93
82
|
queryClient.invalidateQueries({
|
|
@@ -101,7 +90,8 @@ function useDeleteNotification(options) {
|
|
|
101
90
|
const queryClient = reactQuery.useQueryClient();
|
|
102
91
|
return reactQuery.useMutation({
|
|
103
92
|
mutationFn: async ({ userId, notificationId }) => {
|
|
104
|
-
await
|
|
93
|
+
const { error } = await shared.supabase.from("notifications").delete().eq("id", notificationId).eq("user_id", userId);
|
|
94
|
+
if (error) throw new Error(error.message);
|
|
105
95
|
},
|
|
106
96
|
onSuccess: (_, { userId }) => {
|
|
107
97
|
queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });
|
|
@@ -113,9 +103,24 @@ function useUpdateNotificationPreferences(options) {
|
|
|
113
103
|
const queryClient = reactQuery.useQueryClient();
|
|
114
104
|
return reactQuery.useMutation({
|
|
115
105
|
mutationFn: async ({ userId, data }) => {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
106
|
+
const dbData = { user_id: userId };
|
|
107
|
+
if (data.emailNotifications !== void 0) {
|
|
108
|
+
dbData.email_notifications = data.emailNotifications;
|
|
109
|
+
}
|
|
110
|
+
if (data.pushNotifications !== void 0) {
|
|
111
|
+
dbData.push_notifications = data.pushNotifications;
|
|
112
|
+
}
|
|
113
|
+
if (data.frequency !== void 0) {
|
|
114
|
+
dbData.frequency = data.frequency;
|
|
115
|
+
}
|
|
116
|
+
const { data: row, error } = await shared.supabase.from("notification_preferences").upsert(dbData).select().single();
|
|
117
|
+
if (error) throw new Error(error.message);
|
|
118
|
+
const validated = shared.NotificationPreferencesRowSchema.parse(row);
|
|
119
|
+
return {
|
|
120
|
+
emailNotifications: validated.email_notifications,
|
|
121
|
+
pushNotifications: validated.push_notifications,
|
|
122
|
+
frequency: validated.frequency
|
|
123
|
+
};
|
|
119
124
|
},
|
|
120
125
|
onSuccess: (_, { userId }) => {
|
|
121
126
|
queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });
|
|
@@ -124,7 +129,6 @@ function useUpdateNotificationPreferences(options) {
|
|
|
124
129
|
});
|
|
125
130
|
}
|
|
126
131
|
|
|
127
|
-
exports.api = api;
|
|
128
132
|
exports.notificationKeys = notificationKeys;
|
|
129
133
|
exports.useCreateNotification = useCreateNotification;
|
|
130
134
|
exports.useDeleteNotification = useDeleteNotification;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/keys.ts","../src/queries/useNotifications.ts","../src/queries/useNotificationPreferences.ts","../src/mutations/useCreateNotification.ts","../src/mutations/useUpdateNotification.ts","../src/mutations/useDeleteNotification.ts","../src/mutations/useUpdateNotificationPreferences.ts"],"names":["axios","useQuery","NotificationsResponseSchema","NotificationPreferencesSchema","useQueryClient","useAppMode","useMutation","NotificationCreateSchemaAdmin","NotificationCreateSchemaUser","NotificationSchema","NotificationUpdateSchemaAdmin","NotificationUpdateSchemaUser","NotificationPreferencesUpdateSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["import axios from 'axios';\n\n/**\n * Axios instance for Notifications API\n * Base URL configured through environment variables or defaults to localhost for tests\n */\nexport const api = axios.create({\n baseURL: 'http://localhost:3000/api',\n headers: {\n 'Content-Type': 'application/json',\n },\n});\n","/**\n * Query key factory for Notifications domain\n */\nexport const notificationKeys = {\n all: ['notifications'] as const,\n lists: () => [...notificationKeys.all, 'list'] as const,\n list: (userId: string) => [...notificationKeys.lists(), userId] as const,\n preferences: (userId: string) => [...notificationKeys.all, 'preferences', userId] as const,\n};\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { Notification, NotificationsResponseSchema } from '@pfm-platform/shared';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationsParams {\n userId: string;\n}\n\n/**\n * Fetch all notifications for a user\n * GET /users/:userId/alerts/notifications\n *\n * Notifications are system-generated based on alert configurations\n * Read-only domain (no create/update operations)\n */\nexport function useNotifications(\n { userId }: UseNotificationsParams,\n options?: Omit<UseQueryOptions<Notification[]>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.list(userId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/alerts/notifications`);\n const validated = NotificationsResponseSchema.parse(response.data);\n return validated.notifications;\n },\n staleTime: 1000 * 60 * 2, // 2 minutes (notifications change frequently)\n ...options,\n });\n}\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { NotificationPreferences, NotificationPreferencesSchema } from '@pfm-platform/shared';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationPreferencesParams {\n userId: string;\n}\n\n/**\n * Fetch user notification preferences\n * GET /users/:userId/notifications/preferences\n *\n * Returns user preferences for notification delivery and frequency\n */\nexport function useNotificationPreferences(\n { userId }: UseNotificationPreferencesParams,\n options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.preferences(userId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/notifications/preferences`);\n const validated = NotificationPreferencesSchema.parse(response.data);\n return validated;\n },\n staleTime: 1000 * 60 * 5, // 5 minutes (preferences change infrequently)\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationCreateSchemaAdmin,\n NotificationCreateSchemaUser,\n NotificationSchema,\n useAppMode,\n type AlertType,\n} from '@pfm-platform/shared';\nimport type { Notification } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { notificationKeys } from '../keys';\n\n/**\n * Notification create data interface\n */\nexport interface NotificationCreate {\n message: string;\n alert_type: AlertType;\n created_at?: string;\n}\n\n/**\n * Parameters for useCreateNotification mutation\n */\nexport interface CreateNotificationParams {\n userId: string;\n data: NotificationCreate;\n}\n\n/**\n * Mutation hook for creating a new notification\n *\n * Creates a notification manually for testing purposes.\n * Uses mode switching for validation:\n * - Admin mode: Allows manual notification creation for test data\n * - User mode: Blocked (notifications are system-generated)\n *\n * @example\n * ```tsx\n * const createNotification = useCreateNotification();\n *\n * createNotification.mutate({\n * userId: 'user123',\n * data: {\n * message: 'Test notification',\n * alert_type: 'AccountThresholdAlert',\n * created_at: new Date().toISOString() // Optional\n * }\n * });\n * ```\n */\nexport function useCreateNotification(\n options?: Omit<\n UseMutationOptions<Notification, Error, CreateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNotificationParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? NotificationCreateSchemaAdmin\n : NotificationCreateSchemaUser;\n\n // Validate notification data\n const validated = schema.parse(data);\n\n // POST to create new notification\n const response = await api.post(\n `/users/${userId}/alerts/notifications`,\n validated\n );\n\n // Return created notification\n return NotificationSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications query to refetch updated list\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationUpdateSchemaAdmin,\n NotificationUpdateSchemaUser,\n NotificationSchema,\n useAppMode,\n type AlertType,\n} from '@pfm-platform/shared';\nimport type { Notification } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { notificationKeys } from '../keys';\n\n/**\n * Notification update data interface\n */\nexport interface NotificationUpdate {\n message?: string;\n alert_type?: AlertType;\n is_read?: boolean;\n}\n\n/**\n * Parameters for useUpdateNotification mutation\n */\nexport interface UpdateNotificationParams {\n userId: string;\n notificationId: number;\n data: NotificationUpdate;\n}\n\n/**\n * Mutation hook for updating a notification\n *\n * Uses mode switching for validation:\n * - Admin mode: Allows updating message and alert_type for test scenarios\n * - User mode: Allows marking notifications as read/unread\n *\n * @example\n * ```tsx\n * const updateNotification = useUpdateNotification();\n *\n * // User mode: mark as read\n * updateNotification.mutate({\n * userId: 'user123',\n * notificationId: 1,\n * data: { is_read: true }\n * });\n *\n * // Admin mode: update message\n * updateNotification.mutate({\n * userId: 'user123',\n * notificationId: 1,\n * data: { message: 'Updated test notification' }\n * });\n * ```\n */\nexport function useUpdateNotification(\n options?: Omit<\n UseMutationOptions<Notification, Error, UpdateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({\n userId,\n notificationId,\n data,\n }: UpdateNotificationParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? NotificationUpdateSchemaAdmin\n : NotificationUpdateSchemaUser;\n\n // Validate notification update data\n const validated = schema.parse(data);\n\n // PUT to update notification\n const response = await api.put(\n `/users/${userId}/alerts/notifications/${notificationId}`,\n validated\n );\n\n // Return updated notification\n return NotificationSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications query to refetch updated list\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface DeleteNotificationParams {\n userId: string;\n notificationId: number;\n}\n\n/**\n * Delete a notification\n * DELETE /users/:userId/alerts/notifications/:notificationId\n *\n * Notifications are system-generated, deletion only removes from view\n */\nexport function useDeleteNotification(\n options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, notificationId }: DeleteNotificationParams) => {\n await api.delete(`/users/${userId}/alerts/notifications/${notificationId}`);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications list to refetch without deleted item\n queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport {\n NotificationPreferences,\n NotificationPreferencesSchema,\n NotificationPreferencesUpdateSchema,\n} from '@pfm-platform/shared';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UpdateNotificationPreferencesParams {\n userId: string;\n data: Partial<NotificationPreferences>;\n}\n\n/**\n * Update user notification preferences\n * PUT /users/:userId/notifications/preferences\n *\n * Updates delivery and frequency preferences for notifications\n */\nexport function useUpdateNotificationPreferences(\n options?: UseMutationOptions<\n NotificationPreferences,\n Error,\n UpdateNotificationPreferencesParams\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: UpdateNotificationPreferencesParams) => {\n // Validate update data\n const validated = NotificationPreferencesUpdateSchema.parse(data);\n\n const response = await api.put(`/users/${userId}/notifications/preferences`, validated);\n return NotificationPreferencesSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate preferences query to refetch\n queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });\n },\n ...options,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/keys.ts","../src/queries/useNotifications.ts","../src/queries/useNotificationPreferences.ts","../src/mutations/useCreateNotification.ts","../src/mutations/useUpdateNotification.ts","../src/mutations/useDeleteNotification.ts","../src/mutations/useUpdateNotificationPreferences.ts"],"names":["useQuery","supabase","NotificationsResponseSchema","NotificationPreferencesRowSchema","useQueryClient","useMutation","NotificationRowSchema"],"mappings":";;;;;;;;AAGO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,GAAA,EAAK,CAAC,eAAe,CAAA;AAAA,EACrB,OAAO,MAAM,CAAC,GAAG,gBAAA,CAAiB,KAAK,MAAM,CAAA;AAAA,EAC7C,IAAA,EAAM,CAAC,MAAA,KAAmB,CAAC,GAAG,gBAAA,CAAiB,KAAA,IAAS,MAAM,CAAA;AAAA,EAC9D,WAAA,EAAa,CAAC,MAAA,KAAmB,CAAC,GAAG,gBAAA,CAAiB,GAAA,EAAK,eAAe,MAAM;AAClF;;;ACKO,SAAS,gBAAA,CACd,EAAE,MAAA,EAAO,EACT,OAAA,EACA;AACA,EAAA,OAAOA,mBAAA,CAAS;AAAA,IACd,QAAA,EAAU,gBAAA,CAAiB,IAAA,CAAK,MAAM,CAAA;AAAA,IACtC,SAAS,YAAY;AACnB,MAAA,MAAM,EAAE,MAAM,KAAA,EAAM,GAAI,MAAMC,eAAA,CAC3B,IAAA,CAAK,eAAe,CAAA,CACpB,MAAA,CAAO,GAAG,CAAA,CACV,EAAA,CAAG,WAAW,MAAM,CAAA,CACpB,MAAM,YAAA,EAAc,EAAE,SAAA,EAAW,KAAA,EAAO,CAAA;AAE3C,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AACxC,MAAA,OAAOC,kCAAA,CAA4B,MAAM,IAAI,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA,SAAA,EAAW,MAAO,EAAA,GAAK,CAAA;AAAA;AAAA,IACvB,GAAG;AAAA,GACJ,CAAA;AACH;ACdO,SAAS,0BAAA,CACd,EAAE,MAAA,EAAO,EACT,OAAA,EACA;AACA,EAAA,OAAOF,mBAAAA,CAAS;AAAA,IACd,QAAA,EAAU,gBAAA,CAAiB,WAAA,CAAY,MAAM,CAAA;AAAA,IAC7C,SAAS,YAAY;AACnB,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAMC,gBAC3B,IAAA,CAAK,0BAA0B,CAAA,CAC/B,MAAA,CAAO,GAAG,CAAA,CACV,EAAA,CAAG,SAAA,EAAW,MAAM,EACpB,MAAA,EAAO;AAEV,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AAExC,MAAA,MAAM,GAAA,GAAME,uCAAA,CAAiC,KAAA,CAAM,IAAI,CAAA;AAGvD,MAAA,OAAO;AAAA,QACL,oBAAoB,GAAA,CAAI,mBAAA;AAAA,QACxB,mBAAmB,GAAA,CAAI,kBAAA;AAAA,QACvB,WAAW,GAAA,CAAI;AAAA,OACjB;AAAA,IACF,CAAA;AAAA,IACA,SAAA,EAAW,MAAO,EAAA,GAAK,CAAA;AAAA;AAAA,IACvB,GAAG;AAAA,GACJ,CAAA;AACH;ACXO,SAAS,sBACd,OAAA,EAIA;AACA,EAAA,MAAM,cAAcC,yBAAA,EAAe;AAEnC,EAAA,OAAOC,sBAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,EAAE,MAAA,EAAQ,MAAK,KAAgC;AAChE,MAAA,MAAM,EAAE,IAAA,EAAM,GAAA,EAAK,KAAA,EAAM,GAAI,MAAMJ,eAAA,CAChC,IAAA,CAAK,eAAe,CAAA,CACpB,MAAA,CAAO;AAAA,QACN,OAAA,EAAS,MAAA;AAAA,QACT,SAAS,IAAA,CAAK,OAAA;AAAA,QACd,YAAY,IAAA,CAAK,UAAA;AAAA,QACjB,GAAI,KAAK,UAAA,GAAa,EAAE,YAAY,IAAA,CAAK,UAAA,KAAe;AAAC,OACzB,CAAA,CACjC,MAAA,EAAO,CACP,MAAA,EAAO;AAEV,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AACxC,MAAA,OAAOK,4BAAA,CAAsB,MAAM,GAAG,CAAA;AAAA,IACxC,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAC5B,MAAA,WAAA,CAAY,iBAAA,CAAkB;AAAA,QAC5B,QAAA,EAAU,gBAAA,CAAiB,IAAA,CAAK,MAAM;AAAA,OACvC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;AC9BO,SAAS,sBACd,OAAA,EAIA;AACA,EAAA,MAAM,cAAcF,yBAAAA,EAAe;AAEnC,EAAA,OAAOC,sBAAAA,CAAY;AAAA,IACjB,YAAY,OAAO;AAAA,MACjB,MAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACF,KAAgC;AAC9B,MAAA,MAAM,EAAE,MAAM,GAAA,EAAK,KAAA,KAAU,MAAMJ,eAAA,CAChC,IAAA,CAAK,eAAe,CAAA,CACpB,MAAA,CAAO,IAAqC,CAAA,CAC5C,EAAA,CAAG,IAAA,EAAM,cAAc,CAAA,CACvB,EAAA,CAAG,WAAW,MAAM,CAAA,CACpB,MAAA,EAAO,CACP,MAAA,EAAO;AAEV,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AACxC,MAAA,OAAOK,4BAAAA,CAAsB,MAAM,GAAG,CAAA;AAAA,IACxC,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAC5B,MAAA,WAAA,CAAY,iBAAA,CAAkB;AAAA,QAC5B,QAAA,EAAU,gBAAA,CAAiB,IAAA,CAAK,MAAM;AAAA,OACvC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;ACtDO,SAAS,sBACd,OAAA,EACA;AACA,EAAA,MAAM,cAAcF,yBAAAA,EAAe;AAEnC,EAAA,OAAOC,sBAAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,EAAE,MAAA,EAAQ,gBAAe,KAAgC;AAC1E,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAMJ,eAAA,CACrB,KAAK,eAAe,CAAA,CACpB,MAAA,EAAO,CACP,GAAG,IAAA,EAAM,cAAc,CAAA,CACvB,EAAA,CAAG,WAAW,MAAM,CAAA;AAEvB,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AAAA,IAC1C,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAC5B,MAAA,WAAA,CAAY,kBAAkB,EAAE,QAAA,EAAU,iBAAiB,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,IAC3E,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;ACZO,SAAS,iCACd,OAAA,EAKA;AACA,EAAA,MAAM,cAAcG,yBAAAA,EAAe;AAEnC,EAAA,OAAOC,sBAAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,EAAE,MAAA,EAAQ,MAAK,KAA2C;AAE3E,MAAA,MAAM,MAAA,GAAkC,EAAE,OAAA,EAAS,MAAA,EAAO;AAC1D,MAAA,IAAI,IAAA,CAAK,uBAAuB,MAAA,EAAW;AACzC,QAAA,MAAA,CAAO,sBAAsB,IAAA,CAAK,kBAAA;AAAA,MACpC;AACA,MAAA,IAAI,IAAA,CAAK,sBAAsB,MAAA,EAAW;AACxC,QAAA,MAAA,CAAO,qBAAqB,IAAA,CAAK,iBAAA;AAAA,MACnC;AACA,MAAA,IAAI,IAAA,CAAK,cAAc,MAAA,EAAW;AAChC,QAAA,MAAA,CAAO,YAAY,IAAA,CAAK,SAAA;AAAA,MAC1B;AAEA,MAAA,MAAM,EAAE,IAAA,EAAM,GAAA,EAAK,KAAA,KAAU,MAAMJ,eAAA,CAChC,IAAA,CAAK,0BAA0B,EAC/B,MAAA,CAAO,MAAkD,CAAA,CACzD,MAAA,GACA,MAAA,EAAO;AAEV,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AAExC,MAAA,MAAM,SAAA,GAAYE,uCAAAA,CAAiC,KAAA,CAAM,GAAG,CAAA;AAG5D,MAAA,OAAO;AAAA,QACL,oBAAoB,SAAA,CAAU,mBAAA;AAAA,QAC9B,mBAAmB,SAAA,CAAU,kBAAA;AAAA,QAC7B,WAAW,SAAA,CAAU;AAAA,OACvB;AAAA,IACF,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAC5B,MAAA,WAAA,CAAY,kBAAkB,EAAE,QAAA,EAAU,iBAAiB,WAAA,CAAY,MAAM,GAAG,CAAA;AAAA,IAClF,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH","file":"index.cjs","sourcesContent":["/**\n * Query key factory for Notifications domain\n */\nexport const notificationKeys = {\n all: ['notifications'] as const,\n lists: () => [...notificationKeys.all, 'list'] as const,\n list: (userId: string) => [...notificationKeys.lists(), userId] as const,\n preferences: (userId: string) => [...notificationKeys.all, 'preferences', userId] as const,\n};\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { NotificationsResponseSchema, type NotificationRow } from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationsParams {\n userId: string;\n}\n\n/**\n * Fetch all notifications for a user\n * Supabase: SELECT * FROM notifications WHERE user_id = :userId ORDER BY created_at DESC\n */\nexport function useNotifications(\n { userId }: UseNotificationsParams,\n options?: Omit<UseQueryOptions<NotificationRow[]>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.list(userId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('notifications')\n .select('*')\n .eq('user_id', userId)\n .order('created_at', { ascending: false });\n\n if (error) throw new Error(error.message);\n return NotificationsResponseSchema.parse(data);\n },\n staleTime: 1000 * 60 * 2, // 2 minutes (notifications change frequently)\n ...options,\n });\n}\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport {\n NotificationPreferencesRowSchema,\n type NotificationPreferences,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationPreferencesParams {\n userId: string;\n}\n\n/**\n * Fetch user notification preferences\n * Supabase: SELECT * FROM notification_preferences WHERE user_id = :userId\n *\n * Transforms snake_case DB columns to camelCase for feature/UI layers\n */\nexport function useNotificationPreferences(\n { userId }: UseNotificationPreferencesParams,\n options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.preferences(userId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('notification_preferences')\n .select('*')\n .eq('user_id', userId)\n .single();\n\n if (error) throw new Error(error.message);\n\n const row = NotificationPreferencesRowSchema.parse(data);\n\n // Transform snake_case → camelCase for feature/UI layers\n return {\n emailNotifications: row.email_notifications,\n pushNotifications: row.push_notifications,\n frequency: row.frequency,\n } as NotificationPreferences;\n },\n staleTime: 1000 * 60 * 5, // 5 minutes (preferences change infrequently)\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationRowSchema,\n type AlertType,\n type NotificationRow,\n type TablesInsert,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\n/**\n * Notification create data interface\n */\nexport interface NotificationCreate {\n message: string;\n alert_type: AlertType;\n created_at?: string;\n}\n\n/**\n * Parameters for useCreateNotification mutation\n */\nexport interface CreateNotificationParams {\n userId: string;\n data: NotificationCreate;\n}\n\n/**\n * Mutation hook for creating a new notification\n */\nexport function useCreateNotification(\n options?: Omit<\n UseMutationOptions<NotificationRow, Error, CreateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNotificationParams) => {\n const { data: row, error } = await supabase\n .from('notifications')\n .insert({\n user_id: userId,\n message: data.message,\n alert_type: data.alert_type,\n ...(data.created_at ? { created_at: data.created_at } : {}),\n } as TablesInsert<'notifications'>)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n return NotificationRowSchema.parse(row);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationRowSchema,\n type AlertType,\n type NotificationRow,\n type TablesUpdate,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\n/**\n * Notification update data interface\n */\nexport interface NotificationUpdate {\n message?: string;\n alert_type?: AlertType;\n is_read?: boolean;\n}\n\n/**\n * Parameters for useUpdateNotification mutation\n */\nexport interface UpdateNotificationParams {\n userId: string;\n notificationId: string;\n data: NotificationUpdate;\n}\n\n/**\n * Mutation hook for updating a notification\n */\nexport function useUpdateNotification(\n options?: Omit<\n UseMutationOptions<NotificationRow, Error, UpdateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({\n userId,\n notificationId,\n data,\n }: UpdateNotificationParams) => {\n const { data: row, error } = await supabase\n .from('notifications')\n .update(data as TablesUpdate<'notifications'>)\n .eq('id', notificationId)\n .eq('user_id', userId)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n return NotificationRowSchema.parse(row);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface DeleteNotificationParams {\n userId: string;\n notificationId: string;\n}\n\n/**\n * Delete a notification\n * Supabase: DELETE FROM notifications WHERE id = :notificationId AND user_id = :userId\n */\nexport function useDeleteNotification(\n options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, notificationId }: DeleteNotificationParams) => {\n const { error } = await supabase\n .from('notifications')\n .delete()\n .eq('id', notificationId)\n .eq('user_id', userId);\n\n if (error) throw new Error(error.message);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport {\n NotificationPreferencesRowSchema,\n type NotificationPreferences,\n type TablesInsert,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UpdateNotificationPreferencesParams {\n userId: string;\n data: Partial<NotificationPreferences>;\n}\n\n/**\n * Update user notification preferences\n * Supabase: UPSERT notification_preferences\n *\n * Transforms camelCase input → snake_case for Supabase,\n * then transforms response back to camelCase\n */\nexport function useUpdateNotificationPreferences(\n options?: UseMutationOptions<\n NotificationPreferences,\n Error,\n UpdateNotificationPreferencesParams\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: UpdateNotificationPreferencesParams) => {\n // Transform camelCase → snake_case for Supabase\n const dbData: Record<string, unknown> = { user_id: userId };\n if (data.emailNotifications !== undefined) {\n dbData.email_notifications = data.emailNotifications;\n }\n if (data.pushNotifications !== undefined) {\n dbData.push_notifications = data.pushNotifications;\n }\n if (data.frequency !== undefined) {\n dbData.frequency = data.frequency;\n }\n\n const { data: row, error } = await supabase\n .from('notification_preferences')\n .upsert(dbData as TablesInsert<'notification_preferences'>)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n\n const validated = NotificationPreferencesRowSchema.parse(row);\n\n // Transform snake_case → camelCase for feature/UI layers\n return {\n emailNotifications: validated.email_notifications,\n pushNotifications: validated.push_notifications,\n frequency: validated.frequency,\n } as NotificationPreferences;\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });\n },\n ...options,\n });\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
2
|
import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
4
|
-
import * as axios from 'axios';
|
|
3
|
+
import { NotificationRow, NotificationPreferences, AlertType } from '@pfm-platform/shared';
|
|
5
4
|
|
|
6
5
|
interface UseNotificationsParams {
|
|
7
6
|
userId: string;
|
|
8
7
|
}
|
|
9
8
|
/**
|
|
10
9
|
* Fetch all notifications for a user
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Notifications are system-generated based on alert configurations
|
|
14
|
-
* Read-only domain (no create/update operations)
|
|
10
|
+
* Supabase: SELECT * FROM notifications WHERE user_id = :userId ORDER BY created_at DESC
|
|
15
11
|
*/
|
|
16
|
-
declare function useNotifications({ userId }: UseNotificationsParams, options?: Omit<UseQueryOptions<
|
|
17
|
-
id:
|
|
12
|
+
declare function useNotifications({ userId }: UseNotificationsParams, options?: Omit<UseQueryOptions<NotificationRow[]>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
|
|
13
|
+
id: string;
|
|
18
14
|
user_id: string;
|
|
19
|
-
alert_id:
|
|
20
|
-
message: string;
|
|
15
|
+
alert_id: string | null;
|
|
21
16
|
alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
|
|
17
|
+
message: string;
|
|
22
18
|
is_read: boolean;
|
|
23
|
-
created_at: string;
|
|
19
|
+
created_at: string | null;
|
|
24
20
|
}[], Error>;
|
|
25
21
|
|
|
26
22
|
interface UseNotificationPreferencesParams {
|
|
@@ -28,9 +24,9 @@ interface UseNotificationPreferencesParams {
|
|
|
28
24
|
}
|
|
29
25
|
/**
|
|
30
26
|
* Fetch user notification preferences
|
|
31
|
-
*
|
|
27
|
+
* Supabase: SELECT * FROM notification_preferences WHERE user_id = :userId
|
|
32
28
|
*
|
|
33
|
-
*
|
|
29
|
+
* Transforms snake_case DB columns to camelCase for feature/UI layers
|
|
34
30
|
*/
|
|
35
31
|
declare function useNotificationPreferences({ userId }: UseNotificationPreferencesParams, options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
|
|
36
32
|
emailNotifications: boolean;
|
|
@@ -55,34 +51,15 @@ interface CreateNotificationParams {
|
|
|
55
51
|
}
|
|
56
52
|
/**
|
|
57
53
|
* Mutation hook for creating a new notification
|
|
58
|
-
*
|
|
59
|
-
* Creates a notification manually for testing purposes.
|
|
60
|
-
* Uses mode switching for validation:
|
|
61
|
-
* - Admin mode: Allows manual notification creation for test data
|
|
62
|
-
* - User mode: Blocked (notifications are system-generated)
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```tsx
|
|
66
|
-
* const createNotification = useCreateNotification();
|
|
67
|
-
*
|
|
68
|
-
* createNotification.mutate({
|
|
69
|
-
* userId: 'user123',
|
|
70
|
-
* data: {
|
|
71
|
-
* message: 'Test notification',
|
|
72
|
-
* alert_type: 'AccountThresholdAlert',
|
|
73
|
-
* created_at: new Date().toISOString() // Optional
|
|
74
|
-
* }
|
|
75
|
-
* });
|
|
76
|
-
* ```
|
|
77
54
|
*/
|
|
78
|
-
declare function useCreateNotification(options?: Omit<UseMutationOptions<
|
|
79
|
-
id:
|
|
55
|
+
declare function useCreateNotification(options?: Omit<UseMutationOptions<NotificationRow, Error, CreateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
|
|
56
|
+
id: string;
|
|
80
57
|
user_id: string;
|
|
81
|
-
alert_id:
|
|
82
|
-
message: string;
|
|
58
|
+
alert_id: string | null;
|
|
83
59
|
alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
|
|
60
|
+
message: string;
|
|
84
61
|
is_read: boolean;
|
|
85
|
-
created_at: string;
|
|
62
|
+
created_at: string | null;
|
|
86
63
|
}, Error, CreateNotificationParams, unknown>;
|
|
87
64
|
|
|
88
65
|
/**
|
|
@@ -98,54 +75,29 @@ interface NotificationUpdate {
|
|
|
98
75
|
*/
|
|
99
76
|
interface UpdateNotificationParams {
|
|
100
77
|
userId: string;
|
|
101
|
-
notificationId:
|
|
78
|
+
notificationId: string;
|
|
102
79
|
data: NotificationUpdate;
|
|
103
80
|
}
|
|
104
81
|
/**
|
|
105
82
|
* Mutation hook for updating a notification
|
|
106
|
-
*
|
|
107
|
-
* Uses mode switching for validation:
|
|
108
|
-
* - Admin mode: Allows updating message and alert_type for test scenarios
|
|
109
|
-
* - User mode: Allows marking notifications as read/unread
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* ```tsx
|
|
113
|
-
* const updateNotification = useUpdateNotification();
|
|
114
|
-
*
|
|
115
|
-
* // User mode: mark as read
|
|
116
|
-
* updateNotification.mutate({
|
|
117
|
-
* userId: 'user123',
|
|
118
|
-
* notificationId: 1,
|
|
119
|
-
* data: { is_read: true }
|
|
120
|
-
* });
|
|
121
|
-
*
|
|
122
|
-
* // Admin mode: update message
|
|
123
|
-
* updateNotification.mutate({
|
|
124
|
-
* userId: 'user123',
|
|
125
|
-
* notificationId: 1,
|
|
126
|
-
* data: { message: 'Updated test notification' }
|
|
127
|
-
* });
|
|
128
|
-
* ```
|
|
129
83
|
*/
|
|
130
|
-
declare function useUpdateNotification(options?: Omit<UseMutationOptions<
|
|
131
|
-
id:
|
|
84
|
+
declare function useUpdateNotification(options?: Omit<UseMutationOptions<NotificationRow, Error, UpdateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
|
|
85
|
+
id: string;
|
|
132
86
|
user_id: string;
|
|
133
|
-
alert_id:
|
|
134
|
-
message: string;
|
|
87
|
+
alert_id: string | null;
|
|
135
88
|
alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
|
|
89
|
+
message: string;
|
|
136
90
|
is_read: boolean;
|
|
137
|
-
created_at: string;
|
|
91
|
+
created_at: string | null;
|
|
138
92
|
}, Error, UpdateNotificationParams, unknown>;
|
|
139
93
|
|
|
140
94
|
interface DeleteNotificationParams {
|
|
141
95
|
userId: string;
|
|
142
|
-
notificationId:
|
|
96
|
+
notificationId: string;
|
|
143
97
|
}
|
|
144
98
|
/**
|
|
145
99
|
* Delete a notification
|
|
146
|
-
* DELETE
|
|
147
|
-
*
|
|
148
|
-
* Notifications are system-generated, deletion only removes from view
|
|
100
|
+
* Supabase: DELETE FROM notifications WHERE id = :notificationId AND user_id = :userId
|
|
149
101
|
*/
|
|
150
102
|
declare function useDeleteNotification(options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<void, Error, DeleteNotificationParams, unknown>;
|
|
151
103
|
|
|
@@ -155,9 +107,10 @@ interface UpdateNotificationPreferencesParams {
|
|
|
155
107
|
}
|
|
156
108
|
/**
|
|
157
109
|
* Update user notification preferences
|
|
158
|
-
*
|
|
110
|
+
* Supabase: UPSERT notification_preferences
|
|
159
111
|
*
|
|
160
|
-
*
|
|
112
|
+
* Transforms camelCase input → snake_case for Supabase,
|
|
113
|
+
* then transforms response back to camelCase
|
|
161
114
|
*/
|
|
162
115
|
declare function useUpdateNotificationPreferences(options?: UseMutationOptions<NotificationPreferences, Error, UpdateNotificationPreferencesParams>): _tanstack_react_query.UseMutationResult<{
|
|
163
116
|
emailNotifications: boolean;
|
|
@@ -175,10 +128,4 @@ declare const notificationKeys: {
|
|
|
175
128
|
preferences: (userId: string) => readonly ["notifications", "preferences", string];
|
|
176
129
|
};
|
|
177
130
|
|
|
178
|
-
|
|
179
|
-
* Axios instance for Notifications API
|
|
180
|
-
* Base URL configured through environment variables or defaults to localhost for tests
|
|
181
|
-
*/
|
|
182
|
-
declare const api: axios.AxiosInstance;
|
|
183
|
-
|
|
184
|
-
export { type CreateNotificationParams, type DeleteNotificationParams, type NotificationCreate, type NotificationUpdate, type UpdateNotificationParams, type UpdateNotificationPreferencesParams, type UseNotificationPreferencesParams, type UseNotificationsParams, api, notificationKeys, useCreateNotification, useDeleteNotification, useNotificationPreferences, useNotifications, useUpdateNotification, useUpdateNotificationPreferences };
|
|
131
|
+
export { type CreateNotificationParams, type DeleteNotificationParams, type NotificationCreate, type NotificationUpdate, type UpdateNotificationParams, type UpdateNotificationPreferencesParams, type UseNotificationPreferencesParams, type UseNotificationsParams, notificationKeys, useCreateNotification, useDeleteNotification, useNotificationPreferences, useNotifications, useUpdateNotification, useUpdateNotificationPreferences };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
2
|
import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
4
|
-
import * as axios from 'axios';
|
|
3
|
+
import { NotificationRow, NotificationPreferences, AlertType } from '@pfm-platform/shared';
|
|
5
4
|
|
|
6
5
|
interface UseNotificationsParams {
|
|
7
6
|
userId: string;
|
|
8
7
|
}
|
|
9
8
|
/**
|
|
10
9
|
* Fetch all notifications for a user
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Notifications are system-generated based on alert configurations
|
|
14
|
-
* Read-only domain (no create/update operations)
|
|
10
|
+
* Supabase: SELECT * FROM notifications WHERE user_id = :userId ORDER BY created_at DESC
|
|
15
11
|
*/
|
|
16
|
-
declare function useNotifications({ userId }: UseNotificationsParams, options?: Omit<UseQueryOptions<
|
|
17
|
-
id:
|
|
12
|
+
declare function useNotifications({ userId }: UseNotificationsParams, options?: Omit<UseQueryOptions<NotificationRow[]>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
|
|
13
|
+
id: string;
|
|
18
14
|
user_id: string;
|
|
19
|
-
alert_id:
|
|
20
|
-
message: string;
|
|
15
|
+
alert_id: string | null;
|
|
21
16
|
alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
|
|
17
|
+
message: string;
|
|
22
18
|
is_read: boolean;
|
|
23
|
-
created_at: string;
|
|
19
|
+
created_at: string | null;
|
|
24
20
|
}[], Error>;
|
|
25
21
|
|
|
26
22
|
interface UseNotificationPreferencesParams {
|
|
@@ -28,9 +24,9 @@ interface UseNotificationPreferencesParams {
|
|
|
28
24
|
}
|
|
29
25
|
/**
|
|
30
26
|
* Fetch user notification preferences
|
|
31
|
-
*
|
|
27
|
+
* Supabase: SELECT * FROM notification_preferences WHERE user_id = :userId
|
|
32
28
|
*
|
|
33
|
-
*
|
|
29
|
+
* Transforms snake_case DB columns to camelCase for feature/UI layers
|
|
34
30
|
*/
|
|
35
31
|
declare function useNotificationPreferences({ userId }: UseNotificationPreferencesParams, options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
|
|
36
32
|
emailNotifications: boolean;
|
|
@@ -55,34 +51,15 @@ interface CreateNotificationParams {
|
|
|
55
51
|
}
|
|
56
52
|
/**
|
|
57
53
|
* Mutation hook for creating a new notification
|
|
58
|
-
*
|
|
59
|
-
* Creates a notification manually for testing purposes.
|
|
60
|
-
* Uses mode switching for validation:
|
|
61
|
-
* - Admin mode: Allows manual notification creation for test data
|
|
62
|
-
* - User mode: Blocked (notifications are system-generated)
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```tsx
|
|
66
|
-
* const createNotification = useCreateNotification();
|
|
67
|
-
*
|
|
68
|
-
* createNotification.mutate({
|
|
69
|
-
* userId: 'user123',
|
|
70
|
-
* data: {
|
|
71
|
-
* message: 'Test notification',
|
|
72
|
-
* alert_type: 'AccountThresholdAlert',
|
|
73
|
-
* created_at: new Date().toISOString() // Optional
|
|
74
|
-
* }
|
|
75
|
-
* });
|
|
76
|
-
* ```
|
|
77
54
|
*/
|
|
78
|
-
declare function useCreateNotification(options?: Omit<UseMutationOptions<
|
|
79
|
-
id:
|
|
55
|
+
declare function useCreateNotification(options?: Omit<UseMutationOptions<NotificationRow, Error, CreateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
|
|
56
|
+
id: string;
|
|
80
57
|
user_id: string;
|
|
81
|
-
alert_id:
|
|
82
|
-
message: string;
|
|
58
|
+
alert_id: string | null;
|
|
83
59
|
alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
|
|
60
|
+
message: string;
|
|
84
61
|
is_read: boolean;
|
|
85
|
-
created_at: string;
|
|
62
|
+
created_at: string | null;
|
|
86
63
|
}, Error, CreateNotificationParams, unknown>;
|
|
87
64
|
|
|
88
65
|
/**
|
|
@@ -98,54 +75,29 @@ interface NotificationUpdate {
|
|
|
98
75
|
*/
|
|
99
76
|
interface UpdateNotificationParams {
|
|
100
77
|
userId: string;
|
|
101
|
-
notificationId:
|
|
78
|
+
notificationId: string;
|
|
102
79
|
data: NotificationUpdate;
|
|
103
80
|
}
|
|
104
81
|
/**
|
|
105
82
|
* Mutation hook for updating a notification
|
|
106
|
-
*
|
|
107
|
-
* Uses mode switching for validation:
|
|
108
|
-
* - Admin mode: Allows updating message and alert_type for test scenarios
|
|
109
|
-
* - User mode: Allows marking notifications as read/unread
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* ```tsx
|
|
113
|
-
* const updateNotification = useUpdateNotification();
|
|
114
|
-
*
|
|
115
|
-
* // User mode: mark as read
|
|
116
|
-
* updateNotification.mutate({
|
|
117
|
-
* userId: 'user123',
|
|
118
|
-
* notificationId: 1,
|
|
119
|
-
* data: { is_read: true }
|
|
120
|
-
* });
|
|
121
|
-
*
|
|
122
|
-
* // Admin mode: update message
|
|
123
|
-
* updateNotification.mutate({
|
|
124
|
-
* userId: 'user123',
|
|
125
|
-
* notificationId: 1,
|
|
126
|
-
* data: { message: 'Updated test notification' }
|
|
127
|
-
* });
|
|
128
|
-
* ```
|
|
129
83
|
*/
|
|
130
|
-
declare function useUpdateNotification(options?: Omit<UseMutationOptions<
|
|
131
|
-
id:
|
|
84
|
+
declare function useUpdateNotification(options?: Omit<UseMutationOptions<NotificationRow, Error, UpdateNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
|
|
85
|
+
id: string;
|
|
132
86
|
user_id: string;
|
|
133
|
-
alert_id:
|
|
134
|
-
message: string;
|
|
87
|
+
alert_id: string | null;
|
|
135
88
|
alert_type: "AccountThresholdAlert" | "GoalAlert" | "MerchantNameAlert" | "SpendingTargetAlert" | "TransactionLimitAlert" | "UpcomingBillAlert";
|
|
89
|
+
message: string;
|
|
136
90
|
is_read: boolean;
|
|
137
|
-
created_at: string;
|
|
91
|
+
created_at: string | null;
|
|
138
92
|
}, Error, UpdateNotificationParams, unknown>;
|
|
139
93
|
|
|
140
94
|
interface DeleteNotificationParams {
|
|
141
95
|
userId: string;
|
|
142
|
-
notificationId:
|
|
96
|
+
notificationId: string;
|
|
143
97
|
}
|
|
144
98
|
/**
|
|
145
99
|
* Delete a notification
|
|
146
|
-
* DELETE
|
|
147
|
-
*
|
|
148
|
-
* Notifications are system-generated, deletion only removes from view
|
|
100
|
+
* Supabase: DELETE FROM notifications WHERE id = :notificationId AND user_id = :userId
|
|
149
101
|
*/
|
|
150
102
|
declare function useDeleteNotification(options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<void, Error, DeleteNotificationParams, unknown>;
|
|
151
103
|
|
|
@@ -155,9 +107,10 @@ interface UpdateNotificationPreferencesParams {
|
|
|
155
107
|
}
|
|
156
108
|
/**
|
|
157
109
|
* Update user notification preferences
|
|
158
|
-
*
|
|
110
|
+
* Supabase: UPSERT notification_preferences
|
|
159
111
|
*
|
|
160
|
-
*
|
|
112
|
+
* Transforms camelCase input → snake_case for Supabase,
|
|
113
|
+
* then transforms response back to camelCase
|
|
161
114
|
*/
|
|
162
115
|
declare function useUpdateNotificationPreferences(options?: UseMutationOptions<NotificationPreferences, Error, UpdateNotificationPreferencesParams>): _tanstack_react_query.UseMutationResult<{
|
|
163
116
|
emailNotifications: boolean;
|
|
@@ -175,10 +128,4 @@ declare const notificationKeys: {
|
|
|
175
128
|
preferences: (userId: string) => readonly ["notifications", "preferences", string];
|
|
176
129
|
};
|
|
177
130
|
|
|
178
|
-
|
|
179
|
-
* Axios instance for Notifications API
|
|
180
|
-
* Base URL configured through environment variables or defaults to localhost for tests
|
|
181
|
-
*/
|
|
182
|
-
declare const api: axios.AxiosInstance;
|
|
183
|
-
|
|
184
|
-
export { type CreateNotificationParams, type DeleteNotificationParams, type NotificationCreate, type NotificationUpdate, type UpdateNotificationParams, type UpdateNotificationPreferencesParams, type UseNotificationPreferencesParams, type UseNotificationsParams, api, notificationKeys, useCreateNotification, useDeleteNotification, useNotificationPreferences, useNotifications, useUpdateNotification, useUpdateNotificationPreferences };
|
|
131
|
+
export { type CreateNotificationParams, type DeleteNotificationParams, type NotificationCreate, type NotificationUpdate, type UpdateNotificationParams, type UpdateNotificationPreferencesParams, type UseNotificationPreferencesParams, type UseNotificationsParams, notificationKeys, useCreateNotification, useDeleteNotification, useNotificationPreferences, useNotifications, useUpdateNotification, useUpdateNotificationPreferences };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
|
|
2
|
-
import {
|
|
3
|
-
import axios from 'axios';
|
|
2
|
+
import { supabase, NotificationsResponseSchema, NotificationPreferencesRowSchema, NotificationRowSchema } from '@pfm-platform/shared';
|
|
4
3
|
|
|
5
4
|
// src/queries/useNotifications.ts
|
|
6
|
-
var api = axios.create({
|
|
7
|
-
baseURL: "http://localhost:3000/api",
|
|
8
|
-
headers: {
|
|
9
|
-
"Content-Type": "application/json"
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
5
|
|
|
13
6
|
// src/keys.ts
|
|
14
7
|
var notificationKeys = {
|
|
@@ -23,9 +16,9 @@ function useNotifications({ userId }, options) {
|
|
|
23
16
|
return useQuery({
|
|
24
17
|
queryKey: notificationKeys.list(userId),
|
|
25
18
|
queryFn: async () => {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
return
|
|
19
|
+
const { data, error } = await supabase.from("notifications").select("*").eq("user_id", userId).order("created_at", { ascending: false });
|
|
20
|
+
if (error) throw new Error(error.message);
|
|
21
|
+
return NotificationsResponseSchema.parse(data);
|
|
29
22
|
},
|
|
30
23
|
staleTime: 1e3 * 60 * 2,
|
|
31
24
|
// 2 minutes (notifications change frequently)
|
|
@@ -36,9 +29,14 @@ function useNotificationPreferences({ userId }, options) {
|
|
|
36
29
|
return useQuery({
|
|
37
30
|
queryKey: notificationKeys.preferences(userId),
|
|
38
31
|
queryFn: async () => {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
const { data, error } = await supabase.from("notification_preferences").select("*").eq("user_id", userId).single();
|
|
33
|
+
if (error) throw new Error(error.message);
|
|
34
|
+
const row = NotificationPreferencesRowSchema.parse(data);
|
|
35
|
+
return {
|
|
36
|
+
emailNotifications: row.email_notifications,
|
|
37
|
+
pushNotifications: row.push_notifications,
|
|
38
|
+
frequency: row.frequency
|
|
39
|
+
};
|
|
42
40
|
},
|
|
43
41
|
staleTime: 1e3 * 60 * 5,
|
|
44
42
|
// 5 minutes (preferences change infrequently)
|
|
@@ -47,16 +45,16 @@ function useNotificationPreferences({ userId }, options) {
|
|
|
47
45
|
}
|
|
48
46
|
function useCreateNotification(options) {
|
|
49
47
|
const queryClient = useQueryClient();
|
|
50
|
-
const { mode } = useAppMode();
|
|
51
48
|
return useMutation({
|
|
52
49
|
mutationFn: async ({ userId, data }) => {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
);
|
|
59
|
-
|
|
50
|
+
const { data: row, error } = await supabase.from("notifications").insert({
|
|
51
|
+
user_id: userId,
|
|
52
|
+
message: data.message,
|
|
53
|
+
alert_type: data.alert_type,
|
|
54
|
+
...data.created_at ? { created_at: data.created_at } : {}
|
|
55
|
+
}).select().single();
|
|
56
|
+
if (error) throw new Error(error.message);
|
|
57
|
+
return NotificationRowSchema.parse(row);
|
|
60
58
|
},
|
|
61
59
|
onSuccess: (_, { userId }) => {
|
|
62
60
|
queryClient.invalidateQueries({
|
|
@@ -68,20 +66,15 @@ function useCreateNotification(options) {
|
|
|
68
66
|
}
|
|
69
67
|
function useUpdateNotification(options) {
|
|
70
68
|
const queryClient = useQueryClient();
|
|
71
|
-
const { mode } = useAppMode();
|
|
72
69
|
return useMutation({
|
|
73
70
|
mutationFn: async ({
|
|
74
71
|
userId,
|
|
75
72
|
notificationId,
|
|
76
73
|
data
|
|
77
74
|
}) => {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
`/users/${userId}/alerts/notifications/${notificationId}`,
|
|
82
|
-
validated
|
|
83
|
-
);
|
|
84
|
-
return NotificationSchema.parse(response.data);
|
|
75
|
+
const { data: row, error } = await supabase.from("notifications").update(data).eq("id", notificationId).eq("user_id", userId).select().single();
|
|
76
|
+
if (error) throw new Error(error.message);
|
|
77
|
+
return NotificationRowSchema.parse(row);
|
|
85
78
|
},
|
|
86
79
|
onSuccess: (_, { userId }) => {
|
|
87
80
|
queryClient.invalidateQueries({
|
|
@@ -95,7 +88,8 @@ function useDeleteNotification(options) {
|
|
|
95
88
|
const queryClient = useQueryClient();
|
|
96
89
|
return useMutation({
|
|
97
90
|
mutationFn: async ({ userId, notificationId }) => {
|
|
98
|
-
await
|
|
91
|
+
const { error } = await supabase.from("notifications").delete().eq("id", notificationId).eq("user_id", userId);
|
|
92
|
+
if (error) throw new Error(error.message);
|
|
99
93
|
},
|
|
100
94
|
onSuccess: (_, { userId }) => {
|
|
101
95
|
queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });
|
|
@@ -107,9 +101,24 @@ function useUpdateNotificationPreferences(options) {
|
|
|
107
101
|
const queryClient = useQueryClient();
|
|
108
102
|
return useMutation({
|
|
109
103
|
mutationFn: async ({ userId, data }) => {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
const dbData = { user_id: userId };
|
|
105
|
+
if (data.emailNotifications !== void 0) {
|
|
106
|
+
dbData.email_notifications = data.emailNotifications;
|
|
107
|
+
}
|
|
108
|
+
if (data.pushNotifications !== void 0) {
|
|
109
|
+
dbData.push_notifications = data.pushNotifications;
|
|
110
|
+
}
|
|
111
|
+
if (data.frequency !== void 0) {
|
|
112
|
+
dbData.frequency = data.frequency;
|
|
113
|
+
}
|
|
114
|
+
const { data: row, error } = await supabase.from("notification_preferences").upsert(dbData).select().single();
|
|
115
|
+
if (error) throw new Error(error.message);
|
|
116
|
+
const validated = NotificationPreferencesRowSchema.parse(row);
|
|
117
|
+
return {
|
|
118
|
+
emailNotifications: validated.email_notifications,
|
|
119
|
+
pushNotifications: validated.push_notifications,
|
|
120
|
+
frequency: validated.frequency
|
|
121
|
+
};
|
|
113
122
|
},
|
|
114
123
|
onSuccess: (_, { userId }) => {
|
|
115
124
|
queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });
|
|
@@ -118,6 +127,6 @@ function useUpdateNotificationPreferences(options) {
|
|
|
118
127
|
});
|
|
119
128
|
}
|
|
120
129
|
|
|
121
|
-
export {
|
|
130
|
+
export { notificationKeys, useCreateNotification, useDeleteNotification, useNotificationPreferences, useNotifications, useUpdateNotification, useUpdateNotificationPreferences };
|
|
122
131
|
//# sourceMappingURL=index.js.map
|
|
123
132
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/keys.ts","../src/queries/useNotifications.ts","../src/queries/useNotificationPreferences.ts","../src/mutations/useCreateNotification.ts","../src/mutations/useUpdateNotification.ts","../src/mutations/useDeleteNotification.ts","../src/mutations/useUpdateNotificationPreferences.ts"],"names":["useQuery","useQueryClient","useAppMode","useMutation","NotificationSchema","NotificationPreferencesSchema"],"mappings":";;;;;AAMO,IAAM,GAAA,GAAM,MAAM,MAAA,CAAO;AAAA,EAC9B,OAAA,EAAS,2BAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,cAAA,EAAgB;AAAA;AAEpB,CAAC;;;ACRM,IAAM,gBAAA,GAAmB;AAAA,EAC9B,GAAA,EAAK,CAAC,eAAe,CAAA;AAAA,EACrB,OAAO,MAAM,CAAC,GAAG,gBAAA,CAAiB,KAAK,MAAM,CAAA;AAAA,EAC7C,IAAA,EAAM,CAAC,MAAA,KAAmB,CAAC,GAAG,gBAAA,CAAiB,KAAA,IAAS,MAAM,CAAA;AAAA,EAC9D,WAAA,EAAa,CAAC,MAAA,KAAmB,CAAC,GAAG,gBAAA,CAAiB,GAAA,EAAK,eAAe,MAAM;AAClF;;;ACQO,SAAS,gBAAA,CACd,EAAE,MAAA,EAAO,EACT,OAAA,EACA;AACA,EAAA,OAAO,QAAA,CAAS;AAAA,IACd,QAAA,EAAU,gBAAA,CAAiB,IAAA,CAAK,MAAM,CAAA;AAAA,IACtC,SAAS,YAAY;AACnB,MAAA,MAAM,WAAW,MAAM,GAAA,CAAI,GAAA,CAAI,CAAA,OAAA,EAAU,MAAM,CAAA,qBAAA,CAAuB,CAAA;AACtE,MAAA,MAAM,SAAA,GAAY,2BAAA,CAA4B,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AACjE,MAAA,OAAO,SAAA,CAAU,aAAA;AAAA,IACnB,CAAA;AAAA,IACA,SAAA,EAAW,MAAO,EAAA,GAAK,CAAA;AAAA;AAAA,IACvB,GAAG;AAAA,GACJ,CAAA;AACH;ACfO,SAAS,0BAAA,CACd,EAAE,MAAA,EAAO,EACT,OAAA,EACA;AACA,EAAA,OAAOA,QAAAA,CAAS;AAAA,IACd,QAAA,EAAU,gBAAA,CAAiB,WAAA,CAAY,MAAM,CAAA;AAAA,IAC7C,SAAS,YAAY;AACnB,MAAA,MAAM,WAAW,MAAM,GAAA,CAAI,GAAA,CAAI,CAAA,OAAA,EAAU,MAAM,CAAA,0BAAA,CAA4B,CAAA;AAC3E,MAAA,MAAM,SAAA,GAAY,6BAAA,CAA8B,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AACnE,MAAA,OAAO,SAAA;AAAA,IACT,CAAA;AAAA,IACA,SAAA,EAAW,MAAO,EAAA,GAAK,CAAA;AAAA;AAAA,IACvB,GAAG;AAAA,GACJ,CAAA;AACH;AC0BO,SAAS,sBACd,OAAA,EAIA;AACA,EAAA,MAAM,cAAc,cAAA,EAAe;AACnC,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,UAAA,EAAW;AAE5B,EAAA,OAAO,WAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,EAAE,MAAA,EAAQ,MAAK,KAAgC;AAEhE,MAAA,MAAM,MAAA,GACJ,IAAA,KAAS,OAAA,GACL,6BAAA,GACA,4BAAA;AAGN,MAAA,MAAM,SAAA,GAAY,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AAGnC,MAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,IAAA;AAAA,QACzB,UAAU,MAAM,CAAA,qBAAA,CAAA;AAAA,QAChB;AAAA,OACF;AAGA,MAAA,OAAO,kBAAA,CAAmB,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAE5B,MAAA,WAAA,CAAY,iBAAA,CAAkB;AAAA,QAC5B,QAAA,EAAU,gBAAA,CAAiB,IAAA,CAAK,MAAM;AAAA,OACvC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;AChCO,SAAS,sBACd,OAAA,EAIA;AACA,EAAA,MAAM,cAAcC,cAAAA,EAAe;AACnC,EAAA,MAAM,EAAE,IAAA,EAAK,GAAIC,UAAAA,EAAW;AAE5B,EAAA,OAAOC,WAAAA,CAAY;AAAA,IACjB,YAAY,OAAO;AAAA,MACjB,MAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACF,KAAgC;AAE9B,MAAA,MAAM,MAAA,GACJ,IAAA,KAAS,OAAA,GACL,6BAAA,GACA,4BAAA;AAGN,MAAA,MAAM,SAAA,GAAY,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AAGnC,MAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,GAAA;AAAA,QACzB,CAAA,OAAA,EAAU,MAAM,CAAA,sBAAA,EAAyB,cAAc,CAAA,CAAA;AAAA,QACvD;AAAA,OACF;AAGA,MAAA,OAAOC,kBAAAA,CAAmB,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAE5B,MAAA,WAAA,CAAY,iBAAA,CAAkB;AAAA,QAC5B,QAAA,EAAU,gBAAA,CAAiB,IAAA,CAAK,MAAM;AAAA,OACvC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;ACtFO,SAAS,sBACd,OAAA,EACA;AACA,EAAA,MAAM,cAAcH,cAAAA,EAAe;AAEnC,EAAA,OAAOE,WAAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,EAAE,MAAA,EAAQ,gBAAe,KAAgC;AAC1E,MAAA,MAAM,IAAI,MAAA,CAAO,CAAA,OAAA,EAAU,MAAM,CAAA,sBAAA,EAAyB,cAAc,CAAA,CAAE,CAAA;AAAA,IAC5E,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAE5B,MAAA,WAAA,CAAY,kBAAkB,EAAE,QAAA,EAAU,iBAAiB,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,IAC3E,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;ACVO,SAAS,iCACd,OAAA,EAKA;AACA,EAAA,MAAM,cAAcF,cAAAA,EAAe;AAEnC,EAAA,OAAOE,WAAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,EAAE,MAAA,EAAQ,MAAK,KAA2C;AAE3E,MAAA,MAAM,SAAA,GAAY,mCAAA,CAAoC,KAAA,CAAM,IAAI,CAAA;AAEhE,MAAA,MAAM,WAAW,MAAM,GAAA,CAAI,IAAI,CAAA,OAAA,EAAU,MAAM,8BAA8B,SAAS,CAAA;AACtF,MAAA,OAAOE,6BAAAA,CAA8B,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AAAA,IAC1D,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAE5B,MAAA,WAAA,CAAY,kBAAkB,EAAE,QAAA,EAAU,iBAAiB,WAAA,CAAY,MAAM,GAAG,CAAA;AAAA,IAClF,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH","file":"index.js","sourcesContent":["import axios from 'axios';\n\n/**\n * Axios instance for Notifications API\n * Base URL configured through environment variables or defaults to localhost for tests\n */\nexport const api = axios.create({\n baseURL: 'http://localhost:3000/api',\n headers: {\n 'Content-Type': 'application/json',\n },\n});\n","/**\n * Query key factory for Notifications domain\n */\nexport const notificationKeys = {\n all: ['notifications'] as const,\n lists: () => [...notificationKeys.all, 'list'] as const,\n list: (userId: string) => [...notificationKeys.lists(), userId] as const,\n preferences: (userId: string) => [...notificationKeys.all, 'preferences', userId] as const,\n};\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { Notification, NotificationsResponseSchema } from '@pfm-platform/shared';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationsParams {\n userId: string;\n}\n\n/**\n * Fetch all notifications for a user\n * GET /users/:userId/alerts/notifications\n *\n * Notifications are system-generated based on alert configurations\n * Read-only domain (no create/update operations)\n */\nexport function useNotifications(\n { userId }: UseNotificationsParams,\n options?: Omit<UseQueryOptions<Notification[]>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.list(userId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/alerts/notifications`);\n const validated = NotificationsResponseSchema.parse(response.data);\n return validated.notifications;\n },\n staleTime: 1000 * 60 * 2, // 2 minutes (notifications change frequently)\n ...options,\n });\n}\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { NotificationPreferences, NotificationPreferencesSchema } from '@pfm-platform/shared';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationPreferencesParams {\n userId: string;\n}\n\n/**\n * Fetch user notification preferences\n * GET /users/:userId/notifications/preferences\n *\n * Returns user preferences for notification delivery and frequency\n */\nexport function useNotificationPreferences(\n { userId }: UseNotificationPreferencesParams,\n options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.preferences(userId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/notifications/preferences`);\n const validated = NotificationPreferencesSchema.parse(response.data);\n return validated;\n },\n staleTime: 1000 * 60 * 5, // 5 minutes (preferences change infrequently)\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationCreateSchemaAdmin,\n NotificationCreateSchemaUser,\n NotificationSchema,\n useAppMode,\n type AlertType,\n} from '@pfm-platform/shared';\nimport type { Notification } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { notificationKeys } from '../keys';\n\n/**\n * Notification create data interface\n */\nexport interface NotificationCreate {\n message: string;\n alert_type: AlertType;\n created_at?: string;\n}\n\n/**\n * Parameters for useCreateNotification mutation\n */\nexport interface CreateNotificationParams {\n userId: string;\n data: NotificationCreate;\n}\n\n/**\n * Mutation hook for creating a new notification\n *\n * Creates a notification manually for testing purposes.\n * Uses mode switching for validation:\n * - Admin mode: Allows manual notification creation for test data\n * - User mode: Blocked (notifications are system-generated)\n *\n * @example\n * ```tsx\n * const createNotification = useCreateNotification();\n *\n * createNotification.mutate({\n * userId: 'user123',\n * data: {\n * message: 'Test notification',\n * alert_type: 'AccountThresholdAlert',\n * created_at: new Date().toISOString() // Optional\n * }\n * });\n * ```\n */\nexport function useCreateNotification(\n options?: Omit<\n UseMutationOptions<Notification, Error, CreateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNotificationParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? NotificationCreateSchemaAdmin\n : NotificationCreateSchemaUser;\n\n // Validate notification data\n const validated = schema.parse(data);\n\n // POST to create new notification\n const response = await api.post(\n `/users/${userId}/alerts/notifications`,\n validated\n );\n\n // Return created notification\n return NotificationSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications query to refetch updated list\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationUpdateSchemaAdmin,\n NotificationUpdateSchemaUser,\n NotificationSchema,\n useAppMode,\n type AlertType,\n} from '@pfm-platform/shared';\nimport type { Notification } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { notificationKeys } from '../keys';\n\n/**\n * Notification update data interface\n */\nexport interface NotificationUpdate {\n message?: string;\n alert_type?: AlertType;\n is_read?: boolean;\n}\n\n/**\n * Parameters for useUpdateNotification mutation\n */\nexport interface UpdateNotificationParams {\n userId: string;\n notificationId: number;\n data: NotificationUpdate;\n}\n\n/**\n * Mutation hook for updating a notification\n *\n * Uses mode switching for validation:\n * - Admin mode: Allows updating message and alert_type for test scenarios\n * - User mode: Allows marking notifications as read/unread\n *\n * @example\n * ```tsx\n * const updateNotification = useUpdateNotification();\n *\n * // User mode: mark as read\n * updateNotification.mutate({\n * userId: 'user123',\n * notificationId: 1,\n * data: { is_read: true }\n * });\n *\n * // Admin mode: update message\n * updateNotification.mutate({\n * userId: 'user123',\n * notificationId: 1,\n * data: { message: 'Updated test notification' }\n * });\n * ```\n */\nexport function useUpdateNotification(\n options?: Omit<\n UseMutationOptions<Notification, Error, UpdateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({\n userId,\n notificationId,\n data,\n }: UpdateNotificationParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? NotificationUpdateSchemaAdmin\n : NotificationUpdateSchemaUser;\n\n // Validate notification update data\n const validated = schema.parse(data);\n\n // PUT to update notification\n const response = await api.put(\n `/users/${userId}/alerts/notifications/${notificationId}`,\n validated\n );\n\n // Return updated notification\n return NotificationSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications query to refetch updated list\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface DeleteNotificationParams {\n userId: string;\n notificationId: number;\n}\n\n/**\n * Delete a notification\n * DELETE /users/:userId/alerts/notifications/:notificationId\n *\n * Notifications are system-generated, deletion only removes from view\n */\nexport function useDeleteNotification(\n options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, notificationId }: DeleteNotificationParams) => {\n await api.delete(`/users/${userId}/alerts/notifications/${notificationId}`);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate notifications list to refetch without deleted item\n queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport {\n NotificationPreferences,\n NotificationPreferencesSchema,\n NotificationPreferencesUpdateSchema,\n} from '@pfm-platform/shared';\nimport { api } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UpdateNotificationPreferencesParams {\n userId: string;\n data: Partial<NotificationPreferences>;\n}\n\n/**\n * Update user notification preferences\n * PUT /users/:userId/notifications/preferences\n *\n * Updates delivery and frequency preferences for notifications\n */\nexport function useUpdateNotificationPreferences(\n options?: UseMutationOptions<\n NotificationPreferences,\n Error,\n UpdateNotificationPreferencesParams\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: UpdateNotificationPreferencesParams) => {\n // Validate update data\n const validated = NotificationPreferencesUpdateSchema.parse(data);\n\n const response = await api.put(`/users/${userId}/notifications/preferences`, validated);\n return NotificationPreferencesSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate preferences query to refetch\n queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });\n },\n ...options,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/keys.ts","../src/queries/useNotifications.ts","../src/queries/useNotificationPreferences.ts","../src/mutations/useCreateNotification.ts","../src/mutations/useUpdateNotification.ts","../src/mutations/useDeleteNotification.ts","../src/mutations/useUpdateNotificationPreferences.ts"],"names":["useQuery","useQueryClient","useMutation","NotificationRowSchema","NotificationPreferencesRowSchema"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Query key factory for Notifications domain\n */\nexport const notificationKeys = {\n all: ['notifications'] as const,\n lists: () => [...notificationKeys.all, 'list'] as const,\n list: (userId: string) => [...notificationKeys.lists(), userId] as const,\n preferences: (userId: string) => [...notificationKeys.all, 'preferences', userId] as const,\n};\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { NotificationsResponseSchema, type NotificationRow } from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationsParams {\n userId: string;\n}\n\n/**\n * Fetch all notifications for a user\n * Supabase: SELECT * FROM notifications WHERE user_id = :userId ORDER BY created_at DESC\n */\nexport function useNotifications(\n { userId }: UseNotificationsParams,\n options?: Omit<UseQueryOptions<NotificationRow[]>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.list(userId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('notifications')\n .select('*')\n .eq('user_id', userId)\n .order('created_at', { ascending: false });\n\n if (error) throw new Error(error.message);\n return NotificationsResponseSchema.parse(data);\n },\n staleTime: 1000 * 60 * 2, // 2 minutes (notifications change frequently)\n ...options,\n });\n}\n","import { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport {\n NotificationPreferencesRowSchema,\n type NotificationPreferences,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UseNotificationPreferencesParams {\n userId: string;\n}\n\n/**\n * Fetch user notification preferences\n * Supabase: SELECT * FROM notification_preferences WHERE user_id = :userId\n *\n * Transforms snake_case DB columns to camelCase for feature/UI layers\n */\nexport function useNotificationPreferences(\n { userId }: UseNotificationPreferencesParams,\n options?: Omit<UseQueryOptions<NotificationPreferences>, 'queryKey' | 'queryFn'>\n) {\n return useQuery({\n queryKey: notificationKeys.preferences(userId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('notification_preferences')\n .select('*')\n .eq('user_id', userId)\n .single();\n\n if (error) throw new Error(error.message);\n\n const row = NotificationPreferencesRowSchema.parse(data);\n\n // Transform snake_case → camelCase for feature/UI layers\n return {\n emailNotifications: row.email_notifications,\n pushNotifications: row.push_notifications,\n frequency: row.frequency,\n } as NotificationPreferences;\n },\n staleTime: 1000 * 60 * 5, // 5 minutes (preferences change infrequently)\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationRowSchema,\n type AlertType,\n type NotificationRow,\n type TablesInsert,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\n/**\n * Notification create data interface\n */\nexport interface NotificationCreate {\n message: string;\n alert_type: AlertType;\n created_at?: string;\n}\n\n/**\n * Parameters for useCreateNotification mutation\n */\nexport interface CreateNotificationParams {\n userId: string;\n data: NotificationCreate;\n}\n\n/**\n * Mutation hook for creating a new notification\n */\nexport function useCreateNotification(\n options?: Omit<\n UseMutationOptions<NotificationRow, Error, CreateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNotificationParams) => {\n const { data: row, error } = await supabase\n .from('notifications')\n .insert({\n user_id: userId,\n message: data.message,\n alert_type: data.alert_type,\n ...(data.created_at ? { created_at: data.created_at } : {}),\n } as TablesInsert<'notifications'>)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n return NotificationRowSchema.parse(row);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NotificationRowSchema,\n type AlertType,\n type NotificationRow,\n type TablesUpdate,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\n/**\n * Notification update data interface\n */\nexport interface NotificationUpdate {\n message?: string;\n alert_type?: AlertType;\n is_read?: boolean;\n}\n\n/**\n * Parameters for useUpdateNotification mutation\n */\nexport interface UpdateNotificationParams {\n userId: string;\n notificationId: string;\n data: NotificationUpdate;\n}\n\n/**\n * Mutation hook for updating a notification\n */\nexport function useUpdateNotification(\n options?: Omit<\n UseMutationOptions<NotificationRow, Error, UpdateNotificationParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({\n userId,\n notificationId,\n data,\n }: UpdateNotificationParams) => {\n const { data: row, error } = await supabase\n .from('notifications')\n .update(data as TablesUpdate<'notifications'>)\n .eq('id', notificationId)\n .eq('user_id', userId)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n return NotificationRowSchema.parse(row);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: notificationKeys.list(userId),\n });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface DeleteNotificationParams {\n userId: string;\n notificationId: string;\n}\n\n/**\n * Delete a notification\n * Supabase: DELETE FROM notifications WHERE id = :notificationId AND user_id = :userId\n */\nexport function useDeleteNotification(\n options?: Omit<UseMutationOptions<void, Error, DeleteNotificationParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, notificationId }: DeleteNotificationParams) => {\n const { error } = await supabase\n .from('notifications')\n .delete()\n .eq('id', notificationId)\n .eq('user_id', userId);\n\n if (error) throw new Error(error.message);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: notificationKeys.list(userId) });\n },\n ...options,\n });\n}\n","import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';\nimport {\n NotificationPreferencesRowSchema,\n type NotificationPreferences,\n type TablesInsert,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client.js';\nimport { notificationKeys } from '../keys.js';\n\nexport interface UpdateNotificationPreferencesParams {\n userId: string;\n data: Partial<NotificationPreferences>;\n}\n\n/**\n * Update user notification preferences\n * Supabase: UPSERT notification_preferences\n *\n * Transforms camelCase input → snake_case for Supabase,\n * then transforms response back to camelCase\n */\nexport function useUpdateNotificationPreferences(\n options?: UseMutationOptions<\n NotificationPreferences,\n Error,\n UpdateNotificationPreferencesParams\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: UpdateNotificationPreferencesParams) => {\n // Transform camelCase → snake_case for Supabase\n const dbData: Record<string, unknown> = { user_id: userId };\n if (data.emailNotifications !== undefined) {\n dbData.email_notifications = data.emailNotifications;\n }\n if (data.pushNotifications !== undefined) {\n dbData.push_notifications = data.pushNotifications;\n }\n if (data.frequency !== undefined) {\n dbData.frequency = data.frequency;\n }\n\n const { data: row, error } = await supabase\n .from('notification_preferences')\n .upsert(dbData as TablesInsert<'notification_preferences'>)\n .select()\n .single();\n\n if (error) throw new Error(error.message);\n\n const validated = NotificationPreferencesRowSchema.parse(row);\n\n // Transform snake_case → camelCase for feature/UI layers\n return {\n emailNotifications: validated.email_notifications,\n pushNotifications: validated.push_notifications,\n frequency: validated.frequency,\n } as NotificationPreferences;\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: notificationKeys.preferences(userId) });\n },\n ...options,\n });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pfm-platform/notifications-data-access",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"axios": "^1.13.2",
|
|
8
7
|
"zod": "4.1.12",
|
|
9
|
-
"@pfm-platform/shared": "0.1
|
|
8
|
+
"@pfm-platform/shared": "0.2.1"
|
|
10
9
|
},
|
|
11
10
|
"devDependencies": {
|
|
12
|
-
"@testing-library/react": "^16.3.
|
|
13
|
-
"@vitejs/plugin-react": "^5.1.
|
|
14
|
-
"@vitest/coverage-v8": "^4.0.
|
|
11
|
+
"@testing-library/react": "^16.3.2",
|
|
12
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
13
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
15
14
|
"jsdom": "^27.2.0",
|
|
16
|
-
"react-dom": "19.2.
|
|
15
|
+
"react-dom": "19.2.4",
|
|
17
16
|
"typescript": "5.9.3",
|
|
18
|
-
"vitest": "4.0.
|
|
17
|
+
"vitest": "4.0.18"
|
|
19
18
|
},
|
|
20
19
|
"module": "./dist/index.js",
|
|
21
20
|
"types": "./dist/index.d.ts",
|