@luxexchange/notifications 1.0.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.
Files changed (45) hide show
  1. package/.depcheckrc +14 -0
  2. package/.eslintrc.js +20 -0
  3. package/README.md +548 -0
  4. package/package.json +42 -0
  5. package/project.json +30 -0
  6. package/src/getIsNotificationServiceLocalOverrideEnabled.ts +7 -0
  7. package/src/global.d.ts +2 -0
  8. package/src/index.ts +41 -0
  9. package/src/notification-data-source/NotificationDataSource.ts +8 -0
  10. package/src/notification-data-source/getNotificationQueryOptions.ts +85 -0
  11. package/src/notification-data-source/implementations/createIntervalNotificationDataSource.ts +73 -0
  12. package/src/notification-data-source/implementations/createLocalTriggerDataSource.test.ts +492 -0
  13. package/src/notification-data-source/implementations/createLocalTriggerDataSource.ts +177 -0
  14. package/src/notification-data-source/implementations/createNotificationDataSource.ts +19 -0
  15. package/src/notification-data-source/implementations/createPollingNotificationDataSource.test.ts +398 -0
  16. package/src/notification-data-source/implementations/createPollingNotificationDataSource.ts +74 -0
  17. package/src/notification-data-source/implementations/createReactiveDataSource.ts +113 -0
  18. package/src/notification-data-source/types/ReactiveCondition.ts +60 -0
  19. package/src/notification-processor/NotificationProcessor.ts +26 -0
  20. package/src/notification-processor/implementations/createBaseNotificationProcessor.test.ts +854 -0
  21. package/src/notification-processor/implementations/createBaseNotificationProcessor.ts +239 -0
  22. package/src/notification-processor/implementations/createNotificationProcessor.test.ts +130 -0
  23. package/src/notification-processor/implementations/createNotificationProcessor.ts +15 -0
  24. package/src/notification-renderer/NotificationRenderer.ts +8 -0
  25. package/src/notification-renderer/components/BannerTemplate.tsx +188 -0
  26. package/src/notification-renderer/components/InlineBannerNotification.tsx +123 -0
  27. package/src/notification-renderer/implementations/createNotificationRenderer.ts +16 -0
  28. package/src/notification-renderer/utils/iconUtils.ts +103 -0
  29. package/src/notification-service/NotificationService.ts +47 -0
  30. package/src/notification-service/implementations/createNotificationService.test.ts +1092 -0
  31. package/src/notification-service/implementations/createNotificationService.ts +364 -0
  32. package/src/notification-telemetry/NotificationTelemetry.ts +44 -0
  33. package/src/notification-telemetry/implementations/createNotificationTelemetry.test.ts +99 -0
  34. package/src/notification-telemetry/implementations/createNotificationTelemetry.ts +33 -0
  35. package/src/notification-tracker/NotificationTracker.ts +14 -0
  36. package/src/notification-tracker/implementations/createApiNotificationTracker.test.ts +465 -0
  37. package/src/notification-tracker/implementations/createApiNotificationTracker.ts +154 -0
  38. package/src/notification-tracker/implementations/createNoopNotificationTracker.ts +44 -0
  39. package/src/notification-tracker/implementations/createNotificationTracker.ts +31 -0
  40. package/src/utils/formatNotificationType.test.ts +25 -0
  41. package/src/utils/formatNotificationType.ts +25 -0
  42. package/tsconfig.json +24 -0
  43. package/tsconfig.lint.json +8 -0
  44. package/vitest-setup.ts +1 -0
  45. package/vitest.config.ts +14 -0
