@timothyw/pat-common 1.0.120 → 1.0.122

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.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './enums';
2
2
  export * from './types';
3
3
  export * from './utils';
4
+ export * from './notification-entity-registry';
package/dist/index.js CHANGED
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./enums"), exports);
18
18
  __exportStar(require("./types"), exports);
19
19
  __exportStar(require("./utils"), exports);
20
+ __exportStar(require("./notification-entity-registry"), exports);
@@ -0,0 +1,77 @@
1
+ import { NotificationEntityConfig, ParentResolutionResult } from './types/notification-entity-config';
2
+ /**
3
+ * Registry for managing notification entity configurations and parent resolution
4
+ */
5
+ export declare class NotificationEntityRegistry {
6
+ private static instance;
7
+ private entityConfigs;
8
+ private constructor();
9
+ /**
10
+ * Get the singleton instance
11
+ */
12
+ static getInstance(): NotificationEntityRegistry;
13
+ /**
14
+ * Register a new entity configuration
15
+ */
16
+ registerEntity(config: NotificationEntityConfig): void;
17
+ /**
18
+ * Get configuration for an entity type
19
+ */
20
+ getEntityConfig(entityType: string): NotificationEntityConfig | null;
21
+ /**
22
+ * Get all registered entity types
23
+ */
24
+ getEntityTypes(): string[];
25
+ /**
26
+ * Get all entity configurations
27
+ */
28
+ getAllConfigs(): NotificationEntityConfig[];
29
+ /**
30
+ * Resolve the parent type for a specific entity instance
31
+ */
32
+ resolveParent(entityType: string, entityData: any): ParentResolutionResult | null;
33
+ /**
34
+ * Check if an entity type supports dynamic parent resolution
35
+ */
36
+ isDynamicParentType(entityType: string): boolean;
37
+ /**
38
+ * Get the parent property name for dynamic resolution
39
+ */
40
+ getParentProperty(entityType: string): string | null;
41
+ /**
42
+ * Get display name for an entity type
43
+ */
44
+ getDisplayName(entityType: string): string;
45
+ /**
46
+ * Get icon for an entity type
47
+ */
48
+ getIcon(entityType: string): string | null;
49
+ /**
50
+ * Check if entity type exists
51
+ */
52
+ hasEntityType(entityType: string): boolean;
53
+ /**
54
+ * Remove an entity configuration
55
+ */
56
+ unregisterEntity(entityType: string): boolean;
57
+ /**
58
+ * Clear all configurations
59
+ */
60
+ clear(): void;
61
+ /**
62
+ * Resolve static parent type
63
+ */
64
+ private resolveStaticParent;
65
+ /**
66
+ * Resolve dynamic parent type based on entity data
67
+ */
68
+ private resolveDynamicParent;
69
+ /**
70
+ * Register default entity configurations
71
+ */
72
+ private registerDefaultEntities;
73
+ }
74
+ /**
75
+ * Convenience function to get the singleton instance
76
+ */
77
+ export declare function getNotificationEntityRegistry(): NotificationEntityRegistry;
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotificationEntityRegistry = void 0;
4
+ exports.getNotificationEntityRegistry = getNotificationEntityRegistry;
5
+ /**
6
+ * Registry for managing notification entity configurations and parent resolution
7
+ */
8
+ class NotificationEntityRegistry {
9
+ constructor() {
10
+ this.entityConfigs = new Map();
11
+ // Initialize with default configurations
12
+ this.registerDefaultEntities();
13
+ }
14
+ /**
15
+ * Get the singleton instance
16
+ */
17
+ static getInstance() {
18
+ if (!NotificationEntityRegistry.instance) {
19
+ NotificationEntityRegistry.instance = new NotificationEntityRegistry();
20
+ }
21
+ return NotificationEntityRegistry.instance;
22
+ }
23
+ /**
24
+ * Register a new entity configuration
25
+ */
26
+ registerEntity(config) {
27
+ this.entityConfigs.set(config.entityType, config);
28
+ }
29
+ /**
30
+ * Get configuration for an entity type
31
+ */
32
+ getEntityConfig(entityType) {
33
+ return this.entityConfigs.get(entityType) || null;
34
+ }
35
+ /**
36
+ * Get all registered entity types
37
+ */
38
+ getEntityTypes() {
39
+ return Array.from(this.entityConfigs.keys());
40
+ }
41
+ /**
42
+ * Get all entity configurations
43
+ */
44
+ getAllConfigs() {
45
+ return Array.from(this.entityConfigs.values());
46
+ }
47
+ /**
48
+ * Resolve the parent type for a specific entity instance
49
+ */
50
+ resolveParent(entityType, entityData) {
51
+ const config = this.entityConfigs.get(entityType);
52
+ if (!config) {
53
+ return null;
54
+ }
55
+ const resolver = config.parentResolver;
56
+ if (resolver.type === 'static') {
57
+ return this.resolveStaticParent(resolver);
58
+ }
59
+ else {
60
+ return this.resolveDynamicParent(resolver, entityData);
61
+ }
62
+ }
63
+ /**
64
+ * Check if an entity type supports dynamic parent resolution
65
+ */
66
+ isDynamicParentType(entityType) {
67
+ const config = this.entityConfigs.get(entityType);
68
+ return config?.parentResolver.type === 'dynamic' || false;
69
+ }
70
+ /**
71
+ * Get the parent property name for dynamic resolution
72
+ */
73
+ getParentProperty(entityType) {
74
+ const config = this.entityConfigs.get(entityType);
75
+ if (config?.parentResolver.type === 'dynamic') {
76
+ return config.parentResolver.parentProperty;
77
+ }
78
+ return null;
79
+ }
80
+ /**
81
+ * Get display name for an entity type
82
+ */
83
+ getDisplayName(entityType) {
84
+ const config = this.entityConfigs.get(entityType);
85
+ return config?.displayName || entityType;
86
+ }
87
+ /**
88
+ * Get icon for an entity type
89
+ */
90
+ getIcon(entityType) {
91
+ const config = this.entityConfigs.get(entityType);
92
+ return config?.icon || null;
93
+ }
94
+ /**
95
+ * Check if entity type exists
96
+ */
97
+ hasEntityType(entityType) {
98
+ return this.entityConfigs.has(entityType);
99
+ }
100
+ /**
101
+ * Remove an entity configuration
102
+ */
103
+ unregisterEntity(entityType) {
104
+ return this.entityConfigs.delete(entityType);
105
+ }
106
+ /**
107
+ * Clear all configurations
108
+ */
109
+ clear() {
110
+ this.entityConfigs.clear();
111
+ }
112
+ /**
113
+ * Resolve static parent type
114
+ */
115
+ resolveStaticParent(resolver) {
116
+ return {
117
+ parentType: resolver.parentType,
118
+ isDynamic: false
119
+ };
120
+ }
121
+ /**
122
+ * Resolve dynamic parent type based on entity data
123
+ */
124
+ resolveDynamicParent(resolver, entityData) {
125
+ const propertyValue = entityData?.[resolver.parentProperty];
126
+ if (propertyValue && typeof propertyValue === 'string' && propertyValue.trim()) {
127
+ // Use the property value to construct the parent type
128
+ const parentType = resolver.parentTypePrefix + propertyValue.trim();
129
+ return {
130
+ parentType,
131
+ isDynamic: true,
132
+ resolvedProperty: propertyValue.trim(),
133
+ usedFallback: false
134
+ };
135
+ }
136
+ // Fall back to default parent
137
+ return {
138
+ parentType: resolver.fallbackParent,
139
+ isDynamic: true,
140
+ usedFallback: true
141
+ };
142
+ }
143
+ /**
144
+ * Register default entity configurations
145
+ */
146
+ registerDefaultEntities() {
147
+ // Agenda Panel (static parent of agenda items)
148
+ this.registerEntity({
149
+ entityType: 'agenda_panel',
150
+ parentResolver: {
151
+ type: 'static',
152
+ parentType: 'agenda_panel' // Self-referencing for panel level
153
+ },
154
+ displayName: 'Agenda Panel',
155
+ icon: 'calendar',
156
+ description: 'Default notification templates for all agenda items'
157
+ });
158
+ // Agenda Item (can have dynamic parent based on category)
159
+ this.registerEntity({
160
+ entityType: 'agenda_item',
161
+ parentResolver: {
162
+ type: 'dynamic',
163
+ parentProperty: 'category',
164
+ parentTypePrefix: 'agenda_category_',
165
+ fallbackParent: 'agenda_panel'
166
+ },
167
+ displayName: 'Agenda Item',
168
+ icon: 'calendar',
169
+ description: 'Individual agenda item notifications'
170
+ });
171
+ // Inbox Panel
172
+ this.registerEntity({
173
+ entityType: 'inbox_panel',
174
+ parentResolver: {
175
+ type: 'static',
176
+ parentType: 'inbox_panel' // Self-referencing for panel level
177
+ },
178
+ displayName: 'Inbox Panel',
179
+ icon: 'mail',
180
+ description: 'Inbox notification templates'
181
+ });
182
+ }
183
+ }
184
+ exports.NotificationEntityRegistry = NotificationEntityRegistry;
185
+ /**
186
+ * Convenience function to get the singleton instance
187
+ */
188
+ function getNotificationEntityRegistry() {
189
+ return NotificationEntityRegistry.getInstance();
190
+ }
@@ -6,7 +6,7 @@ export * from './id-types';
6
6
  export * from './people-types';
