@timothyw/pat-common 1.0.123 → 1.0.125

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.
@@ -4,181 +4,76 @@ import { Serialized } from '../utils';
4
4
 
5
5
  export interface NotificationContext<T = any> {
6
6
  entityId: string;
7
- entityType: string;
7
+ entityType: NotificationEntityType;
8
8
  entityData: T;
9
9
  userId: string;
10
- variables: Record<string, any>;
11
10
  }
12
11
 
13
- /**
14
- * @deprecated Use string types with NotificationEntityRegistry instead
15
- * These enums are kept for backward compatibility during migration
16
- */
17
12
  export enum NotificationParentType {
18
13
  AGENDA_PANEL = 'agenda_panel',
19
14
  }
20
15
 
21
- /**
22
- * @deprecated Use string types with NotificationEntityRegistry instead
23
- * These enums are kept for backward compatibility during migration
24
- */
25
16
  export enum NotificationEntityType {
26
17
  INBOX_PANEL = 'inbox_panel',
27
- AGENDA_PANEL = 'agenda_panel',
18
+ AGENDA_PANEL = 'agenda_item',
28
19
  AGENDA_ITEM = 'agenda_item',
29
20
  }
30
21
 
31
- // Updated to use string instead of enum
32
- export const notificationEntityTypeSchema = z.string();
33
-
34
- export enum NotificationStatus {
35
- SCHEDULED = 'scheduled',
36
- SENT = 'sent',
37
- FAILED = 'failed',
38
- CANCELLED = 'cancelled'
39
- }
40
-
41
22
  export enum NotificationTriggerType {
42
23
  TIME_BASED = 'time_based',
43
24
  EVENT_BASED = 'event_based',
44
25
  RECURRING = 'recurring'
45
26
  }
46
27
 
47
- export const notificationStatusSchema = z.nativeEnum(NotificationStatus);
48
28
  export const notificationTriggerTypeSchema = z.nativeEnum(NotificationTriggerType);
49
29
 
50
30
  export const notificationTriggerSchema = z.object({
51
31
  type: notificationTriggerTypeSchema,
52
- conditions: z.record(z.any()),
53
- timing: z.record(z.any())
54
- });
55
-
56
- export const notificationContentSchema = z.object({
57
- title: z.string(),
58
- body: z.string()
59
32
  });
60
33
 
61
34
  export const notificationTemplateSchema = z.object({
62
35
  _id: notificationTemplateIdSchema,
63
36
  userId: userIdSchema,
64
- entityType: notificationEntityTypeSchema,
37
+ entityType: z.nativeEnum(NotificationEntityType),
65
38
  entityId: z.string().optional(),
66
- name: z.string(),
67
- description: z.string().optional(),
68
39
  trigger: notificationTriggerSchema,
69
- content: notificationContentSchema,
70
40
  active: z.boolean(),
71
41
  createdAt: z.date(),
72
42
  updatedAt: z.date()
73
43
  });
74
44
 
75
- export const createNotificationTemplateSchema = notificationTemplateSchema.omit({
76
- _id: true,
77
- createdAt: true,
78
- updatedAt: true
79
- });
80
-
81
- export const entitySyncStateSchema = z.object({
82
- userId: userIdSchema,
83
- entityType: notificationEntityTypeSchema,
84
- entityId: z.string(),
85
- synced: z.boolean(),
86
- updatedAt: z.date()
87
- });
88
-
89
- export const notificationInstanceSchema = z.object({
90
- _id: notificationInstanceIdSchema,
91
- templateId: notificationTemplateIdSchema,
92
- userId: userIdSchema,
93
- entityId: z.string(),
94
- scheduledFor: z.date(),
95
- status: notificationStatusSchema,
96
- sentAt: z.date().optional(),
97
- content: z.object({
98
- title: z.string(),
99
- body: z.string(),
100
- data: z.record(z.any()).optional()
101
- }),
102
- redisId: z.string(),
103
- error: z.string().optional(),
104
- createdAt: z.date(),
105
- updatedAt: z.date()
106
- });
107
-
108
45
  export const createNotificationTemplateRequestSchema = z.object({
109
- entityType: notificationEntityTypeSchema,
46
+ entityType: z.nativeEnum(NotificationEntityType),
110
47
  entityId: z.string().optional(),
111
- name: z.string().min(1).max(100),
112
- description: z.string().max(500).optional(),
113
48
  trigger: z.object({
114
49
  type: notificationTriggerTypeSchema,
115
- conditions: z.record(z.any()),
116
- timing: z.record(z.any())
117
- }),
118
- content: z.object({
119
- title: z.string().min(1).max(200),
120
- body: z.string().min(1).max(1000)
121
50
  }),
122
51
  active: z.boolean().default(true)
123
52
  });
