queen-mq 0.1.1 → 0.1.2

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 (139) hide show
  1. package/API.md +1226 -0
  2. package/AUTH.md +2044 -0
  3. package/LICENSE.md +202 -0
  4. package/README.md +276 -53
  5. package/WEBAPP.md +1889 -0
  6. package/assets/dashboard-01.png +0 -0
  7. package/assets/queen-logo-blue.svg +210 -0
  8. package/assets/queen-logo-cyan.svg +210 -0
  9. package/assets/queen-logo-indigo.svg +210 -0
  10. package/assets/queen-logo-orange.svg +210 -0
  11. package/assets/queen-logo-pink.svg +210 -0
  12. package/assets/queen-logo-purple.svg +210 -0
  13. package/assets/queen-logo-rose.svg +239 -0
  14. package/assets/queen-logo.svg +263 -0
  15. package/examples/batch-processing.js +58 -0
  16. package/examples/test-dashboard-api.js +200 -0
  17. package/package.json +4 -2
  18. package/server.log +1 -0
  19. package/src/benchmark/consumer.js +207 -0
  20. package/src/benchmark/consumer_multi.js +216 -0
  21. package/src/benchmark/producer.js +75 -0
  22. package/src/benchmark/producer_multi.js +115 -0
  23. package/src/client/client.js +192 -16
  24. package/src/client/queenClient.js +5 -0
  25. package/src/cluster-server.js +242 -0
  26. package/src/config.js +19 -5
  27. package/src/database/connection.js +42 -16
  28. package/src/database/poolManager.js +7 -0
  29. package/src/database/schema-v2.sql +194 -130
  30. package/src/managers/queueManagerOptimized.js +823 -933
  31. package/src/managers/systemEventManager.js +8 -3
  32. package/src/routes/messages.js +127 -57
  33. package/src/routes/pop.js +27 -43
  34. package/src/routes/resources.js +61 -27
  35. package/src/routes/status.js +1037 -0
  36. package/src/server.js +308 -272
  37. package/src/services/evictionService.js +57 -28
  38. package/src/services/retentionService.js +44 -11
  39. package/src/test/advanced-pattern-tests.js +5 -5
  40. package/src/test/bus-mode-tests.js +24 -11
  41. package/src/test/edge-case-tests.js +12 -5
  42. package/src/test/enterprise-tests.js +48 -15
  43. package/src/test/utils.js +1 -1
  44. package/src/utils/streaming.js +231 -0
  45. package/src/utils/uuid.js +2 -2
  46. package/src/websocket/wsServer.js +10 -3
  47. package/test-keepalive-v2.sh +22 -0
  48. package/webapp/COLOR_GUIDE.md +118 -0
  49. package/webapp/README.md +143 -0
  50. package/webapp/index.html +14 -0
  51. package/webapp/package-lock.json +3184 -0
  52. package/webapp/package.json +25 -0
  53. package/webapp/postcss.config.js +7 -0
  54. package/webapp/public/assets/queen-logo-blue.svg +210 -0
  55. package/webapp/public/assets/queen-logo-cyan.svg +210 -0
  56. package/webapp/public/assets/queen-logo-indigo.svg +210 -0
  57. package/webapp/public/assets/queen-logo-orange.svg +210 -0
  58. package/webapp/public/assets/queen-logo-pink.svg +210 -0
  59. package/webapp/public/assets/queen-logo-purple.svg +210 -0
  60. package/webapp/public/assets/queen-logo-rose.svg +239 -0
  61. package/webapp/public/assets/queen-logo.svg +263 -0
  62. package/webapp/src/App.vue +19 -0
  63. package/webapp/src/api/analytics.js +10 -0
  64. package/webapp/src/api/client.js +29 -0
  65. package/webapp/src/api/consumers.js +52 -0
  66. package/webapp/src/api/health.js +7 -0
  67. package/webapp/src/api/messages.js +26 -0
  68. package/webapp/src/api/queues.js +14 -0
  69. package/webapp/src/api/resources.js +8 -0
  70. package/webapp/src/assets/styles/main.css +357 -0
  71. package/webapp/src/components/analytics/AnalyticsFilters.vue +87 -0
  72. package/webapp/src/components/analytics/AnalyticsMetrics.vue +57 -0
  73. package/webapp/src/components/analytics/MessageDistributionChart.vue +111 -0
  74. package/webapp/src/components/analytics/MessageFlowChart.vue +173 -0
  75. package/webapp/src/components/analytics/TimeRangeSelector.vue +27 -0
  76. package/webapp/src/components/analytics/TopQueuesChart.vue +132 -0
  77. package/webapp/src/components/common/ConfirmDialog.vue +56 -0
  78. package/webapp/src/components/common/LoadingSpinner.vue +6 -0
  79. package/webapp/src/components/common/MetricCard.vue +43 -0
  80. package/webapp/src/components/common/StatusBadge.vue +45 -0
  81. package/webapp/src/components/dashboard/MessageStatusCard.vue +50 -0
  82. package/webapp/src/components/dashboard/PerformanceCard.vue +38 -0
  83. package/webapp/src/components/dashboard/ThroughputChart.vue +182 -0
  84. package/webapp/src/components/dashboard/TopQueuesTable.vue +53 -0
  85. package/webapp/src/components/layout/AppLayout.vue +110 -0
  86. package/webapp/src/components/layout/AppSidebar.vue +304 -0
  87. package/webapp/src/components/messages/MessageDetailPanel.vue +242 -0
  88. package/webapp/src/components/messages/MessageFilters.vue +114 -0
  89. package/webapp/src/components/queue-detail/PartitionList.vue +79 -0
  90. package/webapp/src/components/queue-detail/PushMessageModal.vue +175 -0
  91. package/webapp/src/components/queue-detail/QueueConfig.vue +63 -0
  92. package/webapp/src/components/queue-detail/QueueDetailHeader.vue +53 -0
  93. package/webapp/src/components/queue-detail/RecentMessages.vue +76 -0
  94. package/webapp/src/components/queues/CreateQueueModal.vue +193 -0
  95. package/webapp/src/components/queues/QueueFilters.vue +90 -0
  96. package/webapp/src/composables/useApi.js +34 -0
  97. package/webapp/src/composables/useTheme.js +36 -0
  98. package/webapp/src/main.js +11 -0
  99. package/webapp/src/router/index.js +42 -0
  100. package/webapp/src/utils/colors.js +96 -0
  101. package/webapp/src/utils/formatters.js +49 -0
  102. package/webapp/src/views/Analytics.vue +377 -0
  103. package/webapp/src/views/ConsumerGroups.vue +433 -0
  104. package/webapp/src/views/Dashboard.vue +418 -0
  105. package/webapp/src/views/Messages.vue +361 -0
  106. package/webapp/src/views/QueueDetail.vue +582 -0
  107. package/webapp/src/views/Queues.vue +496 -0
  108. package/webapp/tailwind.config.js +25 -0
  109. package/webapp/vite.config.js +10 -0
  110. package/dashboard/.vscode/extensions.json +0 -3
  111. package/dashboard/README.md +0 -5
  112. package/dashboard/index.html +0 -14
  113. package/dashboard/package-lock.json +0 -1458
  114. package/dashboard/package.json +0 -25
  115. package/dashboard/public/vite.svg +0 -1
  116. package/dashboard/src/App.vue +0 -29
  117. package/dashboard/src/assets/styles/main.css +0 -908
  118. package/dashboard/src/assets/vue.svg +0 -1
  119. package/dashboard/src/components/cards/MetricCard.vue +0 -298
  120. package/dashboard/src/components/charts/QueueDepthChart.vue +0 -276
  121. package/dashboard/src/components/charts/QueueLagChart.vue +0 -436
  122. package/dashboard/src/components/charts/ThroughputChart.vue +0 -302
  123. package/dashboard/src/components/common/ActivityFeed.vue +0 -251
  124. package/dashboard/src/components/layout/AppHeader.vue +0 -208
  125. package/dashboard/src/components/layout/AppLayout.vue +0 -88
  126. package/dashboard/src/components/layout/AppSidebar.vue +0 -261
  127. package/dashboard/src/main.js +0 -44
  128. package/dashboard/src/router.js +0 -54
  129. package/dashboard/src/services/api.js +0 -187
  130. package/dashboard/src/services/websocket.js +0 -167
  131. package/dashboard/src/utils/constants.js +0 -56
  132. package/dashboard/src/utils/helpers.js +0 -118
  133. package/dashboard/src/views/Analytics.vue +0 -912
  134. package/dashboard/src/views/Dashboard.vue +0 -906
  135. package/dashboard/src/views/Messages.vue +0 -437
  136. package/dashboard/src/views/QueueDetail.vue +0 -501
  137. package/dashboard/src/views/Queues.vue +0 -333
  138. package/dashboard/vite.config.js +0 -30
  139. package/src/routes/analytics.js +0 -812