@@ -0,0 +1,16 @@
1
+ import { type InAppNotification } from '@luxfi/api'
2
+ import { type NotificationRenderer } from '@luxfi/notifications/src/notification-renderer/NotificationRenderer'
3
+
4
+ export function createNotificationRenderer(ctx: {
5
+ render: (notification: InAppNotification) => () => void
6
+ canRender: (notification: InAppNotification) => boolean
7
+ }): NotificationRenderer {
8
+ return {
9
+ render: (notification: InAppNotification): (() => void) => {
10
+ return ctx.render(notification)
11
+ },
12
+ canRender: (notification: InAppNotification): boolean => {
13
+ return ctx.canRender(notification)
14
+ },
15
+ }
16
+ }
@@ -0,0 +1,103 @@
1
+ import type { GeneratedIcon } from '@luxfi/ui/src/components/factories/createIcon'
2
+ import { AlertTriangle } from '@luxfi/ui/src/components/icons/AlertTriangle'
3
+ import { Bell } from '@luxfi/ui/src/components/icons/Bell'
4
+ import { Chart } from '@luxfi/ui/src/components/icons/Chart'
5
+ import { CheckCircleFilled } from '@luxfi/ui/src/components/icons/CheckCircleFilled'
6
+ import { Coin } from '@luxfi/ui/src/components/icons/Coin'
7
+ import { CoinConvert } from '@luxfi/ui/src/components/icons/CoinConvert'
8
+ import { EthMini } from '@luxfi/ui/src/components/icons/EthMini'
9
+ import { Gas } from '@luxfi/ui/src/components/icons/Gas'
10
+ import { Gift } from '@luxfi/ui/src/components/icons/Gift'
11
+ import { Globe } from '@luxfi/ui/src/components/icons/Globe'
12
+ import { InfoCircleFilled } from '@luxfi/ui/src/components/icons/InfoCircleFilled'
13
+ import { Lightning } from '@luxfi/ui/src/components/icons/Lightning'
14
+ import { Rocket } from '@luxfi/ui/src/components/icons/Rocket'
15
+ import { SendAction } from '@luxfi/ui/src/components/icons/SendAction'
16
+ import { ShieldCheck } from '@luxfi/ui/src/components/icons/ShieldCheck'
17
+ import { Star } from '@luxfi/ui/src/components/icons/Star'
18
+ import { Wallet } from '@luxfi/ui/src/components/icons/Wallet'
19
+
20
+ /**
21
+ * Map of custom icon names to their corresponding icon components.
22
+ * Used for parsing notification icon links in the format "custom:<iconName>" or "custom:<iconName>-$<colorToken>".
23
+ */
24
+ export const CUSTOM_ICON_MAP: Record<string, GeneratedIcon> = {
25
+ lightning: Lightning,
26
+ wallet: Wallet,
27
+ chart: Chart,
28
+ gas: Gas,
29
+ coin: Coin,
30
+ 'coin-convert': CoinConvert,
31
+ ethereum: EthMini,
32
+ rocket: Rocket,
33
+ star: Star,
34
+ gift: Gift,
35
+ check: CheckCircleFilled,
36
+ info: InfoCircleFilled,
37
+ shield: ShieldCheck,
38
+ bell: Bell,
39
+ send: SendAction,
40
+ globe: Globe,
41
+ // Alert/warning icons
42
+ 'alert-triangle': AlertTriangle,
43
+ 'caution-triangle': AlertTriangle,
44
+ }
45
+
46
+ export interface ParsedCustomIcon {
47
+ iconName: string
48
+ colorToken: string | undefined
49
+ IconComponent: GeneratedIcon | undefined
50
+ }
51
+
52
+ /**
53
+ * Parses a custom icon link string and returns the icon component and color token.
54
+ *
55
+ * Supports two formats:
56
+ * - "custom:<iconName>" - Returns icon with no color token (use default)
57
+ * - "custom:<iconName>-$<colorToken>" - Returns icon with specified color token
58
+ *
59
+ * @example
60
+ * parseCustomIconLink("custom:globe") // { iconName: "globe", colorToken: undefined, IconComponent: Globe }
61
+ * parseCustomIconLink("custom:lightning-$accent1") // { iconName: "lightning", colorToken: "$accent1", IconComponent: Lightning }
62
+ * parseCustomIconLink("https://example.com/icon.png") // { iconName: "", colorToken: undefined, IconComponent: undefined }
63
+ */
64
+ export function parseCustomIconLink(iconLink: string | undefined): ParsedCustomIcon {
65
+ if (!iconLink || typeof iconLink !== 'string' || !iconLink.startsWith('custom:')) {
66
+ return { iconName: '', colorToken: undefined, IconComponent: undefined }
67
+ }
68
+
69
+ // Remove "custom:" prefix
70
+ const customPart = iconLink.slice(7)
71
+
72
+ // Check for color token format: "iconName-$colorToken"
73
+ const colorTokenMatch = customPart.match(/^(.+)-(\$\w+)$/)
74
+ if (colorTokenMatch && colorTokenMatch[1] && colorTokenMatch[2]) {
75
+ const iconName = colorTokenMatch[1]
76
+ const colorToken = colorTokenMatch[2]
77
+ return {
78
+ iconName,
79
+ colorToken,
80
+ IconComponent: CUSTOM_ICON_MAP[iconName],
81
+ }
82
+ }
83
+
84
+ // Simple format: just "iconName"
85
+ const iconName = customPart.toLowerCase()
86
+ return {
87
+ iconName,
88
+ colorToken: undefined,
89
+ IconComponent: CUSTOM_ICON_MAP[iconName],
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Gets the icon component for a custom icon link, returning undefined if not found.
95
+ *
96
+ * @example
97
+ * getCustomIconComponent("custom:globe") // Globe
98
+ * getCustomIconComponent("custom:lightning-$accent1") // Lightning
99
+ * getCustomIconComponent("https://example.com/icon.png") // undefined
100
+ */
101
+ export function getCustomIconComponent(iconLink: string | undefined): GeneratedIcon | undefined {
102
+ return parseCustomIconLink(iconLink).IconComponent
103
+ }
@@ -0,0 +1,47 @@
1
+ import { type NotificationDataSource } from '@luxfi/notifications/src/notification-data-source/NotificationDataSource'
2
+ import { type NotificationProcessor } from '@luxfi/notifications/src/notification-processor/NotificationProcessor'
3
+ import { type NotificationRenderer } from '@luxfi/notifications/src/notification-renderer/NotificationRenderer'
4
+ import { type NotificationTelemetry } from '@luxfi/notifications/src/notification-telemetry/NotificationTelemetry'
5
+ import { type NotificationTracker } from '@luxfi/notifications/src/notification-tracker/NotificationTracker'
6
+
7
+ /**
8
+ * Represents what was clicked on a notification
9
+ */
10
+ export type NotificationClickTarget = { type: 'button'; index: number } | { type: 'background' } | { type: 'dismiss' }
11
+
12
+ export interface NotificationServiceConfig {
13
+ // Multiple sources can feed notifications
14
+ dataSources: NotificationDataSource[]
15
+ tracker: NotificationTracker
16
+ processor: NotificationProcessor
17
+ renderer: NotificationRenderer
18
+ telemetry?: NotificationTelemetry
19
+ // Platform-specific handler for navigation/link clicks
20
+ // Should handle both internal navigation (same-origin) and external links
21
+ onNavigate?: (url: string) => void
22
+ }
23
+
24
+ export interface NotificationService {
25
+ // Initialize and start fetching notifications
26
+ initialize(): Promise<void>
27
+ /**
28
+ * Handle a render failure (e.g., unknown notification style)
29
+ * Cleans up the render without marking the notification as processed,
30
+ * allowing it to be re-rendered when correct data arrives
31
+ */
32
+ onRenderFailed(notificationId: string): void
33
+ /**
34
+ * Handle a click on a notification (button, background, dismiss, or acknowledge)
35
+ * Executes all actions specified in the onClick array for the clicked target
36
+ * @param notificationId - ID of the notification that was clicked
37
+ * @param target - What was clicked (button, background, dismiss, or acknowledge)
38
+ */
39
+ onNotificationClick(notificationId: string, target: NotificationClickTarget): void
40
+ /**
41
+ * Handle a notification being shown to the user
42
+ * @param notificationId - ID of the notification that was shown
43
+ */
44
+ onNotificationShown(notificationId: string): void
45
+ // Cleanup and teardown
46
+ destroy(): void
47
+ }