124
53
 
125
54
  export const updateNotificationTemplateRequestSchema = z.object({
126
- name: z.string().optional(),
127
- description: z.string().optional(),
128
55
  trigger: z.object({
129
56
  type: notificationTriggerTypeSchema,
130
- conditions: z.record(z.any()),
131
- timing: z.record(z.any())
132
- }).optional(),
133
- content: z.object({
134
- title: z.string(),
135
- body: z.string()
136
57
  }).optional(),
137
58
  active: z.boolean().optional()
138
59
  });
139
60
 
140
- export const syncNotificationTemplateRequestSchema = z.object({
141
- sync: z.boolean()
142
- });
143
-
144
- export const previewNotificationTemplateRequestSchema = z.object({
145
- templateTitle: z.string(),
146
- templateBody: z.string(),
147
- entityType: z.string(),
148
- entityId: z.string()
149
- });
150
-
151
- export const getNotificationInstancesRequestSchema = z.object({
152
- status: z.string().optional(),
153
- templateId: z.string().optional(),
154
- entityId: z.string().optional(),
155
- limit: z.number().optional(),
156
- offset: z.number().optional()
157
- });
158
-
159
61
  export const entitySyncRequestSchema = z.object({
160
- entityType: z.string(),
62
+ entityType: z.nativeEnum(NotificationEntityType),
161
63
  entityId: z.string(),
162
64
  synced: z.boolean()
163
65
  });
164
66
 
165
67
  export const getEntitySyncRequestSchema = z.object({
166
- entityType: z.string(),
68
+ entityType: z.nativeEnum(NotificationEntityType),
167
69
  entityId: z.string()
168
70
  });
169
71
 
170
72
  export type NotificationTrigger = z.infer<typeof notificationTriggerSchema>;
171
- export type NotificationContent = z.infer<typeof notificationContentSchema>;
172
73
  export type NotificationTemplateData = z.infer<typeof notificationTemplateSchema>;
173
- export type CreateNotificationTemplateData = z.infer<typeof createNotificationTemplateSchema>;
174
- export type EntitySyncState = z.infer<typeof entitySyncStateSchema>;
175
- export type NotificationInstanceData = z.infer<typeof notificationInstanceSchema>;
176
74
 
177
75
  export type CreateNotificationTemplateRequest = z.infer<typeof createNotificationTemplateRequestSchema>;
178
76
  export type UpdateNotificationTemplateRequest = z.infer<typeof updateNotificationTemplateRequestSchema>;
179
- export type SyncNotificationTemplateRequest = z.infer<typeof syncNotificationTemplateRequestSchema>;
180
- export type PreviewNotificationTemplateRequest = z.infer<typeof previewNotificationTemplateRequestSchema>;
181
- export type GetNotificationInstancesRequest = z.infer<typeof getNotificationInstancesRequestSchema>;
182
77
  export type EntitySyncRequest = z.infer<typeof entitySyncRequestSchema>;
183
78
  export type GetEntitySyncRequest = z.infer<typeof getEntitySyncRequestSchema>;
184
79
 
