nestlens 0.1.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.
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/dist/__tests__/api/api.controller.spec.d.ts +2 -0
- package/dist/__tests__/api/api.controller.spec.d.ts.map +1 -0
- package/dist/__tests__/api/api.controller.spec.js +982 -0
- package/dist/__tests__/api/api.controller.spec.js.map +1 -0
- package/dist/__tests__/api/api.guard.spec.d.ts +2 -0
- package/dist/__tests__/api/api.guard.spec.d.ts.map +1 -0
- package/dist/__tests__/api/api.guard.spec.js +572 -0
- package/dist/__tests__/api/api.guard.spec.js.map +1 -0
- package/dist/__tests__/api/dashboard.controller.spec.d.ts +2 -0
- package/dist/__tests__/api/dashboard.controller.spec.d.ts.map +1 -0
- package/dist/__tests__/api/dashboard.controller.spec.js +474 -0
- package/dist/__tests__/api/dashboard.controller.spec.js.map +1 -0
- package/dist/__tests__/api/tag.controller.spec.d.ts +2 -0
- package/dist/__tests__/api/tag.controller.spec.d.ts.map +1 -0
- package/dist/__tests__/api/tag.controller.spec.js +280 -0
- package/dist/__tests__/api/tag.controller.spec.js.map +1 -0
- package/dist/__tests__/collector.service.spec.d.ts +2 -0
- package/dist/__tests__/collector.service.spec.d.ts.map +1 -0
- package/dist/__tests__/collector.service.spec.js +240 -0
- package/dist/__tests__/collector.service.spec.js.map +1 -0
- package/dist/__tests__/core/collector.service.spec.d.ts +2 -0
- package/dist/__tests__/core/collector.service.spec.d.ts.map +1 -0
- package/dist/__tests__/core/collector.service.spec.js +526 -0
- package/dist/__tests__/core/collector.service.spec.js.map +1 -0
- package/dist/__tests__/core/family-hash.service.spec.d.ts +2 -0
- package/dist/__tests__/core/family-hash.service.spec.d.ts.map +1 -0
- package/dist/__tests__/core/family-hash.service.spec.js +1117 -0
- package/dist/__tests__/core/family-hash.service.spec.js.map +1 -0
- package/dist/__tests__/core/pruning.service.spec.d.ts +2 -0
- package/dist/__tests__/core/pruning.service.spec.d.ts.map +1 -0
- package/dist/__tests__/core/pruning.service.spec.js +224 -0
- package/dist/__tests__/core/pruning.service.spec.js.map +1 -0
- package/dist/__tests__/core/storage/sqlite.storage.spec.d.ts +2 -0
- package/dist/__tests__/core/storage/sqlite.storage.spec.d.ts.map +1 -0
- package/dist/__tests__/core/storage/sqlite.storage.spec.js +853 -0
- package/dist/__tests__/core/storage/sqlite.storage.spec.js.map +1 -0
- package/dist/__tests__/core/tag.service.spec.d.ts +2 -0
- package/dist/__tests__/core/tag.service.spec.d.ts.map +1 -0
- package/dist/__tests__/core/tag.service.spec.js +994 -0
- package/dist/__tests__/core/tag.service.spec.js.map +1 -0
- package/dist/__tests__/family-hash.service.spec.d.ts +2 -0
- package/dist/__tests__/family-hash.service.spec.d.ts.map +1 -0
- package/dist/__tests__/family-hash.service.spec.js +325 -0
- package/dist/__tests__/family-hash.service.spec.js.map +1 -0
- package/dist/__tests__/filters/api-filters.spec.d.ts +2 -0
- package/dist/__tests__/filters/api-filters.spec.d.ts.map +1 -0
- package/dist/__tests__/filters/api-filters.spec.js +172 -0
- package/dist/__tests__/filters/api-filters.spec.js.map +1 -0
- package/dist/__tests__/filters/entry-factories.d.ts +20 -0
- package/dist/__tests__/filters/entry-factories.d.ts.map +1 -0
- package/dist/__tests__/filters/entry-factories.js +288 -0
- package/dist/__tests__/filters/entry-factories.js.map +1 -0
- package/dist/__tests__/filters/filter-contract.spec.d.ts +2 -0
- package/dist/__tests__/filters/filter-contract.spec.d.ts.map +1 -0
- package/dist/__tests__/filters/filter-contract.spec.js +230 -0
- package/dist/__tests__/filters/filter-contract.spec.js.map +1 -0
- package/dist/__tests__/filters/filter-test-data.d.ts +26 -0
- package/dist/__tests__/filters/filter-test-data.d.ts.map +1 -0
- package/dist/__tests__/filters/filter-test-data.js +374 -0
- package/dist/__tests__/filters/filter-test-data.js.map +1 -0
- package/dist/__tests__/filters/storage-filters.spec.d.ts +2 -0
- package/dist/__tests__/filters/storage-filters.spec.d.ts.map +1 -0
- package/dist/__tests__/filters/storage-filters.spec.js +699 -0
- package/dist/__tests__/filters/storage-filters.spec.js.map +1 -0
- package/dist/__tests__/filters/test-utils.d.ts +23 -0
- package/dist/__tests__/filters/test-utils.d.ts.map +1 -0
- package/dist/__tests__/filters/test-utils.js +54 -0
- package/dist/__tests__/filters/test-utils.js.map +1 -0
- package/dist/__tests__/nestlens.module.spec.d.ts +2 -0
- package/dist/__tests__/nestlens.module.spec.d.ts.map +1 -0
- package/dist/__tests__/nestlens.module.spec.js +620 -0
- package/dist/__tests__/nestlens.module.spec.js.map +1 -0
- package/dist/__tests__/pruning.service.spec.d.ts +2 -0
- package/dist/__tests__/pruning.service.spec.d.ts.map +1 -0
- package/dist/__tests__/pruning.service.spec.js +142 -0
- package/dist/__tests__/pruning.service.spec.js.map +1 -0
- package/dist/__tests__/setup.d.ts +7 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +24 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/__tests__/tag.service.spec.d.ts +2 -0
- package/dist/__tests__/tag.service.spec.d.ts.map +1 -0
- package/dist/__tests__/tag.service.spec.js +482 -0
- package/dist/__tests__/tag.service.spec.js.map +1 -0
- package/dist/__tests__/watchers/batch.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/batch.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/batch.watcher.spec.js +515 -0
- package/dist/__tests__/watchers/batch.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/cache.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/cache.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/cache.watcher.spec.js +395 -0
- package/dist/__tests__/watchers/cache.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/command.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/command.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/command.watcher.spec.js +598 -0
- package/dist/__tests__/watchers/command.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/dump.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/dump.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/dump.watcher.spec.js +724 -0
- package/dist/__tests__/watchers/dump.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/event.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/event.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/event.watcher.spec.js +316 -0
- package/dist/__tests__/watchers/event.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/exception.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/exception.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/exception.watcher.spec.js +495 -0
- package/dist/__tests__/watchers/exception.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/gate.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/gate.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/gate.watcher.spec.js +683 -0
- package/dist/__tests__/watchers/gate.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/http-client.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/http-client.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/http-client.watcher.spec.js +888 -0
- package/dist/__tests__/watchers/http-client.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/job.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/job.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/job.watcher.spec.js +513 -0
- package/dist/__tests__/watchers/job.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/log.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/log.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/log.watcher.spec.js +428 -0
- package/dist/__tests__/watchers/log.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/mail.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/mail.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/mail.watcher.spec.js +425 -0
- package/dist/__tests__/watchers/mail.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/model.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/model.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/model.watcher.spec.js +675 -0
- package/dist/__tests__/watchers/model.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/notification.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/notification.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/notification.watcher.spec.js +595 -0
- package/dist/__tests__/watchers/notification.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/query/types.spec.d.ts +2 -0
- package/dist/__tests__/watchers/query/types.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/query/types.spec.js +292 -0
- package/dist/__tests__/watchers/query/types.spec.js.map +1 -0
- package/dist/__tests__/watchers/query.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/query.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/query.watcher.spec.js +597 -0
- package/dist/__tests__/watchers/query.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/redis.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/redis.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/redis.watcher.spec.js +634 -0
- package/dist/__tests__/watchers/redis.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/request.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/request.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/request.watcher.spec.js +1017 -0
- package/dist/__tests__/watchers/request.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/schedule.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/schedule.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/schedule.watcher.spec.js +338 -0
- package/dist/__tests__/watchers/schedule.watcher.spec.js.map +1 -0
- package/dist/__tests__/watchers/view.watcher.spec.d.ts +2 -0
- package/dist/__tests__/watchers/view.watcher.spec.d.ts.map +1 -0
- package/dist/__tests__/watchers/view.watcher.spec.js +564 -0
- package/dist/__tests__/watchers/view.watcher.spec.js.map +1 -0
- package/dist/api/api.controller.d.ts +193 -0
- package/dist/api/api.controller.d.ts.map +1 -0
- package/dist/api/api.controller.js +562 -0
- package/dist/api/api.controller.js.map +1 -0
- package/dist/api/api.guard.d.ts +77 -0
- package/dist/api/api.guard.d.ts.map +1 -0
- package/dist/api/api.guard.js +294 -0
- package/dist/api/api.guard.js.map +1 -0
- package/dist/api/dashboard.controller.d.ts +49 -0
- package/dist/api/dashboard.controller.d.ts.map +1 -0
- package/dist/api/dashboard.controller.js +472 -0
- package/dist/api/dashboard.controller.js.map +1 -0
- package/dist/api/index.d.ts +5 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +21 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/tag.controller.d.ts +65 -0
- package/dist/api/tag.controller.d.ts.map +1 -0
- package/dist/api/tag.controller.js +149 -0
- package/dist/api/tag.controller.js.map +1 -0
- package/dist/core/collector.service.d.ts +80 -0
- package/dist/core/collector.service.d.ts.map +1 -0
- package/dist/core/collector.service.js +255 -0
- package/dist/core/collector.service.js.map +1 -0
- package/dist/core/family-hash.service.d.ts +64 -0
- package/dist/core/family-hash.service.d.ts.map +1 -0
- package/dist/core/family-hash.service.js +281 -0
- package/dist/core/family-hash.service.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +20 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/pruning.service.d.ts +16 -0
- package/dist/core/pruning.service.d.ts.map +1 -0
- package/dist/core/pruning.service.js +71 -0
- package/dist/core/pruning.service.js.map +1 -0
- package/dist/core/storage/index.d.ts +3 -0
- package/dist/core/storage/index.d.ts.map +1 -0
- package/dist/core/storage/index.js +19 -0
- package/dist/core/storage/index.js.map +1 -0
- package/dist/core/storage/sqlite.storage.d.ts +60 -0
- package/dist/core/storage/sqlite.storage.d.ts.map +1 -0
- package/dist/core/storage/sqlite.storage.js +929 -0
- package/dist/core/storage/sqlite.storage.js.map +1 -0
- package/dist/core/storage/storage.interface.d.ts +122 -0
- package/dist/core/storage/storage.interface.d.ts.map +1 -0
- package/dist/core/storage/storage.interface.js +5 -0
- package/dist/core/storage/storage.interface.js.map +1 -0
- package/dist/core/tag.service.d.ts +71 -0
- package/dist/core/tag.service.d.ts.map +1 -0
- package/dist/core/tag.service.js +568 -0
- package/dist/core/tag.service.js.map +1 -0
- package/dist/dashboard/public/assets/BatchesPage-DFT4fKlJ.js +1 -0
- package/dist/dashboard/public/assets/CachePage-CRy1Tjb8.js +1 -0
- package/dist/dashboard/public/assets/ClickableBadge-CV5J3THx.js +1 -0
- package/dist/dashboard/public/assets/CommandsPage-DdRnTm-W.js +1 -0
- package/dist/dashboard/public/assets/DashboardPage-CjaRZXYy.js +26 -0
- package/dist/dashboard/public/assets/DataTable-B6o9H8lh.js +88 -0
- package/dist/dashboard/public/assets/DumpsPage-DO8y1RTg.js +1 -0
- package/dist/dashboard/public/assets/EntryDetailPage-By-YcAGL.js +125 -0
- package/dist/dashboard/public/assets/EventsPage-u-r4AiT4.js +1 -0
- package/dist/dashboard/public/assets/ExceptionsPage-DXUcARr1.js +6 -0
- package/dist/dashboard/public/assets/GatesPage-DpeP7CDZ.js +1 -0
- package/dist/dashboard/public/assets/HttpClientPage-BJ4-5E6t.js +1 -0
- package/dist/dashboard/public/assets/JobsPage-Dv3KaX2x.js +1 -0
- package/dist/dashboard/public/assets/LogsPage-D0Q3yDb1.js +1 -0
- package/dist/dashboard/public/assets/MailPage-Bf8C6WF6.js +1 -0
- package/dist/dashboard/public/assets/ModelsPage-BMHncI5y.js +1 -0
- package/dist/dashboard/public/assets/NotificationsPage-D5-I-Oxb.js +1 -0
- package/dist/dashboard/public/assets/QueriesPage-oNp0i6Gt.js +1 -0
- package/dist/dashboard/public/assets/RedisPage-_GeS2OD8.js +1 -0
- package/dist/dashboard/public/assets/RequestsPage-BCwqu9US.js +1 -0
- package/dist/dashboard/public/assets/SchedulePage-CR0P-oX6.js +1 -0
- package/dist/dashboard/public/assets/ViewsPage-Dsy5ECRA.js +1 -0
- package/dist/dashboard/public/assets/calendar-DfK3x-6B.js +6 -0
- package/dist/dashboard/public/assets/circle-check-big-DcsYW8y8.js +6 -0
- package/dist/dashboard/public/assets/format-BFldcnCk.js +1 -0
- package/dist/dashboard/public/assets/index-DmeA1maE.css +1 -0
- package/dist/dashboard/public/assets/index-rkbGYdU7.js +351 -0
- package/dist/dashboard/public/assets/types-Cldoe2db.js +1 -0
- package/dist/dashboard/public/assets/vendor-B2nVRih0.js +43 -0
- package/dist/dashboard/public/assets/zap-DqtRi0JM.js +6 -0
- package/dist/dashboard/public/index.html +15 -0
- package/dist/dashboard/public/nestlens-icon.svg +9 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/nestlens.config.d.ts +216 -0
- package/dist/nestlens.config.d.ts.map +1 -0
- package/dist/nestlens.config.js +57 -0
- package/dist/nestlens.config.js.map +1 -0
- package/dist/nestlens.module.d.ts +10 -0
- package/dist/nestlens.module.d.ts.map +1 -0
- package/dist/nestlens.module.js +211 -0
- package/dist/nestlens.module.js.map +1 -0
- package/dist/types/entry.types.d.ts +368 -0
- package/dist/types/entry.types.d.ts.map +1 -0
- package/dist/types/entry.types.js +3 -0
- package/dist/types/entry.types.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +20 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/request.types.d.ts +9 -0
- package/dist/types/request.types.d.ts.map +1 -0
- package/dist/types/request.types.js +3 -0
- package/dist/types/request.types.js.map +1 -0
- package/dist/types/tag.types.d.ts +32 -0
- package/dist/types/tag.types.d.ts.map +1 -0
- package/dist/types/tag.types.js +3 -0
- package/dist/types/tag.types.js.map +1 -0
- package/dist/watchers/batch.watcher.d.ts +48 -0
- package/dist/watchers/batch.watcher.d.ts.map +1 -0
- package/dist/watchers/batch.watcher.js +185 -0
- package/dist/watchers/batch.watcher.js.map +1 -0
- package/dist/watchers/cache.watcher.d.ts +19 -0
- package/dist/watchers/cache.watcher.d.ts.map +1 -0
- package/dist/watchers/cache.watcher.js +158 -0
- package/dist/watchers/cache.watcher.js.map +1 -0
- package/dist/watchers/command.watcher.d.ts +32 -0
- package/dist/watchers/command.watcher.d.ts.map +1 -0
- package/dist/watchers/command.watcher.js +174 -0
- package/dist/watchers/command.watcher.js.map +1 -0
- package/dist/watchers/dump.watcher.d.ts +52 -0
- package/dist/watchers/dump.watcher.d.ts.map +1 -0
- package/dist/watchers/dump.watcher.js +234 -0
- package/dist/watchers/dump.watcher.js.map +1 -0
- package/dist/watchers/event.watcher.d.ts +20 -0
- package/dist/watchers/event.watcher.d.ts.map +1 -0
- package/dist/watchers/event.watcher.js +123 -0
- package/dist/watchers/event.watcher.js.map +1 -0
- package/dist/watchers/exception.watcher.d.ts +15 -0
- package/dist/watchers/exception.watcher.d.ts.map +1 -0
- package/dist/watchers/exception.watcher.js +117 -0
- package/dist/watchers/exception.watcher.js.map +1 -0
- package/dist/watchers/gate.watcher.d.ts +40 -0
- package/dist/watchers/gate.watcher.d.ts.map +1 -0
- package/dist/watchers/gate.watcher.js +200 -0
- package/dist/watchers/gate.watcher.js.map +1 -0
- package/dist/watchers/http-client.watcher.d.ts +34 -0
- package/dist/watchers/http-client.watcher.d.ts.map +1 -0
- package/dist/watchers/http-client.watcher.js +259 -0
- package/dist/watchers/http-client.watcher.js.map +1 -0
- package/dist/watchers/index.d.ts +19 -0
- package/dist/watchers/index.d.ts.map +1 -0
- package/dist/watchers/index.js +35 -0
- package/dist/watchers/index.js.map +1 -0
- package/dist/watchers/job.watcher.d.ts +27 -0
- package/dist/watchers/job.watcher.d.ts.map +1 -0
- package/dist/watchers/job.watcher.js +190 -0
- package/dist/watchers/job.watcher.js.map +1 -0
- package/dist/watchers/log.watcher.d.ts +26 -0
- package/dist/watchers/log.watcher.d.ts.map +1 -0
- package/dist/watchers/log.watcher.js +122 -0
- package/dist/watchers/log.watcher.js.map +1 -0
- package/dist/watchers/mail.watcher.d.ts +26 -0
- package/dist/watchers/mail.watcher.d.ts.map +1 -0
- package/dist/watchers/mail.watcher.js +154 -0
- package/dist/watchers/mail.watcher.js.map +1 -0
- package/dist/watchers/model.watcher.d.ts +54 -0
- package/dist/watchers/model.watcher.d.ts.map +1 -0
- package/dist/watchers/model.watcher.js +343 -0
- package/dist/watchers/model.watcher.js.map +1 -0
- package/dist/watchers/notification.watcher.d.ts +48 -0
- package/dist/watchers/notification.watcher.d.ts.map +1 -0
- package/dist/watchers/notification.watcher.js +215 -0
- package/dist/watchers/notification.watcher.js.map +1 -0
- package/dist/watchers/query/index.d.ts +3 -0
- package/dist/watchers/query/index.d.ts.map +1 -0
- package/dist/watchers/query/index.js +19 -0
- package/dist/watchers/query/index.js.map +1 -0
- package/dist/watchers/query/query.watcher.d.ts +27 -0
- package/dist/watchers/query/query.watcher.d.ts.map +1 -0
- package/dist/watchers/query/query.watcher.js +167 -0
- package/dist/watchers/query/query.watcher.js.map +1 -0
- package/dist/watchers/query/types.d.ts +60 -0
- package/dist/watchers/query/types.d.ts.map +1 -0
- package/dist/watchers/query/types.js +55 -0
- package/dist/watchers/query/types.js.map +1 -0
- package/dist/watchers/redis.watcher.d.ts +43 -0
- package/dist/watchers/redis.watcher.d.ts.map +1 -0
- package/dist/watchers/redis.watcher.js +225 -0
- package/dist/watchers/redis.watcher.js.map +1 -0
- package/dist/watchers/request.watcher.d.ts +21 -0
- package/dist/watchers/request.watcher.d.ts.map +1 -0
- package/dist/watchers/request.watcher.js +287 -0
- package/dist/watchers/request.watcher.js.map +1 -0
- package/dist/watchers/schedule.watcher.d.ts +25 -0
- package/dist/watchers/schedule.watcher.d.ts.map +1 -0
- package/dist/watchers/schedule.watcher.js +168 -0
- package/dist/watchers/schedule.watcher.js.map +1 -0
- package/dist/watchers/view.watcher.d.ts +51 -0
- package/dist/watchers/view.watcher.d.ts.map +1 -0
- package/dist/watchers/view.watcher.js +219 -0
- package/dist/watchers/view.watcher.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,853 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* SqliteStorage Tests
|
|
5
|
+
*
|
|
6
|
+
* Tests for SQLite-based entry storage.
|
|
7
|
+
* Follows AAA (Arrange-Act-Assert) pattern.
|
|
8
|
+
*/
|
|
9
|
+
const sqlite_storage_1 = require("../../../core/storage/sqlite.storage");
|
|
10
|
+
describe('SqliteStorage', () => {
|
|
11
|
+
let storage;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
// Create storage with in-memory database for testing
|
|
14
|
+
storage = new sqlite_storage_1.SqliteStorage(':memory:');
|
|
15
|
+
});
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
if (storage) {
|
|
18
|
+
await storage.onModuleDestroy();
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// save
|
|
23
|
+
// ============================================================================
|
|
24
|
+
describe('save', () => {
|
|
25
|
+
it('should save a request entry', async () => {
|
|
26
|
+
// Arrange
|
|
27
|
+
const entry = {
|
|
28
|
+
type: 'request',
|
|
29
|
+
requestId: 'req-123',
|
|
30
|
+
payload: {
|
|
31
|
+
method: 'GET',
|
|
32
|
+
url: '/api/users',
|
|
33
|
+
path: '/api/users',
|
|
34
|
+
query: {},
|
|
35
|
+
params: {},
|
|
36
|
+
headers: {},
|
|
37
|
+
statusCode: 200,
|
|
38
|
+
duration: 50,
|
|
39
|
+
memory: 1024,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
// Act
|
|
43
|
+
const result = await storage.save(entry);
|
|
44
|
+
// Assert
|
|
45
|
+
expect(result.id).toBeDefined();
|
|
46
|
+
expect(result.type).toBe('request');
|
|
47
|
+
expect(result.createdAt).toBeDefined();
|
|
48
|
+
});
|
|
49
|
+
it('should save a query entry', async () => {
|
|
50
|
+
// Arrange
|
|
51
|
+
const entry = {
|
|
52
|
+
type: 'query',
|
|
53
|
+
requestId: 'req-123',
|
|
54
|
+
payload: {
|
|
55
|
+
query: 'SELECT * FROM users',
|
|
56
|
+
duration: 10,
|
|
57
|
+
slow: false,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
// Act
|
|
61
|
+
const result = await storage.save(entry);
|
|
62
|
+
// Assert
|
|
63
|
+
expect(result.id).toBeDefined();
|
|
64
|
+
expect(result.type).toBe('query');
|
|
65
|
+
});
|
|
66
|
+
it('should save an exception entry', async () => {
|
|
67
|
+
// Arrange
|
|
68
|
+
const entry = {
|
|
69
|
+
type: 'exception',
|
|
70
|
+
requestId: 'req-123',
|
|
71
|
+
payload: {
|
|
72
|
+
name: 'Error',
|
|
73
|
+
message: 'Something went wrong',
|
|
74
|
+
stack: 'Error: Something went wrong\n at test.ts:10',
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
// Act
|
|
78
|
+
const result = await storage.save(entry);
|
|
79
|
+
// Assert
|
|
80
|
+
expect(result.id).toBeDefined();
|
|
81
|
+
expect(result.type).toBe('exception');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// saveBatch
|
|
86
|
+
// ============================================================================
|
|
87
|
+
describe('saveBatch', () => {
|
|
88
|
+
it('should save multiple entries in a batch', async () => {
|
|
89
|
+
// Arrange
|
|
90
|
+
const entries = [
|
|
91
|
+
{
|
|
92
|
+
type: 'request',
|
|
93
|
+
requestId: 'req-1',
|
|
94
|
+
payload: { method: 'GET', url: '/api/1', path: '/api/1', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: 'request',
|
|
98
|
+
requestId: 'req-2',
|
|
99
|
+
payload: { method: 'POST', url: '/api/2', path: '/api/2', query: {}, params: {}, headers: {}, statusCode: 201, duration: 100, memory: 2048 },
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
// Act
|
|
103
|
+
const result = await storage.saveBatch(entries);
|
|
104
|
+
// Assert
|
|
105
|
+
expect(result).toHaveLength(2);
|
|
106
|
+
expect(result[0].id).toBeDefined();
|
|
107
|
+
expect(result[1].id).toBeDefined();
|
|
108
|
+
expect(result[0].id).not.toBe(result[1].id);
|
|
109
|
+
});
|
|
110
|
+
it('should handle empty batch', async () => {
|
|
111
|
+
// Arrange
|
|
112
|
+
const entries = [];
|
|
113
|
+
// Act
|
|
114
|
+
const result = await storage.saveBatch(entries);
|
|
115
|
+
// Assert
|
|
116
|
+
expect(result).toHaveLength(0);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
// ============================================================================
|
|
120
|
+
// find
|
|
121
|
+
// ============================================================================
|
|
122
|
+
describe('find', () => {
|
|
123
|
+
it('should find entries by type', async () => {
|
|
124
|
+
// Arrange
|
|
125
|
+
await storage.save({
|
|
126
|
+
type: 'request',
|
|
127
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
128
|
+
});
|
|
129
|
+
await storage.save({
|
|
130
|
+
type: 'query',
|
|
131
|
+
payload: { query: 'SELECT 1', duration: 5, slow: false },
|
|
132
|
+
});
|
|
133
|
+
// Act
|
|
134
|
+
const result = await storage.find({ type: 'request' });
|
|
135
|
+
// Assert
|
|
136
|
+
expect(result).toHaveLength(1);
|
|
137
|
+
expect(result[0].type).toBe('request');
|
|
138
|
+
});
|
|
139
|
+
it('should find entries by requestId', async () => {
|
|
140
|
+
// Arrange
|
|
141
|
+
await storage.save({
|
|
142
|
+
type: 'request',
|
|
143
|
+
requestId: 'req-123',
|
|
144
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
145
|
+
});
|
|
146
|
+
await storage.save({
|
|
147
|
+
type: 'request',
|
|
148
|
+
requestId: 'req-456',
|
|
149
|
+
payload: { method: 'POST', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
150
|
+
});
|
|
151
|
+
// Act
|
|
152
|
+
const result = await storage.find({ requestId: 'req-123' });
|
|
153
|
+
// Assert
|
|
154
|
+
expect(result).toHaveLength(1);
|
|
155
|
+
expect(result[0].requestId).toBe('req-123');
|
|
156
|
+
});
|
|
157
|
+
it('should find entries with limit', async () => {
|
|
158
|
+
// Arrange
|
|
159
|
+
for (let i = 0; i < 5; i++) {
|
|
160
|
+
await storage.save({
|
|
161
|
+
type: 'request',
|
|
162
|
+
payload: { method: 'GET', url: `/api/${i}`, path: `/api/${i}`, query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
// Act
|
|
166
|
+
const result = await storage.find({ limit: 3 });
|
|
167
|
+
// Assert
|
|
168
|
+
expect(result).toHaveLength(3);
|
|
169
|
+
});
|
|
170
|
+
it('should find entries with limit and offset', async () => {
|
|
171
|
+
// Arrange
|
|
172
|
+
for (let i = 0; i < 5; i++) {
|
|
173
|
+
await storage.save({
|
|
174
|
+
type: 'request',
|
|
175
|
+
payload: { method: 'GET', url: `/api/${i}`, path: `/api/${i}`, query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// Act - SQLite requires LIMIT when using OFFSET
|
|
179
|
+
const result = await storage.find({ limit: 100, offset: 2 });
|
|
180
|
+
// Assert
|
|
181
|
+
expect(result).toHaveLength(3);
|
|
182
|
+
});
|
|
183
|
+
it('should find entries by date range', async () => {
|
|
184
|
+
// Arrange
|
|
185
|
+
await storage.save({
|
|
186
|
+
type: 'request',
|
|
187
|
+
payload: { method: 'GET', url: '/old', path: '/old', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
188
|
+
});
|
|
189
|
+
// Act - use wide date range to ensure entry is included
|
|
190
|
+
const from = new Date(Date.now() - 24 * 60 * 60 * 1000); // 1 day ago
|
|
191
|
+
const to = new Date(Date.now() + 24 * 60 * 60 * 1000); // 1 day from now
|
|
192
|
+
const result = await storage.find({ from, to });
|
|
193
|
+
// Assert
|
|
194
|
+
expect(result).toHaveLength(1);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// findById
|
|
199
|
+
// ============================================================================
|
|
200
|
+
describe('findById', () => {
|
|
201
|
+
it('should find entry by id', async () => {
|
|
202
|
+
// Arrange
|
|
203
|
+
const saved = await storage.save({
|
|
204
|
+
type: 'request',
|
|
205
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
206
|
+
});
|
|
207
|
+
// Act
|
|
208
|
+
const result = await storage.findById(saved.id);
|
|
209
|
+
// Assert
|
|
210
|
+
expect(result).not.toBeNull();
|
|
211
|
+
expect(result?.id).toBe(saved.id);
|
|
212
|
+
});
|
|
213
|
+
it('should return null for non-existent id', async () => {
|
|
214
|
+
// Act
|
|
215
|
+
const result = await storage.findById(99999);
|
|
216
|
+
// Assert
|
|
217
|
+
expect(result).toBeNull();
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// count
|
|
222
|
+
// ============================================================================
|
|
223
|
+
describe('count', () => {
|
|
224
|
+
it('should count all entries', async () => {
|
|
225
|
+
// Arrange
|
|
226
|
+
await storage.save({ type: 'request', payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 } });
|
|
227
|
+
await storage.save({ type: 'query', payload: { query: 'SELECT 1', duration: 5, slow: false } });
|
|
228
|
+
// Act
|
|
229
|
+
const result = await storage.count();
|
|
230
|
+
// Assert
|
|
231
|
+
expect(result).toBe(2);
|
|
232
|
+
});
|
|
233
|
+
it('should count entries by type', async () => {
|
|
234
|
+
// Arrange
|
|
235
|
+
await storage.save({ type: 'request', payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 } });
|
|
236
|
+
await storage.save({ type: 'request', payload: { method: 'POST', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 201, duration: 100, memory: 2048 } });
|
|
237
|
+
await storage.save({ type: 'query', payload: { query: 'SELECT 1', duration: 5, slow: false } });
|
|
238
|
+
// Act
|
|
239
|
+
const result = await storage.count('request');
|
|
240
|
+
// Assert
|
|
241
|
+
expect(result).toBe(2);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
// ============================================================================
|
|
245
|
+
// getStats
|
|
246
|
+
// ============================================================================
|
|
247
|
+
describe('getStats', () => {
|
|
248
|
+
it('should return stats for empty database', async () => {
|
|
249
|
+
// Act
|
|
250
|
+
const result = await storage.getStats();
|
|
251
|
+
// Assert
|
|
252
|
+
expect(result.total).toBe(0);
|
|
253
|
+
expect(result.byType).toEqual({});
|
|
254
|
+
expect(result.slowQueries).toBe(0);
|
|
255
|
+
expect(result.exceptions).toBe(0);
|
|
256
|
+
});
|
|
257
|
+
it('should return correct stats', async () => {
|
|
258
|
+
// Arrange
|
|
259
|
+
await storage.save({
|
|
260
|
+
type: 'request',
|
|
261
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 100, memory: 1024 },
|
|
262
|
+
});
|
|
263
|
+
await storage.save({
|
|
264
|
+
type: 'request',
|
|
265
|
+
payload: { method: 'POST', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 200, memory: 2048 },
|
|
266
|
+
});
|
|
267
|
+
await storage.save({
|
|
268
|
+
type: 'query',
|
|
269
|
+
payload: { query: 'SELECT 1', duration: 5, slow: true },
|
|
270
|
+
});
|
|
271
|
+
await storage.save({
|
|
272
|
+
type: 'exception',
|
|
273
|
+
payload: { name: 'Error', message: 'Test error', stack: '' },
|
|
274
|
+
});
|
|
275
|
+
// Act
|
|
276
|
+
const result = await storage.getStats();
|
|
277
|
+
// Assert
|
|
278
|
+
expect(result.total).toBe(4);
|
|
279
|
+
expect(result.byType.request).toBe(2);
|
|
280
|
+
expect(result.byType.query).toBe(1);
|
|
281
|
+
expect(result.byType.exception).toBe(1);
|
|
282
|
+
expect(result.slowQueries).toBe(1);
|
|
283
|
+
expect(result.exceptions).toBe(1);
|
|
284
|
+
expect(result.avgResponseTime).toBeDefined();
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
// ============================================================================
|
|
288
|
+
// prune
|
|
289
|
+
// ============================================================================
|
|
290
|
+
describe('prune', () => {
|
|
291
|
+
it('should prune entries before date', async () => {
|
|
292
|
+
// Arrange
|
|
293
|
+
await storage.save({
|
|
294
|
+
type: 'request',
|
|
295
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
296
|
+
});
|
|
297
|
+
// Act
|
|
298
|
+
const before = new Date(Date.now() + 10000); // Future date to delete all
|
|
299
|
+
const deleted = await storage.prune(before);
|
|
300
|
+
// Assert
|
|
301
|
+
expect(deleted).toBe(1);
|
|
302
|
+
const count = await storage.count();
|
|
303
|
+
expect(count).toBe(0);
|
|
304
|
+
});
|
|
305
|
+
it('should not prune entries after date', async () => {
|
|
306
|
+
// Arrange
|
|
307
|
+
await storage.save({
|
|
308
|
+
type: 'request',
|
|
309
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
310
|
+
});
|
|
311
|
+
// Act - use a date from yesterday to ensure entry is definitely after it
|
|
312
|
+
const before = new Date(Date.now() - 24 * 60 * 60 * 1000); // 1 day ago
|
|
313
|
+
const deleted = await storage.prune(before);
|
|
314
|
+
// Assert
|
|
315
|
+
expect(deleted).toBe(0);
|
|
316
|
+
const count = await storage.count();
|
|
317
|
+
expect(count).toBe(1);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
// ============================================================================
|
|
321
|
+
// pruneByType
|
|
322
|
+
// ============================================================================
|
|
323
|
+
describe('pruneByType', () => {
|
|
324
|
+
it('should prune entries by type', async () => {
|
|
325
|
+
// Arrange
|
|
326
|
+
await storage.save({
|
|
327
|
+
type: 'request',
|
|
328
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
329
|
+
});
|
|
330
|
+
await storage.save({
|
|
331
|
+
type: 'query',
|
|
332
|
+
payload: { query: 'SELECT 1', duration: 5, slow: false },
|
|
333
|
+
});
|
|
334
|
+
// Act
|
|
335
|
+
const before = new Date(Date.now() + 10000);
|
|
336
|
+
const deleted = await storage.pruneByType('request', before);
|
|
337
|
+
// Assert
|
|
338
|
+
expect(deleted).toBe(1);
|
|
339
|
+
const requestCount = await storage.count('request');
|
|
340
|
+
const queryCount = await storage.count('query');
|
|
341
|
+
expect(requestCount).toBe(0);
|
|
342
|
+
expect(queryCount).toBe(1);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
// ============================================================================
|
|
346
|
+
// clear
|
|
347
|
+
// ============================================================================
|
|
348
|
+
describe('clear', () => {
|
|
349
|
+
it('should clear all entries', async () => {
|
|
350
|
+
// Arrange
|
|
351
|
+
await storage.save({ type: 'request', payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 } });
|
|
352
|
+
await storage.save({ type: 'query', payload: { query: 'SELECT 1', duration: 5, slow: false } });
|
|
353
|
+
// Act
|
|
354
|
+
await storage.clear();
|
|
355
|
+
// Assert
|
|
356
|
+
const count = await storage.count();
|
|
357
|
+
expect(count).toBe(0);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
// ============================================================================
|
|
361
|
+
// updateFamilyHash
|
|
362
|
+
// ============================================================================
|
|
363
|
+
describe('updateFamilyHash', () => {
|
|
364
|
+
it('should update family hash', async () => {
|
|
365
|
+
// Arrange
|
|
366
|
+
const saved = await storage.save({
|
|
367
|
+
type: 'exception',
|
|
368
|
+
payload: { name: 'Error', message: 'Test', stack: '' },
|
|
369
|
+
});
|
|
370
|
+
// Act
|
|
371
|
+
await storage.updateFamilyHash(saved.id, 'hash-123');
|
|
372
|
+
const result = await storage.findById(saved.id);
|
|
373
|
+
// Assert
|
|
374
|
+
expect(result?.familyHash).toBe('hash-123');
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
// ============================================================================
|
|
378
|
+
// resolveException
|
|
379
|
+
// ============================================================================
|
|
380
|
+
describe('resolveEntry', () => {
|
|
381
|
+
it('should mark entry as resolved', async () => {
|
|
382
|
+
// Arrange
|
|
383
|
+
const saved = await storage.save({
|
|
384
|
+
type: 'exception',
|
|
385
|
+
payload: { name: 'Error', message: 'Test', stack: '' },
|
|
386
|
+
});
|
|
387
|
+
// Act
|
|
388
|
+
await storage.resolveEntry(saved.id);
|
|
389
|
+
const result = await storage.findById(saved.id);
|
|
390
|
+
// Assert
|
|
391
|
+
expect(result?.resolvedAt).toBeDefined();
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
// ============================================================================
|
|
395
|
+
// Tags
|
|
396
|
+
// ============================================================================
|
|
397
|
+
describe('tags', () => {
|
|
398
|
+
it('should add tags to entry', async () => {
|
|
399
|
+
// Arrange
|
|
400
|
+
const saved = await storage.save({
|
|
401
|
+
type: 'request',
|
|
402
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
403
|
+
});
|
|
404
|
+
// Act
|
|
405
|
+
await storage.addTags(saved.id, ['tag1', 'tag2']);
|
|
406
|
+
const result = await storage.findById(saved.id);
|
|
407
|
+
// Assert
|
|
408
|
+
expect(result?.tags).toContain('tag1');
|
|
409
|
+
expect(result?.tags).toContain('tag2');
|
|
410
|
+
});
|
|
411
|
+
it('should remove tags from entry', async () => {
|
|
412
|
+
// Arrange
|
|
413
|
+
const saved = await storage.save({
|
|
414
|
+
type: 'request',
|
|
415
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
416
|
+
});
|
|
417
|
+
await storage.addTags(saved.id, ['tag1', 'tag2', 'tag3']);
|
|
418
|
+
// Act
|
|
419
|
+
await storage.removeTags(saved.id, ['tag2']);
|
|
420
|
+
const result = await storage.findById(saved.id);
|
|
421
|
+
// Assert
|
|
422
|
+
expect(result?.tags).toContain('tag1');
|
|
423
|
+
expect(result?.tags).not.toContain('tag2');
|
|
424
|
+
expect(result?.tags).toContain('tag3');
|
|
425
|
+
});
|
|
426
|
+
it('should get tags for entry', async () => {
|
|
427
|
+
// Arrange
|
|
428
|
+
const saved = await storage.save({
|
|
429
|
+
type: 'request',
|
|
430
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
431
|
+
});
|
|
432
|
+
await storage.addTags(saved.id, ['alpha', 'beta']);
|
|
433
|
+
// Act
|
|
434
|
+
const tags = await storage.getEntryTags(saved.id);
|
|
435
|
+
// Assert
|
|
436
|
+
expect(tags).toContain('alpha');
|
|
437
|
+
expect(tags).toContain('beta');
|
|
438
|
+
});
|
|
439
|
+
it('should get all unique tags with counts', async () => {
|
|
440
|
+
// Arrange
|
|
441
|
+
const entry1 = await storage.save({
|
|
442
|
+
type: 'request',
|
|
443
|
+
payload: { method: 'GET', url: '/api/1', path: '/api/1', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
444
|
+
});
|
|
445
|
+
const entry2 = await storage.save({
|
|
446
|
+
type: 'request',
|
|
447
|
+
payload: { method: 'GET', url: '/api/2', path: '/api/2', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
448
|
+
});
|
|
449
|
+
await storage.addTags(entry1.id, ['common', 'unique1']);
|
|
450
|
+
await storage.addTags(entry2.id, ['common', 'unique2']);
|
|
451
|
+
// Act
|
|
452
|
+
const allTags = await storage.getAllTags();
|
|
453
|
+
// Assert - returns TagWithCount objects
|
|
454
|
+
const tagNames = allTags.map((t) => t.tag);
|
|
455
|
+
expect(tagNames).toContain('common');
|
|
456
|
+
expect(tagNames).toContain('unique1');
|
|
457
|
+
expect(tagNames).toContain('unique2');
|
|
458
|
+
// 'common' should have count of 2
|
|
459
|
+
const commonTag = allTags.find((t) => t.tag === 'common');
|
|
460
|
+
expect(commonTag?.count).toBe(2);
|
|
461
|
+
});
|
|
462
|
+
it('should find entries by tags', async () => {
|
|
463
|
+
// Arrange
|
|
464
|
+
const entry1 = await storage.save({
|
|
465
|
+
type: 'request',
|
|
466
|
+
payload: { method: 'GET', url: '/api/1', path: '/api/1', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
467
|
+
});
|
|
468
|
+
const entry2 = await storage.save({
|
|
469
|
+
type: 'request',
|
|
470
|
+
payload: { method: 'GET', url: '/api/2', path: '/api/2', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
471
|
+
});
|
|
472
|
+
await storage.addTags(entry1.id, ['important']);
|
|
473
|
+
await storage.addTags(entry2.id, ['normal']);
|
|
474
|
+
// Act
|
|
475
|
+
const results = await storage.findByTags(['important']);
|
|
476
|
+
// Assert
|
|
477
|
+
expect(results).toHaveLength(1);
|
|
478
|
+
expect(results[0].id).toBe(entry1.id);
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
// ============================================================================
|
|
482
|
+
// Pagination
|
|
483
|
+
// ============================================================================
|
|
484
|
+
describe('pagination', () => {
|
|
485
|
+
it('should get entries with cursor pagination', async () => {
|
|
486
|
+
// Arrange
|
|
487
|
+
for (let i = 0; i < 10; i++) {
|
|
488
|
+
await storage.save({
|
|
489
|
+
type: 'request',
|
|
490
|
+
payload: { method: 'GET', url: `/api/${i}`, path: `/api/${i}`, query: {}, params: {}, headers: {}, statusCode: 200, duration: 50 + i, memory: 1024 },
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
// Act
|
|
494
|
+
const result = await storage.findWithCursor('request', { limit: 5 });
|
|
495
|
+
// Assert
|
|
496
|
+
expect(result.data).toHaveLength(5);
|
|
497
|
+
expect(result.meta.hasMore).toBe(true);
|
|
498
|
+
expect(result.meta.total).toBe(10);
|
|
499
|
+
});
|
|
500
|
+
it('should get next page with cursor', async () => {
|
|
501
|
+
// Arrange
|
|
502
|
+
for (let i = 0; i < 10; i++) {
|
|
503
|
+
await storage.save({
|
|
504
|
+
type: 'request',
|
|
505
|
+
payload: { method: 'GET', url: `/api/${i}`, path: `/api/${i}`, query: {}, params: {}, headers: {}, statusCode: 200, duration: 50 + i, memory: 1024 },
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
// Act
|
|
509
|
+
const firstPage = await storage.findWithCursor('request', { limit: 5 });
|
|
510
|
+
const secondPage = await storage.findWithCursor('request', {
|
|
511
|
+
limit: 5,
|
|
512
|
+
beforeSequence: firstPage.meta.oldestSequence ?? undefined,
|
|
513
|
+
});
|
|
514
|
+
// Assert
|
|
515
|
+
expect(secondPage.data).toHaveLength(5);
|
|
516
|
+
expect(secondPage.meta.hasMore).toBe(false);
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
// ============================================================================
|
|
520
|
+
// getLatestSequence
|
|
521
|
+
// ============================================================================
|
|
522
|
+
describe('getLatestSequence', () => {
|
|
523
|
+
it('should return null for empty database', async () => {
|
|
524
|
+
// Act
|
|
525
|
+
const result = await storage.getLatestSequence();
|
|
526
|
+
// Assert
|
|
527
|
+
expect(result).toBeNull();
|
|
528
|
+
});
|
|
529
|
+
it('should return latest sequence id', async () => {
|
|
530
|
+
// Arrange
|
|
531
|
+
await storage.save({
|
|
532
|
+
type: 'request',
|
|
533
|
+
payload: { method: 'GET', url: '/api/1', path: '/api/1', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
534
|
+
});
|
|
535
|
+
const second = await storage.save({
|
|
536
|
+
type: 'request',
|
|
537
|
+
payload: { method: 'GET', url: '/api/2', path: '/api/2', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
538
|
+
});
|
|
539
|
+
// Act
|
|
540
|
+
const result = await storage.getLatestSequence();
|
|
541
|
+
// Assert
|
|
542
|
+
expect(result).toBe(second.id);
|
|
543
|
+
});
|
|
544
|
+
it('should return latest sequence by type', async () => {
|
|
545
|
+
// Arrange
|
|
546
|
+
await storage.save({
|
|
547
|
+
type: 'request',
|
|
548
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
549
|
+
});
|
|
550
|
+
const query = await storage.save({
|
|
551
|
+
type: 'query',
|
|
552
|
+
payload: { query: 'SELECT 1', duration: 5, slow: false },
|
|
553
|
+
});
|
|
554
|
+
// Act
|
|
555
|
+
const result = await storage.getLatestSequence('query');
|
|
556
|
+
// Assert
|
|
557
|
+
expect(result).toBe(query.id);
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
// ============================================================================
|
|
561
|
+
// hasEntriesAfter
|
|
562
|
+
// ============================================================================
|
|
563
|
+
describe('hasEntriesAfter', () => {
|
|
564
|
+
it('should return 0 when no entries after sequence', async () => {
|
|
565
|
+
// Arrange
|
|
566
|
+
const entry = await storage.save({
|
|
567
|
+
type: 'request',
|
|
568
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
569
|
+
});
|
|
570
|
+
// Act
|
|
571
|
+
const result = await storage.hasEntriesAfter(entry.id);
|
|
572
|
+
// Assert
|
|
573
|
+
expect(result).toBe(0);
|
|
574
|
+
});
|
|
575
|
+
it('should return count of entries after sequence', async () => {
|
|
576
|
+
// Arrange
|
|
577
|
+
const first = await storage.save({
|
|
578
|
+
type: 'request',
|
|
579
|
+
payload: { method: 'GET', url: '/api/1', path: '/api/1', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
580
|
+
});
|
|
581
|
+
await storage.save({
|
|
582
|
+
type: 'request',
|
|
583
|
+
payload: { method: 'GET', url: '/api/2', path: '/api/2', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
584
|
+
});
|
|
585
|
+
await storage.save({
|
|
586
|
+
type: 'request',
|
|
587
|
+
payload: { method: 'GET', url: '/api/3', path: '/api/3', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
588
|
+
});
|
|
589
|
+
// Act
|
|
590
|
+
const result = await storage.hasEntriesAfter(first.id);
|
|
591
|
+
// Assert
|
|
592
|
+
expect(result).toBe(2);
|
|
593
|
+
});
|
|
594
|
+
it('should filter by type when counting entries after', async () => {
|
|
595
|
+
// Arrange
|
|
596
|
+
const first = await storage.save({
|
|
597
|
+
type: 'request',
|
|
598
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
599
|
+
});
|
|
600
|
+
await storage.save({
|
|
601
|
+
type: 'query',
|
|
602
|
+
payload: { query: 'SELECT 1', duration: 5, slow: false },
|
|
603
|
+
});
|
|
604
|
+
await storage.save({
|
|
605
|
+
type: 'request',
|
|
606
|
+
payload: { method: 'POST', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 201, duration: 100, memory: 2048 },
|
|
607
|
+
});
|
|
608
|
+
// Act
|
|
609
|
+
const result = await storage.hasEntriesAfter(first.id, 'request');
|
|
610
|
+
// Assert
|
|
611
|
+
expect(result).toBe(1);
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
// ============================================================================
|
|
615
|
+
// getStorageStats
|
|
616
|
+
// ============================================================================
|
|
617
|
+
describe('getStorageStats', () => {
|
|
618
|
+
it('should return stats for empty database', async () => {
|
|
619
|
+
// Act
|
|
620
|
+
const result = await storage.getStorageStats();
|
|
621
|
+
// Assert
|
|
622
|
+
expect(result.total).toBe(0);
|
|
623
|
+
expect(result.byType).toEqual({});
|
|
624
|
+
expect(result.oldestEntry).toBeNull();
|
|
625
|
+
expect(result.newestEntry).toBeNull();
|
|
626
|
+
});
|
|
627
|
+
it('should return correct storage stats', async () => {
|
|
628
|
+
// Arrange
|
|
629
|
+
await storage.save({
|
|
630
|
+
type: 'request',
|
|
631
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
632
|
+
});
|
|
633
|
+
await storage.save({
|
|
634
|
+
type: 'query',
|
|
635
|
+
payload: { query: 'SELECT 1', duration: 5, slow: false },
|
|
636
|
+
});
|
|
637
|
+
// Act
|
|
638
|
+
const result = await storage.getStorageStats();
|
|
639
|
+
// Assert
|
|
640
|
+
expect(result.total).toBe(2);
|
|
641
|
+
expect(result.byType.request).toBe(1);
|
|
642
|
+
expect(result.byType.query).toBe(1);
|
|
643
|
+
expect(result.oldestEntry).toBeDefined();
|
|
644
|
+
expect(result.newestEntry).toBeDefined();
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
// ============================================================================
|
|
648
|
+
// Monitored Tags
|
|
649
|
+
// ============================================================================
|
|
650
|
+
describe('monitored tags', () => {
|
|
651
|
+
it('should add monitored tag', async () => {
|
|
652
|
+
// Act
|
|
653
|
+
const result = await storage.addMonitoredTag('important');
|
|
654
|
+
// Assert
|
|
655
|
+
expect(result.id).toBeDefined();
|
|
656
|
+
expect(result.tag).toBe('important');
|
|
657
|
+
expect(result.createdAt).toBeDefined();
|
|
658
|
+
});
|
|
659
|
+
it('should get all monitored tags', async () => {
|
|
660
|
+
// Arrange
|
|
661
|
+
await storage.addMonitoredTag('alpha');
|
|
662
|
+
await storage.addMonitoredTag('beta');
|
|
663
|
+
// Act
|
|
664
|
+
const result = await storage.getMonitoredTags();
|
|
665
|
+
// Assert
|
|
666
|
+
expect(result).toHaveLength(2);
|
|
667
|
+
expect(result.map(t => t.tag)).toContain('alpha');
|
|
668
|
+
expect(result.map(t => t.tag)).toContain('beta');
|
|
669
|
+
});
|
|
670
|
+
it('should remove monitored tag', async () => {
|
|
671
|
+
// Arrange
|
|
672
|
+
await storage.addMonitoredTag('temp');
|
|
673
|
+
await storage.addMonitoredTag('keep');
|
|
674
|
+
// Act
|
|
675
|
+
await storage.removeMonitoredTag('temp');
|
|
676
|
+
const result = await storage.getMonitoredTags();
|
|
677
|
+
// Assert
|
|
678
|
+
expect(result).toHaveLength(1);
|
|
679
|
+
expect(result[0].tag).toBe('keep');
|
|
680
|
+
});
|
|
681
|
+
it('should handle duplicate monitored tags', async () => {
|
|
682
|
+
// Arrange & Act
|
|
683
|
+
await storage.addMonitoredTag('duplicate');
|
|
684
|
+
await storage.addMonitoredTag('duplicate');
|
|
685
|
+
const result = await storage.getMonitoredTags();
|
|
686
|
+
// Assert - should only have one
|
|
687
|
+
expect(result).toHaveLength(1);
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
// ============================================================================
|
|
691
|
+
// unresolveEntry
|
|
692
|
+
// ============================================================================
|
|
693
|
+
describe('unresolveEntry', () => {
|
|
694
|
+
it('should unresolve a resolved entry', async () => {
|
|
695
|
+
// Arrange
|
|
696
|
+
const saved = await storage.save({
|
|
697
|
+
type: 'exception',
|
|
698
|
+
payload: { name: 'Error', message: 'Test', stack: '' },
|
|
699
|
+
});
|
|
700
|
+
await storage.resolveEntry(saved.id);
|
|
701
|
+
// Act
|
|
702
|
+
await storage.unresolveEntry(saved.id);
|
|
703
|
+
const result = await storage.findById(saved.id);
|
|
704
|
+
// Assert
|
|
705
|
+
expect(result?.resolvedAt).toBeUndefined();
|
|
706
|
+
});
|
|
707
|
+
});
|
|
708
|
+
// ============================================================================
|
|
709
|
+
// findByFamilyHash
|
|
710
|
+
// ============================================================================
|
|
711
|
+
describe('findByFamilyHash', () => {
|
|
712
|
+
it('should find entries by family hash', async () => {
|
|
713
|
+
// Arrange
|
|
714
|
+
const entry1 = await storage.save({
|
|
715
|
+
type: 'exception',
|
|
716
|
+
payload: { name: 'Error', message: 'Test 1', stack: '' },
|
|
717
|
+
});
|
|
718
|
+
const entry2 = await storage.save({
|
|
719
|
+
type: 'exception',
|
|
720
|
+
payload: { name: 'Error', message: 'Test 2', stack: '' },
|
|
721
|
+
});
|
|
722
|
+
await storage.save({
|
|
723
|
+
type: 'exception',
|
|
724
|
+
payload: { name: 'Error', message: 'Different', stack: '' },
|
|
725
|
+
});
|
|
726
|
+
await storage.updateFamilyHash(entry1.id, 'hash-abc');
|
|
727
|
+
await storage.updateFamilyHash(entry2.id, 'hash-abc');
|
|
728
|
+
// Act
|
|
729
|
+
const result = await storage.findByFamilyHash('hash-abc');
|
|
730
|
+
// Assert
|
|
731
|
+
expect(result).toHaveLength(2);
|
|
732
|
+
});
|
|
733
|
+
it('should return empty array for non-existent hash', async () => {
|
|
734
|
+
// Act
|
|
735
|
+
const result = await storage.findByFamilyHash('non-existent');
|
|
736
|
+
// Assert
|
|
737
|
+
expect(result).toHaveLength(0);
|
|
738
|
+
});
|
|
739
|
+
});
|
|
740
|
+
// ============================================================================
|
|
741
|
+
// getGroupedByFamilyHash
|
|
742
|
+
// ============================================================================
|
|
743
|
+
describe('getGroupedByFamilyHash', () => {
|
|
744
|
+
it('should return empty array when no family hashes', async () => {
|
|
745
|
+
// Arrange
|
|
746
|
+
await storage.save({
|
|
747
|
+
type: 'exception',
|
|
748
|
+
payload: { name: 'Error', message: 'Test', stack: '' },
|
|
749
|
+
});
|
|
750
|
+
// Act
|
|
751
|
+
const result = await storage.getGroupedByFamilyHash();
|
|
752
|
+
// Assert
|
|
753
|
+
expect(result).toHaveLength(0);
|
|
754
|
+
});
|
|
755
|
+
it('should group entries by family hash', async () => {
|
|
756
|
+
// Arrange
|
|
757
|
+
const entry1 = await storage.save({
|
|
758
|
+
type: 'exception',
|
|
759
|
+
payload: { name: 'Error', message: 'Test 1', stack: '' },
|
|
760
|
+
});
|
|
761
|
+
const entry2 = await storage.save({
|
|
762
|
+
type: 'exception',
|
|
763
|
+
payload: { name: 'Error', message: 'Test 2', stack: '' },
|
|
764
|
+
});
|
|
765
|
+
const entry3 = await storage.save({
|
|
766
|
+
type: 'exception',
|
|
767
|
+
payload: { name: 'Error', message: 'Test 3', stack: '' },
|
|
768
|
+
});
|
|
769
|
+
await storage.updateFamilyHash(entry1.id, 'hash-a');
|
|
770
|
+
await storage.updateFamilyHash(entry2.id, 'hash-a');
|
|
771
|
+
await storage.updateFamilyHash(entry3.id, 'hash-b');
|
|
772
|
+
// Act
|
|
773
|
+
const result = await storage.getGroupedByFamilyHash();
|
|
774
|
+
// Assert
|
|
775
|
+
expect(result).toHaveLength(2);
|
|
776
|
+
const hashA = result.find(r => r.familyHash === 'hash-a');
|
|
777
|
+
expect(hashA?.count).toBe(2);
|
|
778
|
+
const hashB = result.find(r => r.familyHash === 'hash-b');
|
|
779
|
+
expect(hashB?.count).toBe(1);
|
|
780
|
+
});
|
|
781
|
+
it('should filter by type when grouping', async () => {
|
|
782
|
+
// Arrange
|
|
783
|
+
const exc = await storage.save({
|
|
784
|
+
type: 'exception',
|
|
785
|
+
payload: { name: 'Error', message: 'Test', stack: '' },
|
|
786
|
+
});
|
|
787
|
+
const query = await storage.save({
|
|
788
|
+
type: 'query',
|
|
789
|
+
payload: { query: 'SELECT 1', duration: 5, slow: false },
|
|
790
|
+
});
|
|
791
|
+
await storage.updateFamilyHash(exc.id, 'hash-exc');
|
|
792
|
+
await storage.updateFamilyHash(query.id, 'hash-query');
|
|
793
|
+
// Act
|
|
794
|
+
const result = await storage.getGroupedByFamilyHash('exception');
|
|
795
|
+
// Assert
|
|
796
|
+
expect(result).toHaveLength(1);
|
|
797
|
+
expect(result[0].familyHash).toBe('hash-exc');
|
|
798
|
+
});
|
|
799
|
+
});
|
|
800
|
+
// ============================================================================
|
|
801
|
+
// findByTags with AND logic
|
|
802
|
+
// ============================================================================
|
|
803
|
+
describe('findByTags advanced', () => {
|
|
804
|
+
it('should return empty array when tags array is empty', async () => {
|
|
805
|
+
// Arrange
|
|
806
|
+
const entry = await storage.save({
|
|
807
|
+
type: 'request',
|
|
808
|
+
payload: { method: 'GET', url: '/api', path: '/api', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
809
|
+
});
|
|
810
|
+
await storage.addTags(entry.id, ['tag1']);
|
|
811
|
+
// Act
|
|
812
|
+
const result = await storage.findByTags([]);
|
|
813
|
+
// Assert
|
|
814
|
+
expect(result).toHaveLength(0);
|
|
815
|
+
});
|
|
816
|
+
it('should find entries with AND logic (all tags required)', async () => {
|
|
817
|
+
// Arrange
|
|
818
|
+
const entry1 = await storage.save({
|
|
819
|
+
type: 'request',
|
|
820
|
+
payload: { method: 'GET', url: '/api/1', path: '/api/1', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
821
|
+
});
|
|
822
|
+
const entry2 = await storage.save({
|
|
823
|
+
type: 'request',
|
|
824
|
+
payload: { method: 'GET', url: '/api/2', path: '/api/2', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
825
|
+
});
|
|
826
|
+
await storage.addTags(entry1.id, ['red', 'blue', 'green']);
|
|
827
|
+
await storage.addTags(entry2.id, ['red', 'blue']);
|
|
828
|
+
// Act - find entries with BOTH red and green
|
|
829
|
+
const result = await storage.findByTags(['red', 'green'], 'AND');
|
|
830
|
+
// Assert - only entry1 has both
|
|
831
|
+
expect(result).toHaveLength(1);
|
|
832
|
+
expect(result[0].id).toBe(entry1.id);
|
|
833
|
+
});
|
|
834
|
+
it('should find entries with OR logic (any tag)', async () => {
|
|
835
|
+
// Arrange
|
|
836
|
+
const entry1 = await storage.save({
|
|
837
|
+
type: 'request',
|
|
838
|
+
payload: { method: 'GET', url: '/api/1', path: '/api/1', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
839
|
+
});
|
|
840
|
+
const entry2 = await storage.save({
|
|
841
|
+
type: 'request',
|
|
842
|
+
payload: { method: 'GET', url: '/api/2', path: '/api/2', query: {}, params: {}, headers: {}, statusCode: 200, duration: 50, memory: 1024 },
|
|
843
|
+
});
|
|
844
|
+
await storage.addTags(entry1.id, ['alpha']);
|
|
845
|
+
await storage.addTags(entry2.id, ['beta']);
|
|
846
|
+
// Act - find entries with alpha OR beta
|
|
847
|
+
const result = await storage.findByTags(['alpha', 'beta'], 'OR');
|
|
848
|
+
// Assert
|
|
849
|
+
expect(result).toHaveLength(2);
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
//# sourceMappingURL=sqlite.storage.spec.js.map
|