@contractspec/module.notifications 1.46.1 → 1.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["available: NotificationChannel[]"],"sources":["../../src/channels/index.ts"],"sourcesContent":["/**\n * Notification channel interface.\n */\nexport interface NotificationChannel {\n /** Channel identifier */\n readonly channelId: string;\n /** Deliver a notification */\n send(notification: ChannelNotification): Promise<ChannelDeliveryResult>;\n /** Check if channel is available */\n isAvailable(): Promise<boolean>;\n}\n\n/**\n * Notification to deliver via a channel.\n */\nexport interface ChannelNotification {\n id: string;\n userId: string;\n title: string;\n body: string;\n actionUrl?: string;\n imageUrl?: string;\n metadata?: Record<string, unknown>;\n // Channel-specific data\n email?: {\n to: string;\n subject: string;\n html?: string;\n text?: string;\n };\n push?: {\n token: string;\n badge?: number;\n sound?: string;\n data?: Record<string, unknown>;\n };\n webhook?: {\n url: string;\n headers?: Record<string, string>;\n };\n}\n\n/**\n * Result of channel delivery attempt.\n */\nexport interface ChannelDeliveryResult {\n success: boolean;\n externalId?: string;\n responseCode?: string;\n responseMessage?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * In-app notification channel (stores in database).\n */\nexport class InAppChannel implements NotificationChannel {\n readonly channelId = 'IN_APP';\n\n async send(\n _notification: ChannelNotification\n ): Promise<ChannelDeliveryResult> {\n // In-app notifications are stored directly in the database\n // The actual delivery is handled by the notification service\n return {\n success: true,\n responseMessage: 'Stored in database',\n };\n }\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Console channel for development/testing.\n */\nexport class ConsoleChannel implements NotificationChannel {\n readonly channelId = 'CONSOLE';\n\n async send(\n notification: ChannelNotification\n ): Promise<ChannelDeliveryResult> {\n console.log(`📬 [${notification.id}] ${notification.title}`);\n console.log(` ${notification.body}`);\n if (notification.actionUrl) {\n console.log(` Action: ${notification.actionUrl}`);\n }\n return {\n success: true,\n responseMessage: 'Logged to console',\n };\n }\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Email channel interface (to be implemented with provider).\n */\nexport abstract class EmailChannel implements NotificationChannel {\n readonly channelId = 'EMAIL';\n\n abstract send(\n notification: ChannelNotification\n ): Promise<ChannelDeliveryResult>;\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Push notification channel interface (to be implemented with provider).\n */\nexport abstract class PushChannel implements NotificationChannel {\n readonly channelId = 'PUSH';\n\n abstract send(\n notification: ChannelNotification\n ): Promise<ChannelDeliveryResult>;\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Webhook channel for external integrations.\n */\nexport class WebhookChannel implements NotificationChannel {\n readonly channelId = 'WEBHOOK';\n\n async send(\n notification: ChannelNotification\n ): Promise<ChannelDeliveryResult> {\n if (!notification.webhook?.url) {\n return {\n success: false,\n responseMessage: 'No webhook URL configured',\n };\n }\n\n try {\n const response = await fetch(notification.webhook.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...notification.webhook.headers,\n },\n body: JSON.stringify({\n id: notification.id,\n title: notification.title,\n body: notification.body,\n actionUrl: notification.actionUrl,\n metadata: notification.metadata,\n }),\n });\n\n return {\n success: response.ok,\n responseCode: String(response.status),\n responseMessage: response.statusText,\n };\n } catch (error) {\n return {\n success: false,\n responseMessage:\n error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Channel registry for managing available channels.\n */\nexport class ChannelRegistry {\n private channels = new Map<string, NotificationChannel>();\n\n register(channel: NotificationChannel): void {\n this.channels.set(channel.channelId, channel);\n }\n\n get(channelId: string): NotificationChannel | undefined {\n return this.channels.get(channelId);\n }\n\n getAll(): NotificationChannel[] {\n return Array.from(this.channels.values());\n }\n\n async getAvailable(): Promise<NotificationChannel[]> {\n const available: NotificationChannel[] = [];\n for (const channel of this.channels.values()) {\n if (await channel.isAvailable()) {\n available.push(channel);\n }\n }\n return available;\n }\n}\n\n/**\n * Create a default channel registry with standard channels.\n */\nexport function createChannelRegistry(): ChannelRegistry {\n const registry = new ChannelRegistry();\n registry.register(new InAppChannel());\n registry.register(new ConsoleChannel());\n registry.register(new WebhookChannel());\n return registry;\n}\n"],"mappings":";;;;AAwDA,IAAa,eAAb,MAAyD;CACvD,AAAS,YAAY;CAErB,MAAM,KACJ,eACgC;AAGhC,SAAO;GACL,SAAS;GACT,iBAAiB;GAClB;;CAGH,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAa,iBAAb,MAA2D;CACzD,AAAS,YAAY;CAErB,MAAM,KACJ,cACgC;AAChC,UAAQ,IAAI,OAAO,aAAa,GAAG,IAAI,aAAa,QAAQ;AAC5D,UAAQ,IAAI,MAAM,aAAa,OAAO;AACtC,MAAI,aAAa,UACf,SAAQ,IAAI,cAAc,aAAa,YAAY;AAErD,SAAO;GACL,SAAS;GACT,iBAAiB;GAClB;;CAGH,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAsB,eAAtB,MAAkE;CAChE,AAAS,YAAY;CAMrB,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAsB,cAAtB,MAAiE;CAC/D,AAAS,YAAY;CAMrB,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAa,iBAAb,MAA2D;CACzD,AAAS,YAAY;CAErB,MAAM,KACJ,cACgC;AAChC,MAAI,CAAC,aAAa,SAAS,IACzB,QAAO;GACL,SAAS;GACT,iBAAiB;GAClB;AAGH,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,aAAa,QAAQ,KAAK;IACrD,QAAQ;IACR,SAAS;KACP,gBAAgB;KAChB,GAAG,aAAa,QAAQ;KACzB;IACD,MAAM,KAAK,UAAU;KACnB,IAAI,aAAa;KACjB,OAAO,aAAa;KACpB,MAAM,aAAa;KACnB,WAAW,aAAa;KACxB,UAAU,aAAa;KACxB,CAAC;IACH,CAAC;AAEF,UAAO;IACL,SAAS,SAAS;IAClB,cAAc,OAAO,SAAS,OAAO;IACrC,iBAAiB,SAAS;IAC3B;WACM,OAAO;AACd,UAAO;IACL,SAAS;IACT,iBACE,iBAAiB,QAAQ,MAAM,UAAU;IAC5C;;;CAIL,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAa,kBAAb,MAA6B;CAC3B,AAAQ,2BAAW,IAAI,KAAkC;CAEzD,SAAS,SAAoC;AAC3C,OAAK,SAAS,IAAI,QAAQ,WAAW,QAAQ;;CAG/C,IAAI,WAAoD;AACtD,SAAO,KAAK,SAAS,IAAI,UAAU;;CAGrC,SAAgC;AAC9B,SAAO,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC;;CAG3C,MAAM,eAA+C;EACnD,MAAMA,YAAmC,EAAE;AAC3C,OAAK,MAAM,WAAW,KAAK,SAAS,QAAQ,CAC1C,KAAI,MAAM,QAAQ,aAAa,CAC7B,WAAU,KAAK,QAAQ;AAG3B,SAAO;;;;;;AAOX,SAAgB,wBAAyC;CACvD,MAAM,WAAW,IAAI,iBAAiB;AACtC,UAAS,SAAS,IAAI,cAAc,CAAC;AACrC,UAAS,SAAS,IAAI,gBAAgB,CAAC;AACvC,UAAS,SAAS,IAAI,gBAAgB,CAAC;AACvC,QAAO"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/channels/index.ts"],"sourcesContent":["/**\n * Notification channel interface.\n */\nexport interface NotificationChannel {\n /** Channel identifier */\n readonly channelId: string;\n /** Deliver a notification */\n send(notification: ChannelNotification): Promise<ChannelDeliveryResult>;\n /** Check if channel is available */\n isAvailable(): Promise<boolean>;\n}\n\n/**\n * Notification to deliver via a channel.\n */\nexport interface ChannelNotification {\n id: string;\n userId: string;\n title: string;\n body: string;\n actionUrl?: string;\n imageUrl?: string;\n metadata?: Record<string, unknown>;\n // Channel-specific data\n email?: {\n to: string;\n subject: string;\n html?: string;\n text?: string;\n };\n push?: {\n token: string;\n badge?: number;\n sound?: string;\n data?: Record<string, unknown>;\n };\n webhook?: {\n url: string;\n headers?: Record<string, string>;\n };\n}\n\n/**\n * Result of channel delivery attempt.\n */\nexport interface ChannelDeliveryResult {\n success: boolean;\n externalId?: string;\n responseCode?: string;\n responseMessage?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * In-app notification channel (stores in database).\n */\nexport class InAppChannel implements NotificationChannel {\n readonly channelId = 'IN_APP';\n\n async send(\n _notification: ChannelNotification\n ): Promise<ChannelDeliveryResult> {\n // In-app notifications are stored directly in the database\n // The actual delivery is handled by the notification service\n return {\n success: true,\n responseMessage: 'Stored in database',\n };\n }\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Console channel for development/testing.\n */\nexport class ConsoleChannel implements NotificationChannel {\n readonly channelId = 'CONSOLE';\n\n async send(\n notification: ChannelNotification\n ): Promise<ChannelDeliveryResult> {\n console.log(`📬 [${notification.id}] ${notification.title}`);\n console.log(` ${notification.body}`);\n if (notification.actionUrl) {\n console.log(` Action: ${notification.actionUrl}`);\n }\n return {\n success: true,\n responseMessage: 'Logged to console',\n };\n }\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Email channel interface (to be implemented with provider).\n */\nexport abstract class EmailChannel implements NotificationChannel {\n readonly channelId = 'EMAIL';\n\n abstract send(\n notification: ChannelNotification\n ): Promise<ChannelDeliveryResult>;\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Push notification channel interface (to be implemented with provider).\n */\nexport abstract class PushChannel implements NotificationChannel {\n readonly channelId = 'PUSH';\n\n abstract send(\n notification: ChannelNotification\n ): Promise<ChannelDeliveryResult>;\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Webhook channel for external integrations.\n */\nexport class WebhookChannel implements NotificationChannel {\n readonly channelId = 'WEBHOOK';\n\n async send(\n notification: ChannelNotification\n ): Promise<ChannelDeliveryResult> {\n if (!notification.webhook?.url) {\n return {\n success: false,\n responseMessage: 'No webhook URL configured',\n };\n }\n\n try {\n const response = await fetch(notification.webhook.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...notification.webhook.headers,\n },\n body: JSON.stringify({\n id: notification.id,\n title: notification.title,\n body: notification.body,\n actionUrl: notification.actionUrl,\n metadata: notification.metadata,\n }),\n });\n\n return {\n success: response.ok,\n responseCode: String(response.status),\n responseMessage: response.statusText,\n };\n } catch (error) {\n return {\n success: false,\n responseMessage:\n error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Channel registry for managing available channels.\n */\nexport class ChannelRegistry {\n private channels = new Map<string, NotificationChannel>();\n\n register(channel: NotificationChannel): void {\n this.channels.set(channel.channelId, channel);\n }\n\n get(channelId: string): NotificationChannel | undefined {\n return this.channels.get(channelId);\n }\n\n getAll(): NotificationChannel[] {\n return Array.from(this.channels.values());\n }\n\n async getAvailable(): Promise<NotificationChannel[]> {\n const available: NotificationChannel[] = [];\n for (const channel of this.channels.values()) {\n if (await channel.isAvailable()) {\n available.push(channel);\n }\n }\n return available;\n }\n}\n\n/**\n * Create a default channel registry with standard channels.\n */\nexport function createChannelRegistry(): ChannelRegistry {\n const registry = new ChannelRegistry();\n registry.register(new InAppChannel());\n registry.register(new ConsoleChannel());\n registry.register(new WebhookChannel());\n return registry;\n}\n"],"mappings":";;;;AAwDA,IAAa,eAAb,MAAyD;CACvD,AAAS,YAAY;CAErB,MAAM,KACJ,eACgC;AAGhC,SAAO;GACL,SAAS;GACT,iBAAiB;GAClB;;CAGH,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAa,iBAAb,MAA2D;CACzD,AAAS,YAAY;CAErB,MAAM,KACJ,cACgC;AAChC,UAAQ,IAAI,OAAO,aAAa,GAAG,IAAI,aAAa,QAAQ;AAC5D,UAAQ,IAAI,MAAM,aAAa,OAAO;AACtC,MAAI,aAAa,UACf,SAAQ,IAAI,cAAc,aAAa,YAAY;AAErD,SAAO;GACL,SAAS;GACT,iBAAiB;GAClB;;CAGH,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAsB,eAAtB,MAAkE;CAChE,AAAS,YAAY;CAMrB,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAsB,cAAtB,MAAiE;CAC/D,AAAS,YAAY;CAMrB,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAa,iBAAb,MAA2D;CACzD,AAAS,YAAY;CAErB,MAAM,KACJ,cACgC;AAChC,MAAI,CAAC,aAAa,SAAS,IACzB,QAAO;GACL,SAAS;GACT,iBAAiB;GAClB;AAGH,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,aAAa,QAAQ,KAAK;IACrD,QAAQ;IACR,SAAS;KACP,gBAAgB;KAChB,GAAG,aAAa,QAAQ;KACzB;IACD,MAAM,KAAK,UAAU;KACnB,IAAI,aAAa;KACjB,OAAO,aAAa;KACpB,MAAM,aAAa;KACnB,WAAW,aAAa;KACxB,UAAU,aAAa;KACxB,CAAC;IACH,CAAC;AAEF,UAAO;IACL,SAAS,SAAS;IAClB,cAAc,OAAO,SAAS,OAAO;IACrC,iBAAiB,SAAS;IAC3B;WACM,OAAO;AACd,UAAO;IACL,SAAS;IACT,iBACE,iBAAiB,QAAQ,MAAM,UAAU;IAC5C;;;CAIL,MAAM,cAAgC;AACpC,SAAO;;;;;;AAOX,IAAa,kBAAb,MAA6B;CAC3B,AAAQ,2BAAW,IAAI,KAAkC;CAEzD,SAAS,SAAoC;AAC3C,OAAK,SAAS,IAAI,QAAQ,WAAW,QAAQ;;CAG/C,IAAI,WAAoD;AACtD,SAAO,KAAK,SAAS,IAAI,UAAU;;CAGrC,SAAgC;AAC9B,SAAO,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC;;CAG3C,MAAM,eAA+C;EACnD,MAAM,YAAmC,EAAE;AAC3C,OAAK,MAAM,WAAW,KAAK,SAAS,QAAQ,CAC1C,KAAI,MAAM,QAAQ,aAAa,CAC7B,WAAU,KAAK,QAAQ;AAG3B,SAAO;;;;;;AAOX,SAAgB,wBAAyC;CACvD,MAAM,WAAW,IAAI,iBAAiB;AACtC,UAAS,SAAS,IAAI,cAAc,CAAC;AACrC,UAAS,SAAS,IAAI,gBAAgB,CAAC;AACvC,UAAS,SAAS,IAAI,gBAAgB,CAAC;AACvC,QAAO"}
@@ -1,5 +1,5 @@
1
1
  import * as _contractspec_lib_schema0 from "@contractspec/lib.schema";
2
- import * as _contractspec_lib_contracts0 from "@contractspec/lib.contracts";
2
+ import * as _contractspec_lib_contracts1 from "@contractspec/lib.contracts";
3
3
 
4
4
  //#region src/contracts/index.d.ts
5
5
  declare const NotificationFilterEnum: _contractspec_lib_schema0.EnumType<[string, string, string]>;
@@ -237,7 +237,7 @@ declare const UpdatePreferencesInputModel: _contractspec_lib_schema0.SchemaModel
237
237
  /**
238
238
  * Send a notification.
239
239
  */
240
- declare const SendNotificationContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
240
+ declare const SendNotificationContract: _contractspec_lib_contracts1.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
241
241
  userId: {
242
242
  type: _contractspec_lib_schema0.FieldType<string, string>;
243
243
  isOptional: false;
@@ -368,7 +368,7 @@ declare const SendNotificationContract: _contractspec_lib_contracts0.OperationSp
368
368
  /**
369
369
  * List notifications for current user.
370
370
  */
371
- declare const ListNotificationsContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
371
+ declare const ListNotificationsContract: _contractspec_lib_contracts1.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
372
372
  status: {
373
373
  type: _contractspec_lib_schema0.EnumType<[string, string, string]>;
374
374
  isOptional: true;
@@ -447,7 +447,7 @@ declare const ListNotificationsContract: _contractspec_lib_contracts0.OperationS
447
447
  /**
448
448
  * Mark notification as read.
449
449
  */
450
- declare const MarkNotificationReadContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
450
+ declare const MarkNotificationReadContract: _contractspec_lib_contracts1.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
451
451
  notificationId: {
452
452
  type: _contractspec_lib_schema0.FieldType<string, string>;
453
453
  isOptional: false;
@@ -498,7 +498,7 @@ declare const MarkNotificationReadContract: _contractspec_lib_contracts0.Operati
498
498
  /**
499
499
  * Mark all notifications as read.
500
500
  */
501
- declare const MarkAllNotificationsReadContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema0.AnySchemaModel, _contractspec_lib_schema0.SchemaModel<{
501
+ declare const MarkAllNotificationsReadContract: _contractspec_lib_contracts1.OperationSpec<_contractspec_lib_schema0.AnySchemaModel, _contractspec_lib_schema0.SchemaModel<{
502
502
  markedCount: {
503
503
  type: _contractspec_lib_schema0.FieldType<number, number>;
504
504
  isOptional: false;
@@ -507,7 +507,7 @@ declare const MarkAllNotificationsReadContract: _contractspec_lib_contracts0.Ope
507
507
  /**
508
508
  * Get notification preferences.
509
509
  */
510
- declare const GetNotificationPreferencesContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema0.AnySchemaModel, _contractspec_lib_schema0.SchemaModel<{
510
+ declare const GetNotificationPreferencesContract: _contractspec_lib_contracts1.OperationSpec<_contractspec_lib_schema0.AnySchemaModel, _contractspec_lib_schema0.SchemaModel<{
511
511
  userId: {
512
512
  type: _contractspec_lib_schema0.FieldType<string, string>;
513
513
  isOptional: false;
@@ -548,7 +548,7 @@ declare const GetNotificationPreferencesContract: _contractspec_lib_contracts0.O
548
548
  /**
549
549
  * Update notification preferences.
550
550
  */
551
- declare const UpdateNotificationPreferencesContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
551
+ declare const UpdateNotificationPreferencesContract: _contractspec_lib_contracts1.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
552
552
  globalEnabled: {
553
553
  type: _contractspec_lib_schema0.FieldType<boolean, boolean>;
554
554
  isOptional: true;
@@ -622,7 +622,7 @@ declare const UpdateNotificationPreferencesContract: _contractspec_lib_contracts
622
622
  /**
623
623
  * Delete a notification.
624
624
  */
625
- declare const DeleteNotificationContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
625
+ declare const DeleteNotificationContract: _contractspec_lib_contracts1.OperationSpec<_contractspec_lib_schema0.SchemaModel<{
626
626
  notificationId: {
627
627
  type: _contractspec_lib_schema0.FieldType<string, string>;
628
628
  isOptional: false;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["notificationsSchemaContribution: ModuleSchemaContribution"],"sources":["../../src/entities/index.ts"],"sourcesContent":["import {\n defineEntity,\n defineEntityEnum,\n field,\n index,\n} from '@contractspec/lib.schema';\nimport type { ModuleSchemaContribution } from '@contractspec/lib.schema';\n\n/**\n * Notification status enum.\n */\nexport const NotificationStatusEnum = defineEntityEnum({\n name: 'NotificationStatus',\n values: [\n 'PENDING',\n 'SENT',\n 'DELIVERED',\n 'READ',\n 'FAILED',\n 'CANCELLED',\n ] as const,\n schema: 'lssm_notifications',\n description: 'Status of a notification.',\n});\n\n/**\n * Notification channel enum.\n */\nexport const NotificationChannelEnum = defineEntityEnum({\n name: 'NotificationChannel',\n values: ['EMAIL', 'IN_APP', 'PUSH', 'WEBHOOK', 'SMS'] as const,\n schema: 'lssm_notifications',\n description: 'Delivery channel for notifications.',\n});\n\n/**\n * Notification entity - individual notification instance.\n */\nexport const NotificationEntity = defineEntity({\n name: 'Notification',\n description: 'An individual notification to be delivered to a user.',\n schema: 'lssm_notifications',\n map: 'notification',\n fields: {\n id: field.id({ description: 'Unique notification ID' }),\n\n // Recipient\n userId: field.foreignKey({ description: 'Target user ID' }),\n orgId: field.string({\n isOptional: true,\n description: 'Organization context',\n }),\n\n // Content\n templateId: field.string({\n isOptional: true,\n description: 'Template used',\n }),\n title: field.string({ description: 'Notification title' }),\n body: field.string({ description: 'Notification body' }),\n actionUrl: field.string({ isOptional: true, description: 'Action URL' }),\n imageUrl: field.string({ isOptional: true, description: 'Image URL' }),\n\n // Categorization\n type: field.string({\n description: 'Notification type (e.g., mention, update)',\n }),\n category: field.string({\n isOptional: true,\n description: 'Notification category',\n }),\n priority: field.enum('NotificationPriority', { default: 'NORMAL' }),\n\n // Delivery\n channels: field.string({\n isArray: true,\n description: 'Target delivery channels',\n }),\n status: field.enum('NotificationStatus', { default: 'PENDING' }),\n\n // Tracking\n sentAt: field.dateTime({ isOptional: true }),\n deliveredAt: field.dateTime({ isOptional: true }),\n readAt: field.dateTime({ isOptional: true }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional metadata',\n }),\n variables: field.json({\n isOptional: true,\n description: 'Template variables used',\n }),\n\n // Source\n triggeredBy: field.string({\n isOptional: true,\n description: 'Event/action that triggered',\n }),\n sourceId: field.string({\n isOptional: true,\n description: 'Source entity ID',\n }),\n sourceType: field.string({\n isOptional: true,\n description: 'Source entity type',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n expiresAt: field.dateTime({\n isOptional: true,\n description: 'Notification expiry',\n }),\n\n // Relations\n deliveryLogs: field.hasMany('DeliveryLog'),\n },\n indexes: [\n index.on(['userId', 'status', 'createdAt']),\n index.on(['userId', 'readAt']),\n index.on(['orgId', 'createdAt']),\n index.on(['type', 'createdAt']),\n ],\n enums: [NotificationStatusEnum, NotificationChannelEnum],\n});\n\n/**\n * Notification priority enum.\n */\nexport const NotificationPriorityEnum = defineEntityEnum({\n name: 'NotificationPriority',\n values: ['LOW', 'NORMAL', 'HIGH', 'URGENT'] as const,\n schema: 'lssm_notifications',\n description: 'Priority level of a notification.',\n});\n\n/**\n * NotificationTemplate entity - reusable notification templates.\n */\nexport const NotificationTemplateEntity = defineEntity({\n name: 'NotificationTemplate',\n description: 'Reusable notification template.',\n schema: 'lssm_notifications',\n map: 'notification_template',\n fields: {\n id: field.id(),\n templateId: field.string({\n isUnique: true,\n description: 'Template identifier',\n }),\n name: field.string({ description: 'Template display name' }),\n description: field.string({ isOptional: true }),\n\n // Content by channel\n emailSubject: field.string({ isOptional: true }),\n emailBody: field.string({ isOptional: true }),\n inAppTitle: field.string({ isOptional: true }),\n inAppBody: field.string({ isOptional: true }),\n pushTitle: field.string({ isOptional: true }),\n pushBody: field.string({ isOptional: true }),\n\n // Settings\n defaultChannels: field.string({ isArray: true }),\n category: field.string({ isOptional: true }),\n priority: field.enum('NotificationPriority', { default: 'NORMAL' }),\n\n // Variables schema\n variablesSchema: field.json({\n isOptional: true,\n description: 'JSON schema for variables',\n }),\n\n // State\n enabled: field.boolean({ default: true }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n },\n enums: [NotificationPriorityEnum],\n});\n\n/**\n * NotificationPreference entity - user notification preferences.\n */\nexport const NotificationPreferenceEntity = defineEntity({\n name: 'NotificationPreference',\n description: 'User notification preferences by type and channel.',\n schema: 'lssm_notifications',\n map: 'notification_preference',\n fields: {\n id: field.id(),\n userId: field.foreignKey(),\n\n // Global settings\n globalEnabled: field.boolean({ default: true }),\n quietHoursStart: field.string({\n isOptional: true,\n description: 'Quiet hours start (HH:MM)',\n }),\n quietHoursEnd: field.string({\n isOptional: true,\n description: 'Quiet hours end (HH:MM)',\n }),\n timezone: field.string({ default: '\"UTC\"' }),\n\n // Channel preferences (JSON object: { email: true, push: false, ... })\n channelPreferences: field.json({\n description: 'Channel-level preferences',\n }),\n\n // Type preferences (JSON object: { mention: true, update: false, ... })\n typePreferences: field.json({ description: 'Type-level preferences' }),\n\n // Digest settings\n digestEnabled: field.boolean({ default: false }),\n digestFrequency: field.string({\n isOptional: true,\n description: 'daily, weekly, etc.',\n }),\n digestTime: field.string({\n isOptional: true,\n description: 'Digest send time (HH:MM)',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n },\n indexes: [index.unique(['userId'])],\n});\n\n/**\n * DeliveryLog entity - track delivery attempts per channel.\n */\nexport const DeliveryLogEntity = defineEntity({\n name: 'DeliveryLog',\n description: 'Log of notification delivery attempts.',\n schema: 'lssm_notifications',\n map: 'delivery_log',\n fields: {\n id: field.id(),\n notificationId: field.foreignKey(),\n\n // Delivery info\n channel: field.enum('NotificationChannel'),\n status: field.enum('NotificationStatus'),\n\n // Timing\n attemptedAt: field.dateTime(),\n deliveredAt: field.dateTime({ isOptional: true }),\n\n // Response\n responseCode: field.string({ isOptional: true }),\n responseMessage: field.string({ isOptional: true }),\n\n // External IDs\n externalId: field.string({\n isOptional: true,\n description: 'Provider message ID',\n }),\n\n // Metadata\n metadata: field.json({ isOptional: true }),\n\n // Relations\n notification: field.belongsTo('Notification', ['notificationId'], ['id'], {\n onDelete: 'Cascade',\n }),\n },\n indexes: [index.on(['notificationId', 'channel'])],\n});\n\n/**\n * All notification entities for schema composition.\n */\nexport const notificationEntities = [\n NotificationEntity,\n NotificationTemplateEntity,\n NotificationPreferenceEntity,\n DeliveryLogEntity,\n];\n\n/**\n * Module schema contribution for notifications.\n */\nexport const notificationsSchemaContribution: ModuleSchemaContribution = {\n moduleId: '@contractspec/module.notifications',\n entities: notificationEntities,\n enums: [\n NotificationStatusEnum,\n NotificationChannelEnum,\n NotificationPriorityEnum,\n ],\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/entities/index.ts"],"sourcesContent":["import {\n defineEntity,\n defineEntityEnum,\n field,\n index,\n} from '@contractspec/lib.schema';\nimport type { ModuleSchemaContribution } from '@contractspec/lib.schema';\n\n/**\n * Notification status enum.\n */\nexport const NotificationStatusEnum = defineEntityEnum({\n name: 'NotificationStatus',\n values: [\n 'PENDING',\n 'SENT',\n 'DELIVERED',\n 'READ',\n 'FAILED',\n 'CANCELLED',\n ] as const,\n schema: 'lssm_notifications',\n description: 'Status of a notification.',\n});\n\n/**\n * Notification channel enum.\n */\nexport const NotificationChannelEnum = defineEntityEnum({\n name: 'NotificationChannel',\n values: ['EMAIL', 'IN_APP', 'PUSH', 'WEBHOOK', 'SMS'] as const,\n schema: 'lssm_notifications',\n description: 'Delivery channel for notifications.',\n});\n\n/**\n * Notification entity - individual notification instance.\n */\nexport const NotificationEntity = defineEntity({\n name: 'Notification',\n description: 'An individual notification to be delivered to a user.',\n schema: 'lssm_notifications',\n map: 'notification',\n fields: {\n id: field.id({ description: 'Unique notification ID' }),\n\n // Recipient\n userId: field.foreignKey({ description: 'Target user ID' }),\n orgId: field.string({\n isOptional: true,\n description: 'Organization context',\n }),\n\n // Content\n templateId: field.string({\n isOptional: true,\n description: 'Template used',\n }),\n title: field.string({ description: 'Notification title' }),\n body: field.string({ description: 'Notification body' }),\n actionUrl: field.string({ isOptional: true, description: 'Action URL' }),\n imageUrl: field.string({ isOptional: true, description: 'Image URL' }),\n\n // Categorization\n type: field.string({\n description: 'Notification type (e.g., mention, update)',\n }),\n category: field.string({\n isOptional: true,\n description: 'Notification category',\n }),\n priority: field.enum('NotificationPriority', { default: 'NORMAL' }),\n\n // Delivery\n channels: field.string({\n isArray: true,\n description: 'Target delivery channels',\n }),\n status: field.enum('NotificationStatus', { default: 'PENDING' }),\n\n // Tracking\n sentAt: field.dateTime({ isOptional: true }),\n deliveredAt: field.dateTime({ isOptional: true }),\n readAt: field.dateTime({ isOptional: true }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional metadata',\n }),\n variables: field.json({\n isOptional: true,\n description: 'Template variables used',\n }),\n\n // Source\n triggeredBy: field.string({\n isOptional: true,\n description: 'Event/action that triggered',\n }),\n sourceId: field.string({\n isOptional: true,\n description: 'Source entity ID',\n }),\n sourceType: field.string({\n isOptional: true,\n description: 'Source entity type',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n expiresAt: field.dateTime({\n isOptional: true,\n description: 'Notification expiry',\n }),\n\n // Relations\n deliveryLogs: field.hasMany('DeliveryLog'),\n },\n indexes: [\n index.on(['userId', 'status', 'createdAt']),\n index.on(['userId', 'readAt']),\n index.on(['orgId', 'createdAt']),\n index.on(['type', 'createdAt']),\n ],\n enums: [NotificationStatusEnum, NotificationChannelEnum],\n});\n\n/**\n * Notification priority enum.\n */\nexport const NotificationPriorityEnum = defineEntityEnum({\n name: 'NotificationPriority',\n values: ['LOW', 'NORMAL', 'HIGH', 'URGENT'] as const,\n schema: 'lssm_notifications',\n description: 'Priority level of a notification.',\n});\n\n/**\n * NotificationTemplate entity - reusable notification templates.\n */\nexport const NotificationTemplateEntity = defineEntity({\n name: 'NotificationTemplate',\n description: 'Reusable notification template.',\n schema: 'lssm_notifications',\n map: 'notification_template',\n fields: {\n id: field.id(),\n templateId: field.string({\n isUnique: true,\n description: 'Template identifier',\n }),\n name: field.string({ description: 'Template display name' }),\n description: field.string({ isOptional: true }),\n\n // Content by channel\n emailSubject: field.string({ isOptional: true }),\n emailBody: field.string({ isOptional: true }),\n inAppTitle: field.string({ isOptional: true }),\n inAppBody: field.string({ isOptional: true }),\n pushTitle: field.string({ isOptional: true }),\n pushBody: field.string({ isOptional: true }),\n\n // Settings\n defaultChannels: field.string({ isArray: true }),\n category: field.string({ isOptional: true }),\n priority: field.enum('NotificationPriority', { default: 'NORMAL' }),\n\n // Variables schema\n variablesSchema: field.json({\n isOptional: true,\n description: 'JSON schema for variables',\n }),\n\n // State\n enabled: field.boolean({ default: true }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n },\n enums: [NotificationPriorityEnum],\n});\n\n/**\n * NotificationPreference entity - user notification preferences.\n */\nexport const NotificationPreferenceEntity = defineEntity({\n name: 'NotificationPreference',\n description: 'User notification preferences by type and channel.',\n schema: 'lssm_notifications',\n map: 'notification_preference',\n fields: {\n id: field.id(),\n userId: field.foreignKey(),\n\n // Global settings\n globalEnabled: field.boolean({ default: true }),\n quietHoursStart: field.string({\n isOptional: true,\n description: 'Quiet hours start (HH:MM)',\n }),\n quietHoursEnd: field.string({\n isOptional: true,\n description: 'Quiet hours end (HH:MM)',\n }),\n timezone: field.string({ default: '\"UTC\"' }),\n\n // Channel preferences (JSON object: { email: true, push: false, ... })\n channelPreferences: field.json({\n description: 'Channel-level preferences',\n }),\n\n // Type preferences (JSON object: { mention: true, update: false, ... })\n typePreferences: field.json({ description: 'Type-level preferences' }),\n\n // Digest settings\n digestEnabled: field.boolean({ default: false }),\n digestFrequency: field.string({\n isOptional: true,\n description: 'daily, weekly, etc.',\n }),\n digestTime: field.string({\n isOptional: true,\n description: 'Digest send time (HH:MM)',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n },\n indexes: [index.unique(['userId'])],\n});\n\n/**\n * DeliveryLog entity - track delivery attempts per channel.\n */\nexport const DeliveryLogEntity = defineEntity({\n name: 'DeliveryLog',\n description: 'Log of notification delivery attempts.',\n schema: 'lssm_notifications',\n map: 'delivery_log',\n fields: {\n id: field.id(),\n notificationId: field.foreignKey(),\n\n // Delivery info\n channel: field.enum('NotificationChannel'),\n status: field.enum('NotificationStatus'),\n\n // Timing\n attemptedAt: field.dateTime(),\n deliveredAt: field.dateTime({ isOptional: true }),\n\n // Response\n responseCode: field.string({ isOptional: true }),\n responseMessage: field.string({ isOptional: true }),\n\n // External IDs\n externalId: field.string({\n isOptional: true,\n description: 'Provider message ID',\n }),\n\n // Metadata\n metadata: field.json({ isOptional: true }),\n\n // Relations\n notification: field.belongsTo('Notification', ['notificationId'], ['id'], {\n onDelete: 'Cascade',\n }),\n },\n indexes: [index.on(['notificationId', 'channel'])],\n});\n\n/**\n * All notification entities for schema composition.\n */\nexport const notificationEntities = [\n NotificationEntity,\n NotificationTemplateEntity,\n NotificationPreferenceEntity,\n DeliveryLogEntity,\n];\n\n/**\n * Module schema contribution for notifications.\n */\nexport const notificationsSchemaContribution: ModuleSchemaContribution = {\n moduleId: '@contractspec/module.notifications',\n entities: notificationEntities,\n enums: [\n NotificationStatusEnum,\n NotificationChannelEnum,\n NotificationPriorityEnum,\n ],\n};\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import * as _contractspec_lib_contracts0 from "@contractspec/lib.contracts";
2
+
3
+ //#region src/notifications.capability.d.ts
4
+ declare const NotificationsCapability: _contractspec_lib_contracts0.CapabilitySpec;
5
+ //#endregion
6
+ export { NotificationsCapability };
7
+ //# sourceMappingURL=notifications.capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.capability.d.ts","names":[],"sources":["../src/notifications.capability.ts"],"sourcesContent":[],"mappings":";;;cAEa,yBAUX,4BAAA,CAVkC"}
@@ -0,0 +1,20 @@
1
+ import { StabilityEnum, defineCapability } from "@contractspec/lib.contracts";
2
+
3
+ //#region src/notifications.capability.ts
4
+ const NotificationsCapability = defineCapability({ meta: {
5
+ key: "notifications",
6
+ version: "1.0.0",
7
+ kind: "ui",
8
+ stability: StabilityEnum.Experimental,
9
+ description: "User notifications and alerts",
10
+ owners: ["@platform.messaging"],
11
+ tags: [
12
+ "notifications",
13
+ "messaging",
14
+ "alerts"
15
+ ]
16
+ } });
17
+
18
+ //#endregion
19
+ export { NotificationsCapability };
20
+ //# sourceMappingURL=notifications.capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.capability.js","names":[],"sources":["../src/notifications.capability.ts"],"sourcesContent":["import { defineCapability, StabilityEnum } from '@contractspec/lib.contracts';\n\nexport const NotificationsCapability = defineCapability({\n meta: {\n key: 'notifications',\n version: '1.0.0',\n kind: 'ui',\n stability: StabilityEnum.Experimental,\n description: 'User notifications and alerts',\n owners: ['@platform.messaging'],\n tags: ['notifications', 'messaging', 'alerts'],\n },\n});\n"],"mappings":";;;AAEA,MAAa,0BAA0B,iBAAiB,EACtD,MAAM;CACJ,KAAK;CACL,SAAS;CACT,MAAM;CACN,WAAW,cAAc;CACzB,aAAa;CACb,QAAQ,CAAC,sBAAsB;CAC/B,MAAM;EAAC;EAAiB;EAAa;EAAS;CAC/C,EACF,CAAC"}
@@ -1,4 +1,4 @@
1
- import { FeatureModuleSpec } from "@contractspec/lib.contracts";
1
+ import * as _contractspec_lib_contracts0 from "@contractspec/lib.contracts";
2
2
 
3
3
  //#region src/notifications.feature.d.ts
4
4
 
@@ -6,7 +6,7 @@ import { FeatureModuleSpec } from "@contractspec/lib.contracts";
6
6
  * Notifications feature module that bundles notification sending,
7
7
  * listing, marking as read, and preference management capabilities.
8
8
  */
9
- declare const NotificationsFeature: FeatureModuleSpec;
9
+ declare const NotificationsFeature: _contractspec_lib_contracts0.FeatureModuleSpec;
10
10
  //#endregion
11
11
  export { NotificationsFeature };
12
12
  //# sourceMappingURL=notifications.feature.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"notifications.feature.d.ts","names":[],"sources":["../src/notifications.feature.ts"],"sourcesContent":[],"mappings":";;;;;;;;cAWa,sBAAsB"}
1
+ {"version":3,"file":"notifications.feature.d.ts","names":[],"sources":["../src/notifications.feature.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;cAAa,sBAqCX,4BAAA,CArC+B"}
@@ -1,9 +1,16 @@
1
+ import { defineFeature } from "@contractspec/lib.contracts";
2
+
1
3
  //#region src/notifications.feature.ts
2
4
  /**
5
+ * Notifications Feature Module Specification
6
+ *
7
+ * Defines the feature module for notification management.
8
+ */
9
+ /**
3
10
  * Notifications feature module that bundles notification sending,
4
11
  * listing, marking as read, and preference management capabilities.
5
12
  */
6
- const NotificationsFeature = {
13
+ const NotificationsFeature = defineFeature({
7
14
  meta: {
8
15
  key: "notifications",
9
16
  title: "Notifications",
@@ -63,7 +70,7 @@ const NotificationsFeature = {
63
70
  version: "1.0.0"
64
71
  }]
65
72
  }
66
- };
73
+ });
67
74
 
68
75
  //#endregion
69
76
  export { NotificationsFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"notifications.feature.js","names":["NotificationsFeature: FeatureModuleSpec"],"sources":["../src/notifications.feature.ts"],"sourcesContent":["/**\n * Notifications Feature Module Specification\n *\n * Defines the feature module for notification management.\n */\nimport type { FeatureModuleSpec } from '@contractspec/lib.contracts';\n\n/**\n * Notifications feature module that bundles notification sending,\n * listing, marking as read, and preference management capabilities.\n */\nexport const NotificationsFeature: FeatureModuleSpec = {\n meta: {\n key: 'notifications',\n title: 'Notifications',\n description:\n 'Multi-channel notification delivery with preference management',\n domain: 'platform',\n version: '1.0.0',\n owners: ['@platform.notifications'],\n tags: ['notifications', 'email', 'push', 'in-app'],\n stability: 'stable',\n },\n\n // All contract operations included in this feature\n operations: [\n { key: 'notifications.send', version: '1.0.0' },\n { key: 'notifications.markRead', version: '1.0.0' },\n { key: 'notifications.markAllRead', version: '1.0.0' },\n { key: 'notifications.delete', version: '1.0.0' },\n { key: 'notifications.list', version: '1.0.0' },\n { key: 'notifications.preferences.update', version: '1.0.0' },\n { key: 'notifications.preferences.get', version: '1.0.0' },\n ],\n\n // No events for this feature - it consumes events to send notifications\n events: [],\n\n // No presentations for this module feature\n presentations: [],\n opToPresentation: [],\n presentationsTargets: [],\n\n // Capability definitions\n capabilities: {\n provides: [{ key: 'notifications', version: '1.0.0' }],\n requires: [{ key: 'identity', version: '1.0.0' }],\n },\n};\n"],"mappings":";;;;;AAWA,MAAaA,uBAA0C;CACrD,MAAM;EACJ,KAAK;EACL,OAAO;EACP,aACE;EACF,QAAQ;EACR,SAAS;EACT,QAAQ,CAAC,0BAA0B;EACnC,MAAM;GAAC;GAAiB;GAAS;GAAQ;GAAS;EAClD,WAAW;EACZ;CAGD,YAAY;EACV;GAAE,KAAK;GAAsB,SAAS;GAAS;EAC/C;GAAE,KAAK;GAA0B,SAAS;GAAS;EACnD;GAAE,KAAK;GAA6B,SAAS;GAAS;EACtD;GAAE,KAAK;GAAwB,SAAS;GAAS;EACjD;GAAE,KAAK;GAAsB,SAAS;GAAS;EAC/C;GAAE,KAAK;GAAoC,SAAS;GAAS;EAC7D;GAAE,KAAK;GAAiC,SAAS;GAAS;EAC3D;CAGD,QAAQ,EAAE;CAGV,eAAe,EAAE;CACjB,kBAAkB,EAAE;CACpB,sBAAsB,EAAE;CAGxB,cAAc;EACZ,UAAU,CAAC;GAAE,KAAK;GAAiB,SAAS;GAAS,CAAC;EACtD,UAAU,CAAC;GAAE,KAAK;GAAY,SAAS;GAAS,CAAC;EAClD;CACF"}
1
+ {"version":3,"file":"notifications.feature.js","names":[],"sources":["../src/notifications.feature.ts"],"sourcesContent":["/**\n * Notifications Feature Module Specification\n *\n * Defines the feature module for notification management.\n */\nimport { defineFeature } from '@contractspec/lib.contracts';\n\n/**\n * Notifications feature module that bundles notification sending,\n * listing, marking as read, and preference management capabilities.\n */\nexport const NotificationsFeature = defineFeature({\n meta: {\n key: 'notifications',\n title: 'Notifications',\n description:\n 'Multi-channel notification delivery with preference management',\n domain: 'platform',\n version: '1.0.0',\n owners: ['@platform.notifications'],\n tags: ['notifications', 'email', 'push', 'in-app'],\n stability: 'stable',\n },\n\n // All contract operations included in this feature\n operations: [\n { key: 'notifications.send', version: '1.0.0' },\n { key: 'notifications.markRead', version: '1.0.0' },\n { key: 'notifications.markAllRead', version: '1.0.0' },\n { key: 'notifications.delete', version: '1.0.0' },\n { key: 'notifications.list', version: '1.0.0' },\n { key: 'notifications.preferences.update', version: '1.0.0' },\n { key: 'notifications.preferences.get', version: '1.0.0' },\n ],\n\n // No events for this feature - it consumes events to send notifications\n events: [],\n\n // No presentations for this module feature\n presentations: [],\n opToPresentation: [],\n presentationsTargets: [],\n\n // Capability definitions\n capabilities: {\n provides: [{ key: 'notifications', version: '1.0.0' }],\n requires: [{ key: 'identity', version: '1.0.0' }],\n },\n});\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,uBAAuB,cAAc;CAChD,MAAM;EACJ,KAAK;EACL,OAAO;EACP,aACE;EACF,QAAQ;EACR,SAAS;EACT,QAAQ,CAAC,0BAA0B;EACnC,MAAM;GAAC;GAAiB;GAAS;GAAQ;GAAS;EAClD,WAAW;EACZ;CAGD,YAAY;EACV;GAAE,KAAK;GAAsB,SAAS;GAAS;EAC/C;GAAE,KAAK;GAA0B,SAAS;GAAS;EACnD;GAAE,KAAK;GAA6B,SAAS;GAAS;EACtD;GAAE,KAAK;GAAwB,SAAS;GAAS;EACjD;GAAE,KAAK;GAAsB,SAAS;GAAS;EAC/C;GAAE,KAAK;GAAoC,SAAS;GAAS;EAC7D;GAAE,KAAK;GAAiC,SAAS;GAAS;EAC3D;CAGD,QAAQ,EAAE;CAGV,eAAe,EAAE;CACjB,kBAAkB,EAAE;CACpB,sBAAsB,EAAE;CAGxB,cAAc;EACZ,UAAU,CAAC;GAAE,KAAK;GAAiB,SAAS;GAAS,CAAC;EACtD,UAAU,CAAC;GAAE,KAAK;GAAY,SAAS;GAAS,CAAC;EAClD;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["result: RenderedNotification"],"sources":["../../src/templates/index.ts"],"sourcesContent":["/**\n * Template variable definition.\n */\nexport interface TemplateVariable {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'date' | 'url';\n required?: boolean;\n default?: string | number | boolean;\n description?: string;\n}\n\n/**\n * Channel-specific template content.\n */\nexport interface ChannelTemplateContent {\n title?: string;\n subject?: string;\n body: string;\n actionUrl?: string;\n actionText?: string;\n}\n\n/**\n * Notification template definition.\n */\nexport interface NotificationTemplateDefinition {\n id: string;\n name: string;\n description?: string;\n category?: string;\n variables?: TemplateVariable[];\n defaultChannels?: string[];\n channels: {\n email?: ChannelTemplateContent;\n inApp?: ChannelTemplateContent;\n push?: ChannelTemplateContent;\n webhook?: ChannelTemplateContent;\n };\n}\n\n/**\n * Rendered notification content.\n */\nexport interface RenderedNotification {\n title: string;\n body: string;\n actionUrl?: string;\n email?: {\n subject: string;\n html: string;\n text: string;\n };\n}\n\n/**\n * Define a notification template.\n */\nexport function defineTemplate(\n def: NotificationTemplateDefinition\n): NotificationTemplateDefinition {\n return def;\n}\n\n/**\n * Render a template with variables.\n */\nexport function renderTemplate(\n content: string,\n variables: Record<string, unknown>\n): string {\n return content.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key) => {\n const value = variables[key];\n if (value === undefined || value === null) {\n return match; // Keep placeholder if no value\n }\n return String(value);\n });\n}\n\n/**\n * Render a notification template for a specific channel.\n */\nexport function renderNotificationTemplate(\n template: NotificationTemplateDefinition,\n channel: keyof NotificationTemplateDefinition['channels'],\n variables: Record<string, unknown>\n): RenderedNotification | null {\n const channelContent = template.channels[channel];\n if (!channelContent) {\n return null;\n }\n\n const title = channelContent.title\n ? renderTemplate(channelContent.title, variables)\n : template.name;\n\n const body = renderTemplate(channelContent.body, variables);\n\n const actionUrl = channelContent.actionUrl\n ? renderTemplate(channelContent.actionUrl, variables)\n : undefined;\n\n const result: RenderedNotification = {\n title,\n body,\n actionUrl,\n };\n\n // Add email-specific rendering\n if (channel === 'email' && channelContent.subject) {\n result.email = {\n subject: renderTemplate(channelContent.subject, variables),\n html: body,\n text: stripHtml(body),\n };\n }\n\n return result;\n}\n\n/**\n * Strip HTML tags from content (for plain text).\n */\nfunction stripHtml(html: string): string {\n return html\n .replace(/<[^>]*>/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/**\n * Template registry for managing templates.\n */\nexport class TemplateRegistry {\n private templates = new Map<string, NotificationTemplateDefinition>();\n\n register(template: NotificationTemplateDefinition): void {\n this.templates.set(template.id, template);\n }\n\n get(templateId: string): NotificationTemplateDefinition | undefined {\n return this.templates.get(templateId);\n }\n\n getAll(): NotificationTemplateDefinition[] {\n return Array.from(this.templates.values());\n }\n\n getByCategory(category: string): NotificationTemplateDefinition[] {\n return this.getAll().filter((t) => t.category === category);\n }\n}\n\n/**\n * Create a template registry.\n */\nexport function createTemplateRegistry(): TemplateRegistry {\n return new TemplateRegistry();\n}\n\n// ============ Standard Templates ============\n\n/**\n * Welcome email template.\n */\nexport const WelcomeTemplate = defineTemplate({\n id: 'welcome',\n name: 'Welcome',\n description: 'Sent when a user signs up.',\n category: 'onboarding',\n variables: [\n { name: 'name', type: 'string', required: true },\n { name: 'appName', type: 'string', default: 'ContractSpec' },\n { name: 'actionUrl', type: 'url' },\n ],\n defaultChannels: ['EMAIL', 'IN_APP'],\n channels: {\n email: {\n subject: 'Welcome to {{appName}}, {{name}}!',\n body: `\n <h1>Welcome, {{name}}!</h1>\n <p>Thanks for joining {{appName}}. We're excited to have you on board.</p>\n <p><a href=\"{{actionUrl}}\">Get started now</a></p>\n `,\n },\n inApp: {\n title: 'Welcome to {{appName}}!',\n body: 'Thanks for joining. Click to complete your profile.',\n actionUrl: '{{actionUrl}}',\n },\n },\n});\n\n/**\n * Organization invite template.\n */\nexport const OrgInviteTemplate = defineTemplate({\n id: 'org-invite',\n name: 'Organization Invitation',\n description: 'Sent when a user is invited to an organization.',\n category: 'organization',\n variables: [\n { name: 'inviterName', type: 'string', required: true },\n { name: 'orgName', type: 'string', required: true },\n { name: 'role', type: 'string', default: 'member' },\n { name: 'actionUrl', type: 'url', required: true },\n ],\n defaultChannels: ['EMAIL'],\n channels: {\n email: {\n subject: '{{inviterName}} invited you to join {{orgName}}',\n body: `\n <h1>You've been invited!</h1>\n <p>{{inviterName}} has invited you to join <strong>{{orgName}}</strong> as a {{role}}.</p>\n <p><a href=\"{{actionUrl}}\">Accept invitation</a></p>\n `,\n },\n inApp: {\n title: 'Invitation to {{orgName}}',\n body: '{{inviterName}} invited you to join as {{role}}.',\n actionUrl: '{{actionUrl}}',\n actionText: 'Accept',\n },\n },\n});\n\n/**\n * Mention template.\n */\nexport const MentionTemplate = defineTemplate({\n id: 'mention',\n name: 'Mention',\n description: 'Sent when a user is mentioned.',\n category: 'social',\n variables: [\n { name: 'mentionerName', type: 'string', required: true },\n { name: 'context', type: 'string', required: true },\n { name: 'preview', type: 'string' },\n { name: 'actionUrl', type: 'url', required: true },\n ],\n defaultChannels: ['IN_APP', 'PUSH'],\n channels: {\n inApp: {\n title: '{{mentionerName}} mentioned you',\n body: 'In {{context}}: \"{{preview}}\"',\n actionUrl: '{{actionUrl}}',\n },\n push: {\n title: '{{mentionerName}} mentioned you',\n body: '{{preview}}',\n },\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/templates/index.ts"],"sourcesContent":["/**\n * Template variable definition.\n */\nexport interface TemplateVariable {\n name: string;\n type: 'string' | 'number' | 'boolean' | 'date' | 'url';\n required?: boolean;\n default?: string | number | boolean;\n description?: string;\n}\n\n/**\n * Channel-specific template content.\n */\nexport interface ChannelTemplateContent {\n title?: string;\n subject?: string;\n body: string;\n actionUrl?: string;\n actionText?: string;\n}\n\n/**\n * Notification template definition.\n */\nexport interface NotificationTemplateDefinition {\n id: string;\n name: string;\n description?: string;\n category?: string;\n variables?: TemplateVariable[];\n defaultChannels?: string[];\n channels: {\n email?: ChannelTemplateContent;\n inApp?: ChannelTemplateContent;\n push?: ChannelTemplateContent;\n webhook?: ChannelTemplateContent;\n };\n}\n\n/**\n * Rendered notification content.\n */\nexport interface RenderedNotification {\n title: string;\n body: string;\n actionUrl?: string;\n email?: {\n subject: string;\n html: string;\n text: string;\n };\n}\n\n/**\n * Define a notification template.\n */\nexport function defineTemplate(\n def: NotificationTemplateDefinition\n): NotificationTemplateDefinition {\n return def;\n}\n\n/**\n * Render a template with variables.\n */\nexport function renderTemplate(\n content: string,\n variables: Record<string, unknown>\n): string {\n return content.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key) => {\n const value = variables[key];\n if (value === undefined || value === null) {\n return match; // Keep placeholder if no value\n }\n return String(value);\n });\n}\n\n/**\n * Render a notification template for a specific channel.\n */\nexport function renderNotificationTemplate(\n template: NotificationTemplateDefinition,\n channel: keyof NotificationTemplateDefinition['channels'],\n variables: Record<string, unknown>\n): RenderedNotification | null {\n const channelContent = template.channels[channel];\n if (!channelContent) {\n return null;\n }\n\n const title = channelContent.title\n ? renderTemplate(channelContent.title, variables)\n : template.name;\n\n const body = renderTemplate(channelContent.body, variables);\n\n const actionUrl = channelContent.actionUrl\n ? renderTemplate(channelContent.actionUrl, variables)\n : undefined;\n\n const result: RenderedNotification = {\n title,\n body,\n actionUrl,\n };\n\n // Add email-specific rendering\n if (channel === 'email' && channelContent.subject) {\n result.email = {\n subject: renderTemplate(channelContent.subject, variables),\n html: body,\n text: stripHtml(body),\n };\n }\n\n return result;\n}\n\n/**\n * Strip HTML tags from content (for plain text).\n */\nfunction stripHtml(html: string): string {\n return html\n .replace(/<[^>]*>/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/**\n * Template registry for managing templates.\n */\nexport class TemplateRegistry {\n private templates = new Map<string, NotificationTemplateDefinition>();\n\n register(template: NotificationTemplateDefinition): void {\n this.templates.set(template.id, template);\n }\n\n get(templateId: string): NotificationTemplateDefinition | undefined {\n return this.templates.get(templateId);\n }\n\n getAll(): NotificationTemplateDefinition[] {\n return Array.from(this.templates.values());\n }\n\n getByCategory(category: string): NotificationTemplateDefinition[] {\n return this.getAll().filter((t) => t.category === category);\n }\n}\n\n/**\n * Create a template registry.\n */\nexport function createTemplateRegistry(): TemplateRegistry {\n return new TemplateRegistry();\n}\n\n// ============ Standard Templates ============\n\n/**\n * Welcome email template.\n */\nexport const WelcomeTemplate = defineTemplate({\n id: 'welcome',\n name: 'Welcome',\n description: 'Sent when a user signs up.',\n category: 'onboarding',\n variables: [\n { name: 'name', type: 'string', required: true },\n { name: 'appName', type: 'string', default: 'ContractSpec' },\n { name: 'actionUrl', type: 'url' },\n ],\n defaultChannels: ['EMAIL', 'IN_APP'],\n channels: {\n email: {\n subject: 'Welcome to {{appName}}, {{name}}!',\n body: `\n <h1>Welcome, {{name}}!</h1>\n <p>Thanks for joining {{appName}}. We're excited to have you on board.</p>\n <p><a href=\"{{actionUrl}}\">Get started now</a></p>\n `,\n },\n inApp: {\n title: 'Welcome to {{appName}}!',\n body: 'Thanks for joining. Click to complete your profile.',\n actionUrl: '{{actionUrl}}',\n },\n },\n});\n\n/**\n * Organization invite template.\n */\nexport const OrgInviteTemplate = defineTemplate({\n id: 'org-invite',\n name: 'Organization Invitation',\n description: 'Sent when a user is invited to an organization.',\n category: 'organization',\n variables: [\n { name: 'inviterName', type: 'string', required: true },\n { name: 'orgName', type: 'string', required: true },\n { name: 'role', type: 'string', default: 'member' },\n { name: 'actionUrl', type: 'url', required: true },\n ],\n defaultChannels: ['EMAIL'],\n channels: {\n email: {\n subject: '{{inviterName}} invited you to join {{orgName}}',\n body: `\n <h1>You've been invited!</h1>\n <p>{{inviterName}} has invited you to join <strong>{{orgName}}</strong> as a {{role}}.</p>\n <p><a href=\"{{actionUrl}}\">Accept invitation</a></p>\n `,\n },\n inApp: {\n title: 'Invitation to {{orgName}}',\n body: '{{inviterName}} invited you to join as {{role}}.',\n actionUrl: '{{actionUrl}}',\n actionText: 'Accept',\n },\n },\n});\n\n/**\n * Mention template.\n */\nexport const MentionTemplate = defineTemplate({\n id: 'mention',\n name: 'Mention',\n description: 'Sent when a user is mentioned.',\n category: 'social',\n variables: [\n { name: 'mentionerName', type: 'string', required: true },\n { name: 'context', type: 'string', required: true },\n { name: 'preview', type: 'string' },\n { name: 'actionUrl', type: 'url', required: true },\n ],\n defaultChannels: ['IN_APP', 'PUSH'],\n channels: {\n inApp: {\n title: '{{mentionerName}} mentioned you',\n body: 'In {{context}}: \"{{preview}}\"',\n actionUrl: '{{actionUrl}}',\n },\n push: {\n title: '{{mentionerName}} mentioned you',\n body: '{{preview}}',\n },\n },\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/module.notifications",
3
- "version": "1.46.1",
3
+ "version": "1.47.0",
4
4
  "description": "Notification center module for ContractSpec applications",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -10,7 +10,6 @@
10
10
  "email",
11
11
  "typescript"
12
12
  ],
13
- "main": "./dist/index.js",
14
13
  "types": "./dist/index.d.ts",
15
14
  "type": "module",
16
15
  "scripts": {
@@ -26,14 +25,14 @@
26
25
  "lint:check": "eslint src"
27
26
  },
28
27
  "dependencies": {
29
- "@contractspec/lib.schema": "1.46.1",
30
- "@contractspec/lib.contracts": "1.46.1",
31
- "@contractspec/lib.bus": "1.46.1",
32
- "zod": "^4.1.13"
28
+ "@contractspec/lib.schema": "1.47.0",
29
+ "@contractspec/lib.contracts": "1.47.0",
30
+ "@contractspec/lib.bus": "1.47.0",
31
+ "zod": "^4.3.5"
33
32
  },
34
33
  "devDependencies": {
35
- "@contractspec/tool.typescript": "1.46.1",
36
- "@contractspec/tool.tsdown": "1.46.1",
34
+ "@contractspec/tool.typescript": "1.47.0",
35
+ "@contractspec/tool.tsdown": "1.47.0",
37
36
  "typescript": "^5.9.3"
38
37
  },
39
38
  "exports": {
@@ -41,11 +40,11 @@
41
40
  "./channels": "./dist/channels/index.js",
42
41
  "./contracts": "./dist/contracts/index.js",
43
42
  "./entities": "./dist/entities/index.js",
43
+ "./notifications.capability": "./dist/notifications.capability.js",
44
44
  "./notifications.feature": "./dist/notifications.feature.js",
45
45
  "./templates": "./dist/templates/index.js",
46
46
  "./*": "./*"
47
47
  },
48
- "module": "./dist/index.js",
49
48
  "files": [
50
49
  "dist",
51
50
  "README.md"