7
7
  export * from './lists-types';
8
8
  export * from './notifications-types';
9
+ export * from './notification-entity-config';
9
10
  export * from './auth-types';
10
11
  export * from './user-types';
11
12
  export * from './program-config-types';
12
- export * from './misc';
@@ -22,7 +22,7 @@ __exportStar(require("./id-types"), exports);
22
22
  __exportStar(require("./people-types"), exports);
23
23
  __exportStar(require("./lists-types"), exports);
24
24
  __exportStar(require("./notifications-types"), exports);
25
+ __exportStar(require("./notification-entity-config"), exports);
25
26
  __exportStar(require("./auth-types"), exports);
26
27
  __exportStar(require("./user-types"), exports);
27
28
  __exportStar(require("./program-config-types"), exports);
28
- __exportStar(require("./misc"), exports);
@@ -0,0 +1,157 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Static parent resolver - entity always inherits from the same parent type
4
+ */
5
+ export interface StaticParentResolver {
6
+ type: 'static';
7
+ parentType: string;
8
+ }
9
+ /**
10
+ * Dynamic parent resolver - parent determined by entity properties
11
+ */
12
+ export interface DynamicParentResolver {
13
+ type: 'dynamic';
14
+ parentProperty: string;
15
+ parentTypePrefix: string;
16
+ fallbackParent: string;
17
+ }
18
+ export type ParentResolver = StaticParentResolver | DynamicParentResolver;
19
+ /**
20
+ * Configuration for a notification entity type
21
+ */
22
+ export interface NotificationEntityConfig {
23
+ entityType: string;
24
+ parentResolver: ParentResolver;
25
+ displayName: string;
26
+ icon?: string;
27
+ description?: string;
28
+ }
29
+ /**
30
+ * Result of parent resolution for a specific entity instance
31
+ */
32
+ export interface ParentResolutionResult {
33
+ parentType: string;
34
+ isDynamic: boolean;
35
+ resolvedProperty?: string;
36
+ usedFallback?: boolean;
37
+ }
38
+ /**
39
+ * Zod schemas for validation
40
+ */
41
+ export declare const staticParentResolverSchema: z.ZodObject<{
42
+ type: z.ZodLiteral<"static">;
43
+ parentType: z.ZodString;
44
+ }, "strip", z.ZodTypeAny, {
45
+ type: "static";
46
+ parentType: string;
47
+ }, {
48
+ type: "static";
49
+ parentType: string;
50
+ }>;
51
+ export declare const dynamicParentResolverSchema: z.ZodObject<{
52
+ type: z.ZodLiteral<"dynamic">;
53
+ parentProperty: z.ZodString;
54
+ parentTypePrefix: z.ZodString;
55
+ fallbackParent: z.ZodString;
56
+ }, "strip", z.ZodTypeAny, {
57
+ type: "dynamic";
58
+ parentProperty: string;
59
+ parentTypePrefix: string;
60
+ fallbackParent: string;
61
+ }, {
62
+ type: "dynamic";
63
+ parentProperty: string;
64
+ parentTypePrefix: string;
65
+ fallbackParent: string;
66
+ }>;
67
+ export declare const parentResolverSchema: z.ZodUnion<[z.ZodObject<{
68
+ type: z.ZodLiteral<"static">;
69
+ parentType: z.ZodString;
70
+ }, "strip", z.ZodTypeAny, {
71
+ type: "static";
72
+ parentType: string;
73
+ }, {
74
+ type: "static";
75
+ parentType: string;
76
+ }>, z.ZodObject<{
77
+ type: z.ZodLiteral<"dynamic">;
78
+ parentProperty: z.ZodString;
79
+ parentTypePrefix: z.ZodString;
80
+ fallbackParent: z.ZodString;
81
+ }, "strip", z.ZodTypeAny, {
82
+ type: "dynamic";
83
+ parentProperty: string;
84
+ parentTypePrefix: string;
85
+ fallbackParent: string;
86
+ }, {
87
+ type: "dynamic";
88
+ parentProperty: string;
89
+ parentTypePrefix: string;
90
+ fallbackParent: string;
91
+ }>]>;
92
+ export declare const notificationEntityConfigSchema: z.ZodObject<{
93
+ entityType: z.ZodString;
94
+ parentResolver: z.ZodUnion<[z.ZodObject<{
95
+ type: z.ZodLiteral<"static">;
96
+ parentType: z.ZodString;
97
+ }, "strip", z.ZodTypeAny, {
98
+ type: "static";
99
+ parentType: string;
100
+ }, {
101
+ type: "static";
102
+ parentType: string;
103
+ }>, z.ZodObject<{
104
+ type: z.ZodLiteral<"dynamic">;
105
+ parentProperty: z.ZodString;
106
+ parentTypePrefix: z.ZodString;
107
+ fallbackParent: z.ZodString;
108
+ }, "strip", z.ZodTypeAny, {
109
+ type: "dynamic";
110
+ parentProperty: string;
111
+ parentTypePrefix: string;
112
+ fallbackParent: string;
113
+ }, {
114
+ type: "dynamic";
115
+ parentProperty: string;
116
+ parentTypePrefix: string;
117
+ fallbackParent: string;
118
+ }>]>;
119
+ displayName: z.ZodString;
120
+ icon: z.ZodOptional<z.ZodString>;
121
+ description: z.ZodOptional<z.ZodString>;
122
+ }, "strip", z.ZodTypeAny, {
123
+ entityType: string;
124
+ parentResolver: {
125
+ type: "static";
126
+ parentType: string;
127
+ } | {
128
+ type: "dynamic";
129
+ parentProperty: string;
130
+ parentTypePrefix: string;
131
+ fallbackParent: string;
132
+ };
133
+ displayName: string;
134
+ description?: string | undefined;
135
+ icon?: string | undefined;
136
+ }, {
137
+ entityType: string;
138
+ parentResolver: {
139
+ type: "static";
140
+ parentType: string;
141
+ } | {
142
+ type: "dynamic";
143
+ parentProperty: string;
144
+ parentTypePrefix: string;
145
+ fallbackParent: string;
146
+ };
147
+ displayName: string;
148
+ description?: string | undefined;
149
+ icon?: string | undefined;
150
+ }>;
151
+ /**
152
+ * Type exports
153
+ */
154
+ export type StaticParentResolverData = z.infer<typeof staticParentResolverSchema>;
155
+ export type DynamicParentResolverData = z.infer<typeof dynamicParentResolverSchema>;
156
+ export type ParentResolverData = z.infer<typeof parentResolverSchema>;
157
+ export type NotificationEntityConfigData = z.infer<typeof notificationEntityConfigSchema>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.notificationEntityConfigSchema = exports.parentResolverSchema = exports.dynamicParentResolverSchema = exports.staticParentResolverSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ /**
6
+ * Zod schemas for validation
7
+ */
8
+ exports.staticParentResolverSchema = zod_1.z.object({
9
+ type: zod_1.z.literal('static'),
10
+ parentType: zod_1.z.string()
11
+ });
12
+ exports.dynamicParentResolverSchema = zod_1.z.object({
13
+ type: zod_1.z.literal('dynamic'),
14
+ parentProperty: zod_1.z.string(),
15
+ parentTypePrefix: zod_1.z.string(),
16
+ fallbackParent: zod_1.z.string()
17
+ });
18
+ exports.parentResolverSchema = zod_1.z.union([
19
+ exports.staticParentResolverSchema,
20
+ exports.dynamicParentResolverSchema
21
+ ]);
22
+ exports.notificationEntityConfigSchema = zod_1.z.object({
23
+ entityType: zod_1.z.string(),
24
+ parentResolver: exports.parentResolverSchema,
25
+ displayName: zod_1.z.string(),
26
+ icon: zod_1.z.string().optional(),
27
+ description: zod_1.z.string().optional()
28
+ });
@@ -2,23 +2,28 @@ import { z } from 'zod';
2
2
  import { Serialized } from '../utils';