@@ -1,302 +0,0 @@
1
- <template>
2
- <div class="chart-container">
3
- <div class="chart-header">
4
- <h3 class="chart-title">{{ title || 'Message Throughput' }}</h3>
5
- <div class="chart-actions">
6
- <Button
7
- icon="pi pi-refresh"
8
- class="p-button-text p-button-sm"
9
- @click="$emit('refresh')"
10
- v-tooltip="'Refresh'"
11
- />
12
- </div>
13
- </div>
14
-
15
- <div class="throughput-chart">
16
- <Chart
17
- v-if="!loading && chartDataWithTheme && chartDataWithTheme.labels && chartDataWithTheme.labels.length > 0"
18
- type="bar"
19
- :data="chartDataWithTheme"
20
- :options="chartOptionsWithTheme"
21
- class="chart"
22
- />
23
- <div v-else-if="loading" class="chart-loading">
24
- <ProgressSpinner />
25
- <span>Loading chart data...</span>
26
- </div>
27
- <div v-else class="chart-empty">
28
- <i class="pi pi-chart-bar empty-icon"></i>
29
- <span>No data available</span>
30
- </div>
31
- </div>
32
- </div>
33
- </template>
34
-
35
- <script setup>
36
- import { computed } from 'vue'
37
- import Chart from 'primevue/chart'
38
- import Button from 'primevue/button'
39
- import ProgressSpinner from 'primevue/progressspinner'
40
-
41
- // Import and register Chart.js components
42
- import {
43
- Chart as ChartJS,
44
- CategoryScale,
45
- LinearScale,
46
- BarElement,
47
- Title,
48
- Tooltip,
49
- Legend
50
- } from 'chart.js'
51
-
52
- ChartJS.register(
53
- CategoryScale,
54
- LinearScale,
55
- BarElement,
56
- Title,
57
- Tooltip,
58
- Legend
59
- )
60
-
61
- const props = defineProps({
62
- title: {
63
- type: String,
64
- default: null
65
- },
66
- data: {
67
- type: Object,
68
- default: null
69
- },
70
- loading: {
71
- type: Boolean,
72
- default: false
73
- },
74
- stacked: {
75
- type: Boolean,
76
- default: true
77
- }
78
- })
79
-
80
- const emit = defineEmits(['refresh'])
81
-
82
- // Apply dark theme colors to chart data
83
- const chartDataWithTheme = computed(() => {
84
- if (!props.data) return null
85
-
86
- return {
87
- labels: props.data.labels,
88
- datasets: [
89
- {
90
- label: 'Incoming Messages',
91
- backgroundColor: '#ec4899',
92
- borderColor: '#ec4899',
93
- borderWidth: 0,
94
- borderRadius: 4,
95
- data: props.data.datasets?.[0]?.data || []
96
- },
97
- {
98
- label: 'Completed Messages',
99
- backgroundColor: 'rgba(236, 72, 153, 0.5)',
100
- borderColor: 'rgba(236, 72, 153, 0.5)',
101
- borderWidth: 0,
102
- borderRadius: 4,
103
- data: props.data.datasets?.[1]?.data || []
104
- },
105
- {
106
- label: 'Failed Messages',
107
- backgroundColor: 'rgba(236, 72, 153, 0.2)',
108
- borderColor: 'rgba(236, 72, 153, 0.2)',
109
- borderWidth: 0,
110
- borderRadius: 4,
111
- data: props.data.datasets?.[2]?.data || []
112
- }
113
- ]
114
- }
115
- })
116
-
117
- // Dark theme chart options
118
- const chartOptionsWithTheme = computed(() => ({
119
- responsive: true,
120
- maintainAspectRatio: false,
121
- plugins: {
122
- legend: {
123
- position: 'bottom',
124
- labels: {
125
- padding: 15,
126
- usePointStyle: true,
127
- font: {
128
- size: 11,
129
- family: 'Inter'
130
- },
131
- color: '#cbd5e1'
132
- }
133
- },
134
- tooltip: {
135
- backgroundColor: 'rgba(30, 41, 59, 0.95)',
136
- titleColor: '#f1f5f9',
137
- bodyColor: '#cbd5e1',
138
- borderColor: 'rgba(236, 72, 153, 0.3)',
139
- borderWidth: 1,
140
- cornerRadius: 8,
141
- padding: 12,
142
- displayColors: true,
143
- mode: 'index',
144
- intersect: false,
145
- callbacks: {
146
- label: (context) => {
147
- return `${context.dataset.label}: ${context.parsed.y.toLocaleString()} messages`
148
- }
149
- }
150
- }
151
- },
152
- scales: {
153
- x: {
154
- stacked: props.stacked,
155
- grid: {
156
- display: false
157
- },
158
- ticks: {
159
- color: '#94a3b8',
160
- maxRotation: 0,
161
- autoSkipPadding: 20,
162
- font: {
163
- size: 11
164
- }
165
- },
166
- border: {
167
- display: false
168
- }
169
- },
170
- y: {
171
- stacked: props.stacked,
172
- beginAtZero: true,
173
- grid: {
174
- color: 'rgba(255, 255, 255, 0.03)',
175
- drawBorder: false
176
- },
177
- ticks: {
178
- color: '#94a3b8',
179
- callback: (value) => {
180
- if (value >= 1000000) {
181
- return (value / 1000000).toFixed(1) + 'M'
182
- } else if (value >= 1000) {
183
- return (value / 1000).toFixed(1) + 'K'
184
- }
185
- return value
186
- },
187
- font: {
188
- size: 11
189
- }
190
- },
191
- border: {
192
- display: false
193
- }
194
- }
195
- },
196
- interaction: {
197
- mode: 'index',
198
- intersect: false
199
- },
200
- animation: {
201
- duration: 300,
202
- easing: 'easeInOutQuart',
203
- // Smooth animations for real-time updates
204
- onComplete: null,
205
- onProgress: null
206
- },
207
- // Enable smooth transitions for data updates
208
- transitions: {
209
- active: {
210
- animation: {
211
- duration: 200
212
- }
213
- }
214
- }
215
- }))
216
- </script>
217
-
218
- <style scoped>
219
- .chart-container {
220
- background: transparent;
221
- border: 1px solid rgba(255, 255, 255, 0.1);
222
- border-radius: 16px;
223
- padding: 1.5rem;
224
- height: 100%;
225
- display: flex;
226
- flex-direction: column;
227
- }
228
-
229
- .chart-header {
230
- display: flex;
231
- justify-content: space-between;
232
- align-items: center;
233
- margin-bottom: 1.5rem;
234
- }
235
-
236
- .chart-title {
237
- font-size: 1.125rem;
238
- font-weight: 600;
239
- color: var(--surface-700);
240
- margin: 0;
241
- }
242
-
243
- .chart-actions {
244
- display: flex;
245
- gap: 0.5rem;
246
- }
247
-
248
- .throughput-chart {
249
- flex: 1;
250
- min-height: 300px;
251
- position: relative;
252
- }
253
-
254
- .chart {
255
- height: 100%;
256
- }
257
-
258
- .chart-loading,
259
- .chart-empty {
260
- height: 100%;
261
- display: flex;
262
- flex-direction: column;
263
- align-items: center;
264
- justify-content: center;
265
- gap: 1rem;
266
- color: var(--surface-400);
267
- }
268
-
269
- .empty-icon {
270
- font-size: 3rem;
271
- color: var(--surface-300);
272
- }
273
-
274
- :deep(.p-button-sm) {
275
- padding: 0.5rem;
276
- font-size: 0.875rem;
277
- }
278
-
279
- :deep(.p-button-text) {
280
- color: var(--surface-500);
281
- }
282
-
283
- :deep(.p-button-text:hover) {
284
- background: rgba(236, 72, 153, 0.1);
285
- color: var(--primary-500);
286
- }
287
-
288
- /* Responsive */
289
- @media (max-width: 768px) {
290
- .chart-container {
291
- padding: 1rem;
292
- }
293
-
294
- .chart-title {
295
- font-size: 1rem;
296
- }
297
-
298
- .throughput-chart {
299
- min-height: 250px;
300
- }
301
- }
302
- </style>
@@ -1,251 +0,0 @@
1
- <template>
2
- <div class="activity-feed">
3
- <ScrollPanel class="feed-container">
4
- <div v-if="events.length > 0" class="feed-items">
5
- <div
6
- v-for="event in events"
7
- :key="event.id"
8
- class="feed-item fade-in"
9
- >
10
- <div class="feed-icon" :class="getEventClass(event.event)">
11
- <i :class="getEventIcon(event.event)"></i>
12
- </div>
13
-
14
- <div class="feed-content">
15
- <div class="feed-title">{{ getEventTitle(event.event) }}</div>
16
- <div class="feed-details">
17
- <span v-if="event.data && event.data.queue" class="feed-queue">
18
- {{ event.data.queue }}
19
- <span v-if="event.data.partition && event.data.partition !== 'Default'">
20
- /{{ event.data.partition }}
21
- </span>
22
- </span>
23
- <span v-if="event.data && event.data.transactionId" class="feed-id">
24
- {{ event.data.transactionId.substring(0, 8) }}...
25
- </span>
26
- </div>
27
- <div class="feed-time">{{ formatTime(event.timestamp) }}</div>
28
- </div>
29
- </div>
30
- </div>
31
-
32
- <div v-else class="feed-empty">
33
- <i class="pi pi-inbox empty-icon"></i>
34
- <span>No activity yet</span>
35
- <span class="empty-subtitle">Events will appear here in real-time</span>
36
- </div>
37
- </ScrollPanel>
38
- </div>
39
- </template>
40
-
41
- <script setup>
42
- import { computed } from 'vue'
43
- import ScrollPanel from 'primevue/scrollpanel'
44
- import { formatRelativeTime } from '../../utils/helpers.js'
45
-
46
- const props = defineProps({
47
- events: {
48
- type: Array,
49
- default: () => []
50
- }
51
- })
52
-
53
- // Get event icon
54
- const getEventIcon = (eventType) => {
55
- if (!eventType || typeof eventType !== 'string') return 'pi pi-info-circle'
56
- const icons = {
57
- 'message.pushed': 'pi pi-plus',
58
- 'message.processing': 'pi pi-spin pi-spinner',
59
- 'message.completed': 'pi pi-check',
60
- 'message.failed': 'pi pi-times',
61
- 'queue.created': 'pi pi-inbox',
62
- 'queue.depth': 'pi pi-chart-bar',
63
- 'system.stats': 'pi pi-chart-line',
64
- 'client.connected': 'pi pi-sign-in',
65
- 'client.disconnected': 'pi pi-sign-out'
66
- }
67
- return icons[eventType] || 'pi pi-info-circle'
68
- }
69
-
70
- // Get event class for styling
71
- const getEventClass = (eventType) => {
72
- if (!eventType || typeof eventType !== 'string') return 'event-default'
73
- if (eventType.includes('completed')) return 'event-success'
74
- if (eventType.includes('failed')) return 'event-danger'
75
- if (eventType.includes('processing')) return 'event-info'
76
- if (eventType.includes('pushed') || eventType.includes('created')) return 'event-primary'
77
- return 'event-default'
78
- }
79
-
80
- // Get event title
81
- const getEventTitle = (eventType) => {
82
- if (!eventType || typeof eventType !== 'string') return 'Unknown Event'
83
- const titles = {
84
- 'message.pushed': 'Message Pushed',
85
- 'message.processing': 'Processing Message',
86
- 'message.completed': 'Message Completed',
87
- 'message.failed': 'Message Failed',
88
- 'queue.created': 'Queue Created',
89
- 'queue.depth': 'Queue Depth Update',
90
- 'system.stats': 'System Stats Update',
91
- 'client.connected': 'Client Connected',
92
- 'client.disconnected': 'Client Disconnected'
93
- }
94
- return titles[eventType] || eventType
95
- }
96
-
97
- // Format time
98
- const formatTime = (timestamp) => {
99
- return formatRelativeTime(timestamp)
100
- }
101
- </script>
102
-
103
- <style scoped>
104
- .activity-feed {
105
- height: 100%;
106
- }
107
-
108
- .feed-container {
109
- height: 350px;
110
- }
111
-
112
- :deep(.p-scrollpanel-content) {
113
- padding: 0.5rem;
114
- }
115
-
116
- .feed-items {
117
- display: flex;
118
- flex-direction: column;
119
- gap: 0.5rem;
120
- }
121
-
122
- .feed-item {
123
- display: flex;
124
- align-items: flex-start;
125
- gap: 1rem;
126
- padding: 0.875rem;
127
- border-radius: 8px;
128
- background: var(--surface-0);
129
- border: 1px solid rgba(255, 255, 255, 0.03);
130
- transition: all 0.2s ease;
131
- }
132
-
133
- .feed-item:hover {
134
- background: rgba(236, 72, 153, 0.05);
135
- border-color: rgba(236, 72, 153, 0.1);
136
- }
137
-
138
- .feed-icon {
139
- width: 36px;
140
- height: 36px;
141
- border-radius: 8px;
142
- display: flex;
143
- align-items: center;
144
- justify-content: center;
145
- flex-shrink: 0;
146
- font-size: 0.875rem;
147
- }
148
-
149
- .event-primary {
150
- background: rgba(236, 72, 153, 0.15);
151
- color: var(--primary-500);
152
- }
153
-
154
- .event-success {
155
- background: rgba(16, 185, 129, 0.15);
156
- color: var(--success-color);
157
- }
158
-
159
- .event-info {
160
- background: rgba(6, 182, 212, 0.15);
161
- color: var(--info-color);
162
- }
163
-
164
- .event-danger {
165
- background: rgba(239, 68, 68, 0.15);
166
- color: var(--danger-color);
167
- }
168
-
169
- .event-default {
170
- background: rgba(148, 163, 184, 0.15);
171
- color: var(--surface-400);
172
- }
173
-
174
- .feed-content {
175
- flex: 1;
176
- min-width: 0;
177
- }
178
-
179
- .feed-title {
180
- font-size: 0.875rem;
181
- font-weight: 500;
182
- color: var(--surface-600);
183
- margin-bottom: 0.125rem;
184
- }
185
-
186
- .feed-details {
187
- display: flex;
188
- align-items: center;
189
- gap: 0.5rem;
190
- font-size: 0.75rem;
191
- color: var(--surface-400);
192
- margin-bottom: 0.25rem;
193
- }
194
-
195
- .feed-queue {
196
- background: rgba(236, 72, 153, 0.1);
197
- color: var(--primary-500);
198
- padding: 0.125rem 0.5rem;
199
- border-radius: 4px;
200
- font-weight: 500;
201
- }
202
-
203
- .feed-id {
204
- font-family: 'Courier New', monospace;
205
- font-size: 0.75rem;
206
- color: var(--surface-400);
207
- }
208
-
209
- .feed-time {
210
- font-size: 0.75rem;
211
- color: var(--surface-300);
212
- }
213
-
214
- .feed-empty {
215
- height: 100%;
216
- display: flex;
217
- flex-direction: column;
218
- align-items: center;
219
- justify-content: center;
220
- gap: 0.5rem;
221
- color: var(--surface-400);
222
- padding: 2rem;
223
- text-align: center;
224
- }
225
-
226
- .empty-icon {
227
- font-size: 3rem;
228
- color: var(--surface-300);
229
- margin-bottom: 0.5rem;
230
- }
231
-
232
- .empty-subtitle {
233
- font-size: 0.875rem;
234
- color: var(--surface-300);
235
- }
236
-
237
- .fade-in {
238
- animation: fadeIn 0.3s ease;
239
- }
240
-
241
- @keyframes fadeIn {
242
- from {
243
- opacity: 0;
244
- transform: translateY(-10px);
245
- }
246
- to {
247
- opacity: 1;
248
- transform: translateY(0);
249
- }
250
- }
251
- </style>