@@ -200,24 +95,6 @@ export interface UpdateNotificationTemplateResponse {
200
95
 
201
96
  export interface DeleteNotificationTemplateResponse {}
202
97
 
203
- export interface SyncNotificationTemplateResponse {
204
- synced: boolean;
205
- }
206
-
207
- export interface PreviewNotificationTemplateResponse {
208
- preview: {
209
- title: string;
210
- body: string;
211
- };
212
- }
213
-
214
- export interface GetNotificationInstancesResponse {
215
- success: boolean;
216
- instances?: Serialized<NotificationInstanceData>[];
217
- total?: number;
218
- error?: string;
219
- }
220
-
221
98
  export interface EntitySyncResponse {
222
99
  success: boolean;
223
100
  synced: boolean;
@@ -1,241 +0,0 @@
1
- import {
2
- NotificationEntityConfig,
3
- ParentResolver,
4
- ParentResolutionResult,
5
- StaticParentResolver,
6
- DynamicParentResolver
7
- } from './types/notification-entity-config';
8
-
9
- /**
10
- * Registry for managing notification entity configurations and parent resolution
11
- */
12
- export class NotificationEntityRegistry {
13
- private static instance: NotificationEntityRegistry;
14
- private entityConfigs: Map<string, NotificationEntityConfig> = new Map();
15
-
16
- private constructor() {
17
- // Initialize with default configurations
18
- this.registerDefaultEntities();
19
- }
20
-
21
- /**
22
- * Get the singleton instance
23
- */
24
- static getInstance(): NotificationEntityRegistry {
25
- if (!NotificationEntityRegistry.instance) {
26
- NotificationEntityRegistry.instance = new NotificationEntityRegistry();
27
- }
28
- return NotificationEntityRegistry.instance;
29
- }
30
-
31
- /**
32
- * Register a new entity configuration
33
- */
34
- registerEntity(config: NotificationEntityConfig): void {
35
- this.entityConfigs.set(config.entityType, config);
36
- }
37
-
38
- /**
39
- * Get configuration for an entity type
40
- */
41
- getEntityConfig(entityType: string): NotificationEntityConfig | null {
42
- return this.entityConfigs.get(entityType) || null;
43
- }
44
-
45
- /**
46
- * Get all registered entity types
47
- */
48
- getEntityTypes(): string[] {
49
- return Array.from(this.entityConfigs.keys());
50
- }
51
-
52
- /**
53
- * Get all entity configurations
54
- */
55
- getAllConfigs(): NotificationEntityConfig[] {
56
- return Array.from(this.entityConfigs.values());
57
- }
58
-
59
- /**
60
- * Resolve the parent type for a specific entity instance
61
- */
62
- resolveParent(entityType: string, entityData: any): ParentResolutionResult | null {
63
- const config = this.entityConfigs.get(entityType);
64
- if (!config) {
65
- return null;
66
- }
67
-
68
- const resolver = config.parentResolver;
69
-
70
- if (resolver.type === 'static') {
71
- return this.resolveStaticParent(resolver);
72
- } else {
73
- return this.resolveDynamicParent(resolver, entityData);
74
- }
75
- }
76
-
77
- /**
78
- * Check if an entity type supports dynamic parent resolution
79
- */
80
- isDynamicParentType(entityType: string): boolean {
81
- const config = this.entityConfigs.get(entityType);
82
- return config?.parentResolver.type === 'dynamic' || false;
83
- }
84
-
85
- /**
86
- * Get the parent property name for dynamic resolution
87
- */
88
- getParentProperty(entityType: string): string | null {
89
- const config = this.entityConfigs.get(entityType);
90
- if (config?.parentResolver.type === 'dynamic') {
91
- return config.parentResolver.parentProperty;
92
- }
93
- return null;
94
- }
95
-
96
- /**
97
- * Get display name for an entity type
98
- */
99
- getDisplayName(entityType: string): string {
100
- const config = this.entityConfigs.get(entityType);
101
- return config?.displayName || entityType;
102
- }
103
-
104
- /**
105
- * Get icon for an entity type
106
- */
107
- getIcon(entityType: string): string | null {
108
- const config = this.entityConfigs.get(entityType);
109
- return config?.icon || null;
110
- }
111
-
112
- /**
113
- * Check if entity type exists
114
- */
115
- hasEntityType(entityType: string): boolean {
116
- return this.entityConfigs.has(entityType);
117
- }
118
-
119
- /**
120
- * Remove an entity configuration
121
- */
122
- unregisterEntity(entityType: string): boolean {
123
- return this.entityConfigs.delete(entityType);
124
- }
125
-
126
- /**
127
- * Clear all configurations
128
- */
129
- clear(): void {
130
- this.entityConfigs.clear();
131
- }
132
-
133
- /**
134
- * Resolve static parent type
135
- */
136
- private resolveStaticParent(resolver: StaticParentResolver): ParentResolutionResult {
137
- return {
138
- parentType: resolver.parentType,
139
- isDynamic: false
140
- };
141
- }
142
-
143
- /**
144
- * Resolve dynamic parent type based on entity data
145
- */
146
- private resolveDynamicParent(resolver: DynamicParentResolver, entityData: any): ParentResolutionResult {
147
- const propertyValue = entityData?.[resolver.parentProperty];
148
-
149
- if (propertyValue && typeof propertyValue === 'string' && propertyValue.trim()) {
150
- // Use the property value to construct the parent type
151
- const parentType = resolver.parentTypePrefix + propertyValue.trim();
152
- return {
153
- parentType,
154
- isDynamic: true,
155
- resolvedProperty: propertyValue.trim(),
156
- usedFallback: false
157
- };
158
- }
159
-
160
- // Fall back to default parent
161
- return {
162
- parentType: resolver.fallbackParent,
163
- isDynamic: true,
164
- usedFallback: true
165
- };
166
- }
167
-
168
- /**
169
- * Register default entity configurations
170
- */
171
- private registerDefaultEntities(): void {
172
- // Agenda Panel (dynamic parent for agenda items based on category)
173
- this.registerEntity({
174
- entityType: 'agenda_panel',
175
- parentResolver: {
176
- type: 'static',
177
- parentType: 'agenda_panel' // Panel level templates
178
- },
179
- displayName: 'Agenda Panel',
180
- icon: 'calendar',
181
- description: 'Default agenda panel templates'
182
- });
183
-
184
- // Agenda Item (dynamic parent based on category)
185
- this.registerEntity({
186
- entityType: 'agenda_item',
187
- parentResolver: {
188
- type: 'dynamic',
189
- parentProperty: 'category',
190
- parentTypePrefix: 'agenda_category_',
191
- fallbackParent: 'agenda_panel'
192
- },
193
- displayName: 'Agenda Item',
194
- icon: 'calendar',
195
- description: 'Individual agenda item notifications'
196
- });
197
-
198
- // Habits Panel (static parent for habits)
199
- this.registerEntity({
200
- entityType: 'habits_panel',
201
- parentResolver: {
202
- type: 'static',
203
- parentType: 'habits_panel'
204
- },
205
- displayName: 'Habits Panel',
206
- icon: 'fitness',
207
- description: 'Default habits panel templates'
208
- });
209
-
210
- // Habit (static parent - all habits inherit from habits panel)
211
- this.registerEntity({
212
- entityType: 'habit',
213
- parentResolver: {
214
- type: 'static',
215
- parentType: 'habits_panel'
216
- },
217
- displayName: 'Habit',
218
- icon: 'fitness',
219
- description: 'Individual habit notifications'
220
- });
221
-
222
- // Inbox Panel (no parent - top level)
223
- this.registerEntity({
224
- entityType: 'inbox_panel',
225
- parentResolver: {
226
- type: 'static',
227
- parentType: '' // No parent - this is a top-level entity
228
- },
229
- displayName: 'Inbox Panel',
230
- icon: 'mail',
231
- description: 'Inbox notifications'
232
- });
233
- }
234
- }
235
-
236
- /**
237
- * Convenience function to get the singleton instance
238
- */
239
- export function getNotificationEntityRegistry(): NotificationEntityRegistry {
240
- return NotificationEntityRegistry.getInstance();
241
- }
@@ -1,78 +0,0 @@
1
- import { z } from 'zod';
2
-
3
- /**
4
- * Static parent resolver - entity always inherits from the same parent type
5
- */
6
- export interface StaticParentResolver {
7
- type: 'static';
8
- parentType: string;
9
- }
10
-
11
- /**
12
- * Dynamic parent resolver - parent determined by entity properties
13
- */
14
- export interface DynamicParentResolver {
15
- type: 'dynamic';
16
- parentProperty: string; // Property name on entity (e.g., 'category')
17
- parentTypePrefix: string; // Prefix for parent type (e.g., 'agenda_category_')
18
- fallbackParent: string; // Default parent if property is missing/empty
19
- }
20
-
21
- export type ParentResolver = StaticParentResolver | DynamicParentResolver;
22
-
23
- /**
24
- * Configuration for a notification entity type
25
- */
26
- export interface NotificationEntityConfig {
27
- entityType: string;
28
- parentResolver: ParentResolver;
29
- displayName: string;
30
- icon?: string;
31
- description?: string;
32
- }
33
-
34
- /**
35
- * Result of parent resolution for a specific entity instance
36
- */
37
- export interface ParentResolutionResult {
38
- parentType: string;
39
- isDynamic: boolean;
40
- resolvedProperty?: string;
41
- usedFallback?: boolean;
42
- }
43
-
44
- /**
45
- * Zod schemas for validation
46
- */
47
- export const staticParentResolverSchema = z.object({
48
- type: z.literal('static'),
49
- parentType: z.string()
50
- });
51
-
52
- export const dynamicParentResolverSchema = z.object({
53
- type: z.literal('dynamic'),
54
- parentProperty: z.string(),
55
- parentTypePrefix: z.string(),
56
- fallbackParent: z.string()
57
- });
58
-
59
- export const parentResolverSchema = z.union([
60
- staticParentResolverSchema,
61
- dynamicParentResolverSchema
62
- ]);
63
-
64
- export const notificationEntityConfigSchema = z.object({
65
- entityType: z.string(),
66
- parentResolver: parentResolverSchema,
67
- displayName: z.string(),
68
- icon: z.string().optional(),
69
- description: z.string().optional()
70
- });
71
-
72
- /**
73
- * Type exports
74
- */
75
- export type StaticParentResolverData = z.infer<typeof staticParentResolverSchema>;
76
- export type DynamicParentResolverData = z.infer<typeof dynamicParentResolverSchema>;
77
- export type ParentResolverData = z.infer<typeof parentResolverSchema>;
78
- export type NotificationEntityConfigData = z.infer<typeof notificationEntityConfigSchema>;