3
3
  export interface NotificationContext<T = any> {
4
4
  entityId: string;
5
- entityType: NotificationEntityType;
5
+ entityType: string;
6
6
  entityData: T;
7
7
  userId: string;
8
8
  variables: Record<string, any>;
9
9
  }
10
+ /**
11
+ * @deprecated Use string types with NotificationEntityRegistry instead
12
+ * These enums are kept for backward compatibility during migration
13
+ */
14
+ export declare enum NotificationParentType {
15
+ AGENDA_PANEL = "agenda_panel"
16
+ }
17
+ /**
18
+ * @deprecated Use string types with NotificationEntityRegistry instead
19
+ * These enums are kept for backward compatibility during migration
20
+ */
10
21
  export declare enum NotificationEntityType {
11
- AGENDA = "agenda",
12
- TASKS = "tasks",
13
- HABITS = "habits",
14
- INBOX = "inbox",
15
- AGENDA_ITEM = "agenda_item",
16
- HABIT = "habit",
17
- AGENDA_DEFAULTS = "agenda_defaults",
18
- HABITS_DEFAULTS = "habits_defaults",
19
- INBOX_PANEL = "inbox_panel"
22
+ INBOX_PANEL = "inbox_panel",
23
+ AGENDA_PANEL = "agenda_panel",
24
+ AGENDA_ITEM = "agenda_item"
20
25
  }
21
- export declare const notificationEntityTypeSchema: z.ZodNativeEnum<typeof NotificationEntityType>;
26
+ export declare const notificationEntityTypeSchema: z.ZodString;
22
27
  export declare enum NotificationStatus {
23
28
  SCHEDULED = "scheduled",
24
29
  SENT = "sent",
@@ -61,7 +66,7 @@ export declare const notificationContentSchema: z.ZodObject<{
61
66
  export declare const notificationTemplateSchema: z.ZodObject<{
62
67
  _id: z.ZodEffects<z.ZodString, import("./id-types").NotificationTemplateId, string>;
63
68
  userId: z.ZodEffects<z.ZodString, import("./id-types").UserId, string>;
64
- entityType: z.ZodNativeEnum<typeof NotificationEntityType>;
69
+ entityType: z.ZodString;
65
70
  entityId: z.ZodOptional<z.ZodString>;
66
71
  name: z.ZodString;
67
72
  description: z.ZodOptional<z.ZodString>;
@@ -111,7 +116,7 @@ export declare const notificationTemplateSchema: z.ZodObject<{
111
116
  body: string;
112
117
  variables?: Record<string, string> | undefined;
113
118
  };
114
- entityType: NotificationEntityType;
119
+ entityType: string;
115
120
  trigger: {
116
121
  type: NotificationTriggerType;
117
122
  conditions: Record<string, any>;
@@ -133,7 +138,7 @@ export declare const notificationTemplateSchema: z.ZodObject<{
133
138
  body: string;
134
139
  variables?: Record<string, string> | undefined;
135
140
  };
136
- entityType: NotificationEntityType;
141
+ entityType: string;
137
142
  trigger: {
138
143
  type: NotificationTriggerType;
139
144
  conditions: Record<string, any>;
@@ -148,7 +153,7 @@ export declare const notificationTemplateSchema: z.ZodObject<{
148
153
  export declare const createNotificationTemplateSchema: z.ZodObject<Omit<{
149
154
  _id: z.ZodEffects<z.ZodString, import("./id-types").NotificationTemplateId, string>;
150
155
  userId: z.ZodEffects<z.ZodString, import("./id-types").UserId, string>;
151
- entityType: z.ZodNativeEnum<typeof NotificationEntityType>;
156
+ entityType: z.ZodString;
152
157
  entityId: z.ZodOptional<z.ZodString>;
153
158
  name: z.ZodString;
154
159
  description: z.ZodOptional<z.ZodString>;
@@ -193,7 +198,7 @@ export declare const createNotificationTemplateSchema: z.ZodObject<Omit<{
193
198
  body: string;
194
199
  variables?: Record<string, string> | undefined;
195
200
  };
196
- entityType: NotificationEntityType;
201
+ entityType: string;
197
202
  trigger: {
198
203
  type: NotificationTriggerType;
199
204
  conditions: Record<string, any>;
@@ -212,7 +217,7 @@ export declare const createNotificationTemplateSchema: z.ZodObject<Omit<{
212
217
  body: string;
213
218
  variables?: Record<string, string> | undefined;
214
219
  };
215
- entityType: NotificationEntityType;
220
+ entityType: string;
216
221
  trigger: {
217
222
  type: NotificationTriggerType;
218
223
  conditions: Record<string, any>;
@@ -226,7 +231,7 @@ export declare const createNotificationTemplateSchema: z.ZodObject<Omit<{
226
231
  }>;
227
232
  export declare const entitySyncStateSchema: z.ZodObject<{
228
233
  userId: z.ZodEffects<z.ZodString, import("./id-types").UserId, string>;
229
- entityType: z.ZodNativeEnum<typeof NotificationEntityType>;
234
+ entityType: z.ZodString;
230
235
  entityId: z.ZodString;
231
236
  synced: z.ZodBoolean;
232
237
  updatedAt: z.ZodDate;
@@ -235,13 +240,13 @@ export declare const entitySyncStateSchema: z.ZodObject<{
235
240
  userId: string & {
236
241
  readonly __brand: "UserId";
237
242
  };
238
- entityType: NotificationEntityType;
243
+ entityType: string;
239
244
  entityId: string;
240
245
  synced: boolean;
241
246
  }, {
242
247
  updatedAt: Date;
243
248
  userId: string;
244
- entityType: NotificationEntityType;
249
+ entityType: string;
245
250
  entityId: string;
246
251
  synced: boolean;
247
252
  }>;
@@ -312,7 +317,7 @@ export declare const notificationInstanceSchema: z.ZodObject<{
312
317
  error?: string | undefined;
313
318
  }>;
314
319
  export declare const createNotificationTemplateRequestSchema: z.ZodObject<{
315
- entityType: z.ZodNativeEnum<typeof NotificationEntityType>;
320
+ entityType: z.ZodString;
316
321
  entityId: z.ZodOptional<z.ZodString>;
317
322
  name: z.ZodString;
318
323
  description: z.ZodOptional<z.ZodString>;
@@ -352,7 +357,7 @@ export declare const createNotificationTemplateRequestSchema: z.ZodObject<{
352
357
  body: string;
353
358
  variables?: Record<string, string> | undefined;
354
359
  };
355
- entityType: NotificationEntityType;
360
+ entityType: string;
356
361
  trigger: {
357
362
  type: NotificationTriggerType;
358
363
  conditions: Record<string, any>;
@@ -370,7 +375,7 @@ export declare const createNotificationTemplateRequestSchema: z.ZodObject<{
370
375
  body: string;
371
376
  variables?: Record<string, string> | undefined;
372
377
  };
373
- entityType: NotificationEntityType;
378
+ entityType: string;
374
379
  trigger: {
375
380
  type: NotificationTriggerType;
376
381
  conditions: Record<string, any>;
@@ -1,21 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getEntitySyncRequestSchema = exports.entitySyncRequestSchema = exports.getNotificationInstancesRequestSchema = exports.previewNotificationTemplateRequestSchema = exports.syncNotificationTemplateRequestSchema = exports.updateNotificationTemplateRequestSchema = exports.createNotificationTemplateRequestSchema = exports.notificationInstanceSchema = exports.entitySyncStateSchema = exports.createNotificationTemplateSchema = exports.notificationTemplateSchema = exports.notificationContentSchema = exports.notificationTriggerSchema = exports.notificationTriggerTypeSchema = exports.notificationStatusSchema = exports.NotificationTriggerType = exports.NotificationStatus = exports.notificationEntityTypeSchema = exports.NotificationEntityType = void 0;
3
+ exports.getEntitySyncRequestSchema = exports.entitySyncRequestSchema = exports.getNotificationInstancesRequestSchema = exports.previewNotificationTemplateRequestSchema = exports.syncNotificationTemplateRequestSchema = exports.updateNotificationTemplateRequestSchema = exports.createNotificationTemplateRequestSchema = exports.notificationInstanceSchema = exports.entitySyncStateSchema = exports.createNotificationTemplateSchema = exports.notificationTemplateSchema = exports.notificationContentSchema = exports.notificationTriggerSchema = exports.notificationTriggerTypeSchema = exports.notificationStatusSchema = exports.NotificationTriggerType = exports.NotificationStatus = exports.notificationEntityTypeSchema = exports.NotificationEntityType = exports.NotificationParentType = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const id_types_1 = require("./id-types");
6
+ /**
7
+ * @deprecated Use string types with NotificationEntityRegistry instead
8
+ * These enums are kept for backward compatibility during migration
9
+ */
10
+ var NotificationParentType;
11
+ (function (NotificationParentType) {
12
+ NotificationParentType["AGENDA_PANEL"] = "agenda_panel";
13
+ })(NotificationParentType || (exports.NotificationParentType = NotificationParentType = {}));
14
+ /**
15
+ * @deprecated Use string types with NotificationEntityRegistry instead
16
+ * These enums are kept for backward compatibility during migration
17
+ */
6
18
  var NotificationEntityType;
7
19
  (function (NotificationEntityType) {
8
- NotificationEntityType["AGENDA"] = "agenda";
9
- NotificationEntityType["TASKS"] = "tasks";
10
- NotificationEntityType["HABITS"] = "habits";
11
- NotificationEntityType["INBOX"] = "inbox";
12
- NotificationEntityType["AGENDA_ITEM"] = "agenda_item";
13
- NotificationEntityType["HABIT"] = "habit";
14
- NotificationEntityType["AGENDA_DEFAULTS"] = "agenda_defaults";
15
- NotificationEntityType["HABITS_DEFAULTS"] = "habits_defaults";
16
20
  NotificationEntityType["INBOX_PANEL"] = "inbox_panel";
21
+ NotificationEntityType["AGENDA_PANEL"] = "agenda_panel";
22
+ NotificationEntityType["AGENDA_ITEM"] = "agenda_item";
17
23
  })(NotificationEntityType || (exports.NotificationEntityType = NotificationEntityType = {}));
18
- exports.notificationEntityTypeSchema = zod_1.z.nativeEnum(NotificationEntityType);
24
+ // Updated to use string instead of enum
25
+ exports.notificationEntityTypeSchema = zod_1.z.string();
19
26
  var NotificationStatus;
20
27
  (function (NotificationStatus) {
21
28
  NotificationStatus["SCHEDULED"] = "scheduled";
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@timothyw/pat-common",
3
3
  "description": "",
4
4
  "author": "Timothy Washburn",
5
- "version": "1.0.120",
5
+ "version": "1.0.122",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "scripts": {
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './enums'
2
2
  export * from './types'
3
- export * from './utils'
3
+ export * from './utils'
4
+ export * from './notification-entity-registry'
@@ -0,0 +1,217 @@
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 (static parent of agenda items)
173
+ this.registerEntity({
174
+ entityType: 'agenda_panel',
175
+ parentResolver: {
176
+ type: 'static',
177
+ parentType: 'agenda_panel' // Self-referencing for panel level
178
+ },
179
+ displayName: 'Agenda Panel',
180
+ icon: 'calendar',
181
+ description: 'Default notification templates for all agenda items'
182
+ });
183
+
184
+ // Agenda Item (can have 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
+ // Inbox Panel
199
+ this.registerEntity({
200
+ entityType: 'inbox_panel',
201
+ parentResolver: {
202
+ type: 'static',
203
+ parentType: 'inbox_panel' // Self-referencing for panel level
204
+ },
205
+ displayName: 'Inbox Panel',
206
+ icon: 'mail',
207
+ description: 'Inbox notification templates'
208
+ });
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Convenience function to get the singleton instance
214
+ */
215
+ export function getNotificationEntityRegistry(): NotificationEntityRegistry {
216
+ return NotificationEntityRegistry.getInstance();
217
+ }
@@ -6,7 +6,7 @@ export * from './id-types';
6
6
  export * from './people-types';
7
7
  export * from './lists-types';
8
8
  export * from './notifications-types';
9
+ export * from './notification-entity-config';
9
10
  export * from './auth-types';
10
11
  export * from './user-types';
11
- export * from './program-config-types';
12
- export * from './misc';
12
+ export * from './program-config-types';
@@ -0,0 +1,78 @@
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>;
@@ -4,25 +4,32 @@ import { Serialized } from '../utils';
4
4
 
5
5
  export interface NotificationContext<T = any> {
6
6
  entityId: string;
7
- entityType: NotificationEntityType;
7
+ entityType: string;
8
8
  entityData: T;
9
9
  userId: string;
10
10
  variables: Record<string, any>;
11
11
  }
12
12
 
13
+ /**
14
+ * @deprecated Use string types with NotificationEntityRegistry instead
15
+ * These enums are kept for backward compatibility during migration
16
+ */
17
+ export enum NotificationParentType {
18
+ AGENDA_PANEL = 'agenda_panel',
19
+ }
20
+
21
+ /**
22
+ * @deprecated Use string types with NotificationEntityRegistry instead
23
+ * These enums are kept for backward compatibility during migration
24
+ */
13
25
  export enum NotificationEntityType {
14
- AGENDA = 'agenda',
15
- TASKS = 'tasks',
16
- HABITS = 'habits',
17
- INBOX = 'inbox',
26
+ INBOX_PANEL = 'inbox_panel',
27
+ AGENDA_PANEL = 'agenda_panel',
18
28
  AGENDA_ITEM = 'agenda_item',
19
- HABIT = 'habit',
20
- AGENDA_DEFAULTS = 'agenda_defaults',
21
- HABITS_DEFAULTS = 'habits_defaults',
22
- INBOX_PANEL = 'inbox_panel'
23
29
  }
24
30
 
25
- export const notificationEntityTypeSchema = z.nativeEnum(NotificationEntityType);
31
+ // Updated to use string instead of enum
32
+ export const notificationEntityTypeSchema = z.string();
26
33
 
27
34
  export enum NotificationStatus {
28
35
  SCHEDULED = 'scheduled',