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,929 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
var SqliteStorage_1;
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
exports.SqliteStorage = void 0;
|
|
50
|
+
const common_1 = require("@nestjs/common");
|
|
51
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
53
|
+
const path = __importStar(require("path"));
|
|
54
|
+
let SqliteStorage = SqliteStorage_1 = class SqliteStorage {
|
|
55
|
+
constructor(filename = '.cache/nestlens.db') {
|
|
56
|
+
this.filename = filename;
|
|
57
|
+
this.logger = new common_1.Logger(SqliteStorage_1.name);
|
|
58
|
+
// Ensure directory exists
|
|
59
|
+
const dir = path.dirname(filename);
|
|
60
|
+
if (dir && dir !== '.' && !fs.existsSync(dir)) {
|
|
61
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
this.db = new better_sqlite3_1.default(filename);
|
|
64
|
+
this.db.pragma('journal_mode = WAL');
|
|
65
|
+
this.initializeDatabase();
|
|
66
|
+
}
|
|
67
|
+
onModuleInit() {
|
|
68
|
+
// Already initialized in constructor
|
|
69
|
+
}
|
|
70
|
+
initializeDatabase() {
|
|
71
|
+
// Create main entries table (base schema without new columns)
|
|
72
|
+
this.db.exec(`
|
|
73
|
+
CREATE TABLE IF NOT EXISTS nestlens_entries (
|
|
74
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
75
|
+
type TEXT NOT NULL,
|
|
76
|
+
request_id TEXT,
|
|
77
|
+
payload TEXT NOT NULL,
|
|
78
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_nestlens_type ON nestlens_entries(type);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_nestlens_request_id ON nestlens_entries(request_id);
|
|
83
|
+
CREATE INDEX IF NOT EXISTS idx_nestlens_created_at ON nestlens_entries(created_at);
|
|
84
|
+
`);
|
|
85
|
+
// Migrate existing database - add new columns if they don't exist
|
|
86
|
+
this.migrateDatabase();
|
|
87
|
+
// Create tags table
|
|
88
|
+
this.db.exec(`
|
|
89
|
+
CREATE TABLE IF NOT EXISTS nestlens_tags (
|
|
90
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
91
|
+
entry_id INTEGER NOT NULL,
|
|
92
|
+
tag TEXT NOT NULL,
|
|
93
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
94
|
+
FOREIGN KEY (entry_id) REFERENCES nestlens_entries(id) ON DELETE CASCADE
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
CREATE INDEX IF NOT EXISTS idx_nestlens_tags_entry_id ON nestlens_tags(entry_id);
|
|
98
|
+
CREATE INDEX IF NOT EXISTS idx_nestlens_tags_tag ON nestlens_tags(tag);
|
|
99
|
+
`);
|
|
100
|
+
// Create monitored tags table
|
|
101
|
+
this.db.exec(`
|
|
102
|
+
CREATE TABLE IF NOT EXISTS nestlens_monitored_tags (
|
|
103
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
104
|
+
tag TEXT NOT NULL UNIQUE,
|
|
105
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
106
|
+
);
|
|
107
|
+
`);
|
|
108
|
+
this.logger.log(`Database initialized: ${this.filename}`);
|
|
109
|
+
}
|
|
110
|
+
migrateDatabase() {
|
|
111
|
+
// Check and add family_hash column
|
|
112
|
+
const columns = this.db.prepare("PRAGMA table_info(nestlens_entries)").all();
|
|
113
|
+
const columnNames = columns.map(c => c.name);
|
|
114
|
+
if (!columnNames.includes('family_hash')) {
|
|
115
|
+
this.db.exec('ALTER TABLE nestlens_entries ADD COLUMN family_hash TEXT');
|
|
116
|
+
}
|
|
117
|
+
if (!columnNames.includes('resolved_at')) {
|
|
118
|
+
this.db.exec('ALTER TABLE nestlens_entries ADD COLUMN resolved_at DATETIME');
|
|
119
|
+
}
|
|
120
|
+
// Create index for family_hash if column exists
|
|
121
|
+
this.db.exec('CREATE INDEX IF NOT EXISTS idx_nestlens_family_hash ON nestlens_entries(family_hash)');
|
|
122
|
+
}
|
|
123
|
+
async initialize() {
|
|
124
|
+
this.initializeDatabase();
|
|
125
|
+
}
|
|
126
|
+
async save(entry) {
|
|
127
|
+
const stmt = this.db.prepare(`
|
|
128
|
+
INSERT INTO nestlens_entries (type, request_id, payload)
|
|
129
|
+
VALUES (?, ?, ?)
|
|
130
|
+
`);
|
|
131
|
+
const result = stmt.run(entry.type, entry.requestId || null, JSON.stringify(entry.payload));
|
|
132
|
+
return {
|
|
133
|
+
...entry,
|
|
134
|
+
id: result.lastInsertRowid,
|
|
135
|
+
createdAt: new Date().toISOString(),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async saveBatch(entries) {
|
|
139
|
+
const stmt = this.db.prepare(`
|
|
140
|
+
INSERT INTO nestlens_entries (type, request_id, payload)
|
|
141
|
+
VALUES (?, ?, ?)
|
|
142
|
+
`);
|
|
143
|
+
const savedEntries = [];
|
|
144
|
+
const insertMany = this.db.transaction((items) => {
|
|
145
|
+
for (const entry of items) {
|
|
146
|
+
const result = stmt.run(entry.type, entry.requestId || null, JSON.stringify(entry.payload));
|
|
147
|
+
savedEntries.push({
|
|
148
|
+
...entry,
|
|
149
|
+
id: Number(result.lastInsertRowid),
|
|
150
|
+
createdAt: new Date().toISOString(),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
insertMany(entries);
|
|
155
|
+
return savedEntries;
|
|
156
|
+
}
|
|
157
|
+
async find(filter) {
|
|
158
|
+
let sql = 'SELECT * FROM nestlens_entries WHERE 1=1';
|
|
159
|
+
const params = [];
|
|
160
|
+
if (filter.type) {
|
|
161
|
+
sql += ' AND type = ?';
|
|
162
|
+
params.push(filter.type);
|
|
163
|
+
}
|
|
164
|
+
if (filter.requestId) {
|
|
165
|
+
sql += ' AND request_id = ?';
|
|
166
|
+
params.push(filter.requestId);
|
|
167
|
+
}
|
|
168
|
+
if (filter.from) {
|
|
169
|
+
sql += ' AND created_at >= ?';
|
|
170
|
+
params.push(filter.from.toISOString());
|
|
171
|
+
}
|
|
172
|
+
if (filter.to) {
|
|
173
|
+
sql += ' AND created_at <= ?';
|
|
174
|
+
params.push(filter.to.toISOString());
|
|
175
|
+
}
|
|
176
|
+
sql += ' ORDER BY created_at DESC';
|
|
177
|
+
if (filter.limit) {
|
|
178
|
+
sql += ' LIMIT ?';
|
|
179
|
+
params.push(filter.limit);
|
|
180
|
+
}
|
|
181
|
+
if (filter.offset) {
|
|
182
|
+
sql += ' OFFSET ?';
|
|
183
|
+
params.push(filter.offset);
|
|
184
|
+
}
|
|
185
|
+
const stmt = this.db.prepare(sql);
|
|
186
|
+
const rows = stmt.all(...params);
|
|
187
|
+
const entries = rows.map((row) => this.rowToEntry(row));
|
|
188
|
+
return this.hydrateEntriesWithTags(entries);
|
|
189
|
+
}
|
|
190
|
+
rowToEntry(row) {
|
|
191
|
+
let payload;
|
|
192
|
+
try {
|
|
193
|
+
payload = JSON.parse(row.payload);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Handle corrupted JSON gracefully
|
|
197
|
+
payload = { _error: 'Failed to parse payload', _raw: row.payload?.substring(0, 100) };
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
id: row.id,
|
|
201
|
+
type: row.type,
|
|
202
|
+
requestId: row.request_id || undefined,
|
|
203
|
+
payload,
|
|
204
|
+
createdAt: row.created_at,
|
|
205
|
+
familyHash: row.family_hash || undefined,
|
|
206
|
+
resolvedAt: row.resolved_at || undefined,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Hydrate entries with their tags (for batch efficiency)
|
|
211
|
+
*/
|
|
212
|
+
hydrateEntriesWithTags(entries) {
|
|
213
|
+
if (entries.length === 0)
|
|
214
|
+
return entries;
|
|
215
|
+
const entryIds = entries.map(e => e.id).filter((id) => id !== undefined);
|
|
216
|
+
if (entryIds.length === 0)
|
|
217
|
+
return entries;
|
|
218
|
+
// Fetch all tags for these entries in one query
|
|
219
|
+
const placeholders = entryIds.map(() => '?').join(',');
|
|
220
|
+
const stmt = this.db.prepare(`
|
|
221
|
+
SELECT entry_id, tag FROM nestlens_tags
|
|
222
|
+
WHERE entry_id IN (${placeholders})
|
|
223
|
+
`);
|
|
224
|
+
const tagRows = stmt.all(...entryIds);
|
|
225
|
+
// Group tags by entry ID
|
|
226
|
+
const tagsByEntryId = new Map();
|
|
227
|
+
for (const row of tagRows) {
|
|
228
|
+
const existing = tagsByEntryId.get(row.entry_id) || [];
|
|
229
|
+
existing.push(row.tag);
|
|
230
|
+
tagsByEntryId.set(row.entry_id, existing);
|
|
231
|
+
}
|
|
232
|
+
// Assign tags to entries
|
|
233
|
+
return entries.map(entry => ({
|
|
234
|
+
...entry,
|
|
235
|
+
tags: entry.id ? tagsByEntryId.get(entry.id) || [] : [],
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
async findById(id) {
|
|
239
|
+
const stmt = this.db.prepare('SELECT * FROM nestlens_entries WHERE id = ?');
|
|
240
|
+
const row = stmt.get(id);
|
|
241
|
+
if (!row)
|
|
242
|
+
return null;
|
|
243
|
+
const entry = this.rowToEntry(row);
|
|
244
|
+
const [hydratedEntry] = this.hydrateEntriesWithTags([entry]);
|
|
245
|
+
return hydratedEntry;
|
|
246
|
+
}
|
|
247
|
+
async count(type) {
|
|
248
|
+
let sql = 'SELECT COUNT(*) as count FROM nestlens_entries';
|
|
249
|
+
const params = [];
|
|
250
|
+
if (type) {
|
|
251
|
+
sql += ' WHERE type = ?';
|
|
252
|
+
params.push(type);
|
|
253
|
+
}
|
|
254
|
+
const stmt = this.db.prepare(sql);
|
|
255
|
+
const row = stmt.get(...params);
|
|
256
|
+
return row.count;
|
|
257
|
+
}
|
|
258
|
+
async getStats() {
|
|
259
|
+
// Optimized: Use a single query with CTE instead of 6 separate queries
|
|
260
|
+
const stmt = this.db.prepare(`
|
|
261
|
+
WITH type_counts AS (
|
|
262
|
+
SELECT type, COUNT(*) as count
|
|
263
|
+
FROM nestlens_entries
|
|
264
|
+
GROUP BY type
|
|
265
|
+
),
|
|
266
|
+
aggregates AS (
|
|
267
|
+
SELECT
|
|
268
|
+
(SELECT SUM(count) FROM type_counts) as total,
|
|
269
|
+
(SELECT AVG(json_extract(payload, '$.duration'))
|
|
270
|
+
FROM nestlens_entries
|
|
271
|
+
WHERE type = 'request' AND json_extract(payload, '$.duration') IS NOT NULL) as avg_response_time,
|
|
272
|
+
(SELECT COUNT(*)
|
|
273
|
+
FROM nestlens_entries
|
|
274
|
+
WHERE type = 'query' AND json_extract(payload, '$.slow') = 1) as slow_queries,
|
|
275
|
+
(SELECT COUNT(*)
|
|
276
|
+
FROM nestlens_entries
|
|
277
|
+
WHERE type = 'exception' AND resolved_at IS NULL) as unresolved_exceptions
|
|
278
|
+
)
|
|
279
|
+
SELECT * FROM aggregates
|
|
280
|
+
`);
|
|
281
|
+
const aggregateRow = stmt.get();
|
|
282
|
+
// Get type counts separately to build the byType object
|
|
283
|
+
const byTypeStmt = this.db.prepare(`
|
|
284
|
+
SELECT type, COUNT(*) as count
|
|
285
|
+
FROM nestlens_entries
|
|
286
|
+
GROUP BY type
|
|
287
|
+
`);
|
|
288
|
+
const byTypeRows = byTypeStmt.all();
|
|
289
|
+
const byType = byTypeRows.reduce((acc, row) => {
|
|
290
|
+
acc[row.type] = row.count;
|
|
291
|
+
return acc;
|
|
292
|
+
}, {});
|
|
293
|
+
return {
|
|
294
|
+
total: aggregateRow.total || 0,
|
|
295
|
+
byType,
|
|
296
|
+
avgResponseTime: aggregateRow.avg_response_time || undefined,
|
|
297
|
+
slowQueries: aggregateRow.slow_queries,
|
|
298
|
+
exceptions: byType.exception || 0,
|
|
299
|
+
unresolvedExceptions: aggregateRow.unresolved_exceptions,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
async prune(before) {
|
|
303
|
+
const stmt = this.db.prepare('DELETE FROM nestlens_entries WHERE created_at < ?');
|
|
304
|
+
const result = stmt.run(before.toISOString());
|
|
305
|
+
return result.changes;
|
|
306
|
+
}
|
|
307
|
+
async pruneByType(type, before) {
|
|
308
|
+
const stmt = this.db.prepare('DELETE FROM nestlens_entries WHERE type = ? AND created_at < ?');
|
|
309
|
+
const result = stmt.run(type, before.toISOString());
|
|
310
|
+
return result.changes;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Build SQL filter conditions from CursorPaginationParams filters
|
|
314
|
+
* This centralizes all filter logic to avoid duplication
|
|
315
|
+
*/
|
|
316
|
+
buildFilterConditions(filters) {
|
|
317
|
+
const conditions = [];
|
|
318
|
+
const params = [];
|
|
319
|
+
if (!filters) {
|
|
320
|
+
return { conditions, params };
|
|
321
|
+
}
|
|
322
|
+
// Logs: levels filter
|
|
323
|
+
if (filters.levels && filters.levels.length > 0) {
|
|
324
|
+
const placeholders = filters.levels.map(() => '?').join(', ');
|
|
325
|
+
conditions.push(`json_extract(e.payload, '$.level') IN (${placeholders})`);
|
|
326
|
+
params.push(...filters.levels);
|
|
327
|
+
}
|
|
328
|
+
// Logs: contexts filter
|
|
329
|
+
if (filters.contexts && filters.contexts.length > 0) {
|
|
330
|
+
const placeholders = filters.contexts.map(() => '?').join(', ');
|
|
331
|
+
conditions.push(`json_extract(e.payload, '$.context') IN (${placeholders})`);
|
|
332
|
+
params.push(...filters.contexts);
|
|
333
|
+
}
|
|
334
|
+
// Queries: queryTypes filter (SELECT, INSERT, UPDATE, DELETE)
|
|
335
|
+
if (filters.queryTypes && filters.queryTypes.length > 0) {
|
|
336
|
+
const queryConditions = filters.queryTypes.map(() => `json_extract(e.payload, '$.query') LIKE ?`).join(' OR ');
|
|
337
|
+
conditions.push(`(${queryConditions})`);
|
|
338
|
+
params.push(...filters.queryTypes.map(qt => `${qt}%`));
|
|
339
|
+
}
|
|
340
|
+
// Queries: sources filter (typeorm, prisma, etc)
|
|
341
|
+
if (filters.sources && filters.sources.length > 0) {
|
|
342
|
+
const placeholders = filters.sources.map(() => '?').join(', ');
|
|
343
|
+
conditions.push(`json_extract(e.payload, '$.source') IN (${placeholders})`);
|
|
344
|
+
params.push(...filters.sources);
|
|
345
|
+
}
|
|
346
|
+
// Queries: slow filter
|
|
347
|
+
if (filters.slow !== undefined) {
|
|
348
|
+
conditions.push(`json_extract(e.payload, '$.slow') = ?`);
|
|
349
|
+
params.push(filters.slow ? 1 : 0);
|
|
350
|
+
}
|
|
351
|
+
// Exceptions: names filter
|
|
352
|
+
if (filters.names && filters.names.length > 0) {
|
|
353
|
+
const nameConditions = filters.names.map(() => `json_extract(e.payload, '$.name') LIKE ?`).join(' OR ');
|
|
354
|
+
conditions.push(`(${nameConditions})`);
|
|
355
|
+
params.push(...filters.names.map(n => `%${n}%`));
|
|
356
|
+
}
|
|
357
|
+
// Requests & Exceptions: methods filter
|
|
358
|
+
if (filters.methods && filters.methods.length > 0) {
|
|
359
|
+
const placeholders = filters.methods.map(() => '?').join(', ');
|
|
360
|
+
conditions.push(`(json_extract(e.payload, '$.method') IN (${placeholders}) OR json_extract(e.payload, '$.request.method') IN (${placeholders}))`);
|
|
361
|
+
params.push(...filters.methods, ...filters.methods);
|
|
362
|
+
}
|
|
363
|
+
// Requests & Exceptions: paths filter (supports LIKE)
|
|
364
|
+
if (filters.paths && filters.paths.length > 0) {
|
|
365
|
+
const requestConditions = filters.paths.map(() => `json_extract(e.payload, '$.path') LIKE ?`).join(' OR ');
|
|
366
|
+
const exceptionConditions = filters.paths.map(() => `json_extract(e.payload, '$.request.url') LIKE ?`).join(' OR ');
|
|
367
|
+
conditions.push(`((${requestConditions}) OR (${exceptionConditions}))`);
|
|
368
|
+
const pathParams = filters.paths.map(p => p.includes('*') ? p.replace(/\*/g, '%') : `%${p}%`);
|
|
369
|
+
params.push(...pathParams, ...pathParams);
|
|
370
|
+
}
|
|
371
|
+
// Exceptions: resolved filter
|
|
372
|
+
if (filters.resolved !== undefined) {
|
|
373
|
+
conditions.push(filters.resolved ? 'e.resolved_at IS NOT NULL' : 'e.resolved_at IS NULL');
|
|
374
|
+
}
|
|
375
|
+
// Requests & HTTP Client: statuses filter (supports ERR for null status)
|
|
376
|
+
if (filters.statuses && filters.statuses.length > 0) {
|
|
377
|
+
const numericStatuses = filters.statuses.filter((s) => s !== 'ERR');
|
|
378
|
+
const hasErr = filters.statuses.includes('ERR');
|
|
379
|
+
const statusConditions = [];
|
|
380
|
+
if (numericStatuses.length > 0) {
|
|
381
|
+
const placeholders = numericStatuses.map(() => '?').join(', ');
|
|
382
|
+
statusConditions.push(`json_extract(e.payload, '$.statusCode') IN (${placeholders})`);
|
|
383
|
+
params.push(...numericStatuses);
|
|
384
|
+
}
|
|
385
|
+
if (hasErr) {
|
|
386
|
+
statusConditions.push(`json_extract(e.payload, '$.statusCode') IS NULL`);
|
|
387
|
+
}
|
|
388
|
+
if (statusConditions.length > 0) {
|
|
389
|
+
conditions.push(`(${statusConditions.join(' OR ')})`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Requests & HTTP Client: hostnames filter
|
|
393
|
+
// For requests: search in headers.host or headers.Host
|
|
394
|
+
// For http-client: search in payload.hostname
|
|
395
|
+
if (filters.hostnames && filters.hostnames.length > 0) {
|
|
396
|
+
const hostnameConditions = filters.hostnames.map(() => `(json_extract(e.payload, '$.headers.host') LIKE ? OR json_extract(e.payload, '$.headers.Host') LIKE ? OR json_extract(e.payload, '$.hostname') LIKE ?)`).join(' OR ');
|
|
397
|
+
conditions.push(`(${hostnameConditions})`);
|
|
398
|
+
filters.hostnames.forEach(h => {
|
|
399
|
+
params.push(`%${h}%`, `%${h}%`, `%${h}%`);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
// Requests: controllers filter
|
|
403
|
+
if (filters.controllers && filters.controllers.length > 0) {
|
|
404
|
+
const placeholders = filters.controllers.map(() => '?').join(', ');
|
|
405
|
+
conditions.push(`json_extract(e.payload, '$.controllerAction') IN (${placeholders})`);
|
|
406
|
+
params.push(...filters.controllers);
|
|
407
|
+
}
|
|
408
|
+
// Requests: ips filter
|
|
409
|
+
if (filters.ips && filters.ips.length > 0) {
|
|
410
|
+
const placeholders = filters.ips.map(() => '?').join(', ');
|
|
411
|
+
conditions.push(`json_extract(e.payload, '$.ip') IN (${placeholders})`);
|
|
412
|
+
params.push(...filters.ips);
|
|
413
|
+
}
|
|
414
|
+
// Schedule: scheduleStatuses filter (started, completed, failed)
|
|
415
|
+
if (filters.scheduleStatuses && filters.scheduleStatuses.length > 0) {
|
|
416
|
+
const placeholders = filters.scheduleStatuses.map(() => '?').join(', ');
|
|
417
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
418
|
+
params.push(...filters.scheduleStatuses);
|
|
419
|
+
}
|
|
420
|
+
// Jobs: jobStatuses filter (waiting, active, completed, failed, delayed)
|
|
421
|
+
if (filters.jobStatuses && filters.jobStatuses.length > 0) {
|
|
422
|
+
const placeholders = filters.jobStatuses.map(() => '?').join(', ');
|
|
423
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
424
|
+
params.push(...filters.jobStatuses);
|
|
425
|
+
}
|
|
426
|
+
// Jobs: queues filter
|
|
427
|
+
if (filters.queues && filters.queues.length > 0) {
|
|
428
|
+
const placeholders = filters.queues.map(() => '?').join(', ');
|
|
429
|
+
conditions.push(`json_extract(e.payload, '$.queue') IN (${placeholders})`);
|
|
430
|
+
params.push(...filters.queues);
|
|
431
|
+
}
|
|
432
|
+
// Cache: operations filter (get, set, del, clear)
|
|
433
|
+
if (filters.cacheOperations && filters.cacheOperations.length > 0) {
|
|
434
|
+
const placeholders = filters.cacheOperations.map(() => '?').join(', ');
|
|
435
|
+
conditions.push(`json_extract(e.payload, '$.operation') IN (${placeholders})`);
|
|
436
|
+
params.push(...filters.cacheOperations);
|
|
437
|
+
}
|
|
438
|
+
// Mail: mailStatuses filter (sent, failed)
|
|
439
|
+
if (filters.mailStatuses && filters.mailStatuses.length > 0) {
|
|
440
|
+
const placeholders = filters.mailStatuses.map(() => '?').join(', ');
|
|
441
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
442
|
+
params.push(...filters.mailStatuses);
|
|
443
|
+
}
|
|
444
|
+
// Redis: redisStatuses filter (success, error)
|
|
445
|
+
if (filters.redisStatuses && filters.redisStatuses.length > 0) {
|
|
446
|
+
const placeholders = filters.redisStatuses.map(() => '?').join(', ');
|
|
447
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
448
|
+
params.push(...filters.redisStatuses);
|
|
449
|
+
}
|
|
450
|
+
// Redis: redisCommands filter
|
|
451
|
+
if (filters.redisCommands && filters.redisCommands.length > 0) {
|
|
452
|
+
const placeholders = filters.redisCommands.map(() => '?').join(', ');
|
|
453
|
+
conditions.push(`json_extract(e.payload, '$.command') IN (${placeholders})`);
|
|
454
|
+
params.push(...filters.redisCommands);
|
|
455
|
+
}
|
|
456
|
+
// Model: modelActions filter (find, create, update, delete, save)
|
|
457
|
+
if (filters.modelActions && filters.modelActions.length > 0) {
|
|
458
|
+
const placeholders = filters.modelActions.map(() => '?').join(', ');
|
|
459
|
+
conditions.push(`json_extract(e.payload, '$.action') IN (${placeholders})`);
|
|
460
|
+
params.push(...filters.modelActions);
|
|
461
|
+
}
|
|
462
|
+
// Model: entities filter
|
|
463
|
+
if (filters.entities && filters.entities.length > 0) {
|
|
464
|
+
const placeholders = filters.entities.map(() => '?').join(', ');
|
|
465
|
+
conditions.push(`json_extract(e.payload, '$.entity') IN (${placeholders})`);
|
|
466
|
+
params.push(...filters.entities);
|
|
467
|
+
}
|
|
468
|
+
// Model: modelSources filter (typeorm, prisma)
|
|
469
|
+
if (filters.modelSources && filters.modelSources.length > 0) {
|
|
470
|
+
const placeholders = filters.modelSources.map(() => '?').join(', ');
|
|
471
|
+
conditions.push(`json_extract(e.payload, '$.source') IN (${placeholders})`);
|
|
472
|
+
params.push(...filters.modelSources);
|
|
473
|
+
}
|
|
474
|
+
// Notification: notificationTypes filter (email, sms, push, socket, webhook)
|
|
475
|
+
if (filters.notificationTypes && filters.notificationTypes.length > 0) {
|
|
476
|
+
const placeholders = filters.notificationTypes.map(() => '?').join(', ');
|
|
477
|
+
conditions.push(`json_extract(e.payload, '$.type') IN (${placeholders})`);
|
|
478
|
+
params.push(...filters.notificationTypes);
|
|
479
|
+
}
|
|
480
|
+
// Notification: notificationStatuses filter (sent, failed)
|
|
481
|
+
if (filters.notificationStatuses && filters.notificationStatuses.length > 0) {
|
|
482
|
+
const placeholders = filters.notificationStatuses.map(() => '?').join(', ');
|
|
483
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
484
|
+
params.push(...filters.notificationStatuses);
|
|
485
|
+
}
|
|
486
|
+
// View: viewFormats filter (html, json, xml, pdf)
|
|
487
|
+
if (filters.viewFormats && filters.viewFormats.length > 0) {
|
|
488
|
+
const placeholders = filters.viewFormats.map(() => '?').join(', ');
|
|
489
|
+
conditions.push(`json_extract(e.payload, '$.format') IN (${placeholders})`);
|
|
490
|
+
params.push(...filters.viewFormats);
|
|
491
|
+
}
|
|
492
|
+
// View: viewStatuses filter (rendered, error)
|
|
493
|
+
if (filters.viewStatuses && filters.viewStatuses.length > 0) {
|
|
494
|
+
const placeholders = filters.viewStatuses.map(() => '?').join(', ');
|
|
495
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
496
|
+
params.push(...filters.viewStatuses);
|
|
497
|
+
}
|
|
498
|
+
// Command: commandStatuses filter (executing, completed, failed)
|
|
499
|
+
if (filters.commandStatuses && filters.commandStatuses.length > 0) {
|
|
500
|
+
const placeholders = filters.commandStatuses.map(() => '?').join(', ');
|
|
501
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
502
|
+
params.push(...filters.commandStatuses);
|
|
503
|
+
}
|
|
504
|
+
// Command: commandNames filter
|
|
505
|
+
if (filters.commandNames && filters.commandNames.length > 0) {
|
|
506
|
+
const nameConditions = filters.commandNames.map(() => `json_extract(e.payload, '$.name') LIKE ?`).join(' OR ');
|
|
507
|
+
conditions.push(`(${nameConditions})`);
|
|
508
|
+
params.push(...filters.commandNames.map(n => `%${n}%`));
|
|
509
|
+
}
|
|
510
|
+
// Gate: gateNames filter
|
|
511
|
+
if (filters.gateNames && filters.gateNames.length > 0) {
|
|
512
|
+
const nameConditions = filters.gateNames.map(() => `json_extract(e.payload, '$.gate') LIKE ?`).join(' OR ');
|
|
513
|
+
conditions.push(`(${nameConditions})`);
|
|
514
|
+
params.push(...filters.gateNames.map(n => `%${n}%`));
|
|
515
|
+
}
|
|
516
|
+
// Gate: gateResults filter (allowed, denied mapped from boolean)
|
|
517
|
+
if (filters.gateResults && filters.gateResults.length > 0) {
|
|
518
|
+
const resultConditions = [];
|
|
519
|
+
if (filters.gateResults.includes('allowed')) {
|
|
520
|
+
resultConditions.push(`json_extract(e.payload, '$.allowed') = 1`);
|
|
521
|
+
}
|
|
522
|
+
if (filters.gateResults.includes('denied')) {
|
|
523
|
+
resultConditions.push(`json_extract(e.payload, '$.allowed') = 0`);
|
|
524
|
+
}
|
|
525
|
+
if (resultConditions.length > 0) {
|
|
526
|
+
conditions.push(`(${resultConditions.join(' OR ')})`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
// Batch: batchStatuses filter (completed, partial, failed)
|
|
530
|
+
if (filters.batchStatuses && filters.batchStatuses.length > 0) {
|
|
531
|
+
const placeholders = filters.batchStatuses.map(() => '?').join(', ');
|
|
532
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
533
|
+
params.push(...filters.batchStatuses);
|
|
534
|
+
}
|
|
535
|
+
// Batch: batchOperations filter
|
|
536
|
+
if (filters.batchOperations && filters.batchOperations.length > 0) {
|
|
537
|
+
const placeholders = filters.batchOperations.map(() => '?').join(', ');
|
|
538
|
+
conditions.push(`json_extract(e.payload, '$.operation') IN (${placeholders})`);
|
|
539
|
+
params.push(...filters.batchOperations);
|
|
540
|
+
}
|
|
541
|
+
// Dump: dumpStatuses filter (completed, failed)
|
|
542
|
+
if (filters.dumpStatuses && filters.dumpStatuses.length > 0) {
|
|
543
|
+
const placeholders = filters.dumpStatuses.map(() => '?').join(', ');
|
|
544
|
+
conditions.push(`json_extract(e.payload, '$.status') IN (${placeholders})`);
|
|
545
|
+
params.push(...filters.dumpStatuses);
|
|
546
|
+
}
|
|
547
|
+
// Dump: dumpOperations filter (export, import, backup, restore, migrate)
|
|
548
|
+
if (filters.dumpOperations && filters.dumpOperations.length > 0) {
|
|
549
|
+
const placeholders = filters.dumpOperations.map(() => '?').join(', ');
|
|
550
|
+
conditions.push(`json_extract(e.payload, '$.operation') IN (${placeholders})`);
|
|
551
|
+
params.push(...filters.dumpOperations);
|
|
552
|
+
}
|
|
553
|
+
// Dump: dumpFormats filter (sql, json, csv, binary)
|
|
554
|
+
if (filters.dumpFormats && filters.dumpFormats.length > 0) {
|
|
555
|
+
const placeholders = filters.dumpFormats.map(() => '?').join(', ');
|
|
556
|
+
conditions.push(`json_extract(e.payload, '$.format') IN (${placeholders})`);
|
|
557
|
+
params.push(...filters.dumpFormats);
|
|
558
|
+
}
|
|
559
|
+
// Tags filter (OR logic) - handled separately since it requires JOIN
|
|
560
|
+
if (filters.tags && filters.tags.length > 0) {
|
|
561
|
+
const placeholders = filters.tags.map(() => '?').join(', ');
|
|
562
|
+
conditions.push(`t.tag IN (${placeholders})`);
|
|
563
|
+
params.push(...filters.tags);
|
|
564
|
+
}
|
|
565
|
+
// Search filter (searches in payload)
|
|
566
|
+
if (filters.search) {
|
|
567
|
+
conditions.push(`e.payload LIKE ?`);
|
|
568
|
+
params.push(`%${filters.search}%`);
|
|
569
|
+
}
|
|
570
|
+
return { conditions, params };
|
|
571
|
+
}
|
|
572
|
+
async findWithCursor(type, params) {
|
|
573
|
+
const limit = params.limit || 50;
|
|
574
|
+
const sqlParams = [];
|
|
575
|
+
const filters = params.filters;
|
|
576
|
+
// Build base query - may need JOIN for tag filtering
|
|
577
|
+
const needsTagJoin = filters?.tags && filters.tags.length > 0;
|
|
578
|
+
let sql = needsTagJoin
|
|
579
|
+
? 'SELECT DISTINCT e.* FROM nestlens_entries e INNER JOIN nestlens_tags t ON e.id = t.entry_id WHERE 1=1'
|
|
580
|
+
: 'SELECT * FROM nestlens_entries e WHERE 1=1';
|
|
581
|
+
if (type) {
|
|
582
|
+
sql += ' AND e.type = ?';
|
|
583
|
+
sqlParams.push(type);
|
|
584
|
+
}
|
|
585
|
+
// Apply filters using centralized method
|
|
586
|
+
const { conditions, params: filterParams } = this.buildFilterConditions(filters);
|
|
587
|
+
if (conditions.length > 0) {
|
|
588
|
+
sql += ' AND ' + conditions.join(' AND ');
|
|
589
|
+
sqlParams.push(...filterParams);
|
|
590
|
+
}
|
|
591
|
+
// Cursor pagination
|
|
592
|
+
if (params.beforeSequence !== undefined) {
|
|
593
|
+
sql += ' AND e.id < ?';
|
|
594
|
+
sqlParams.push(params.beforeSequence);
|
|
595
|
+
sql += ' ORDER BY e.id DESC';
|
|
596
|
+
}
|
|
597
|
+
else if (params.afterSequence !== undefined) {
|
|
598
|
+
sql += ' AND e.id > ?';
|
|
599
|
+
sqlParams.push(params.afterSequence);
|
|
600
|
+
sql += ' ORDER BY e.id ASC';
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
sql += ' ORDER BY e.id DESC';
|
|
604
|
+
}
|
|
605
|
+
sql += ' LIMIT ?';
|
|
606
|
+
sqlParams.push(limit + 1);
|
|
607
|
+
const stmt = this.db.prepare(sql);
|
|
608
|
+
let rows = stmt.all(...sqlParams);
|
|
609
|
+
const hasMore = rows.length > limit;
|
|
610
|
+
if (hasMore) {
|
|
611
|
+
rows = rows.slice(0, limit);
|
|
612
|
+
}
|
|
613
|
+
if (params.afterSequence !== undefined) {
|
|
614
|
+
rows = rows.reverse();
|
|
615
|
+
}
|
|
616
|
+
const entries = this.hydrateEntriesWithTags(rows.map((row) => this.rowToEntry(row)));
|
|
617
|
+
// Get total count with filters
|
|
618
|
+
const total = await this.countWithFilters(type, filters);
|
|
619
|
+
return {
|
|
620
|
+
data: entries,
|
|
621
|
+
meta: {
|
|
622
|
+
hasMore,
|
|
623
|
+
oldestSequence: entries.length > 0 ? entries[entries.length - 1].id : null,
|
|
624
|
+
newestSequence: entries.length > 0 ? entries[0].id : null,
|
|
625
|
+
total,
|
|
626
|
+
},
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Count entries with filters applied
|
|
631
|
+
*/
|
|
632
|
+
async countWithFilters(type, filters) {
|
|
633
|
+
if (!filters || Object.keys(filters).every(k => {
|
|
634
|
+
const val = filters[k];
|
|
635
|
+
return val === undefined || (Array.isArray(val) && val.length === 0);
|
|
636
|
+
})) {
|
|
637
|
+
return this.count(type);
|
|
638
|
+
}
|
|
639
|
+
const sqlParams = [];
|
|
640
|
+
const needsTagJoin = filters?.tags && filters.tags.length > 0;
|
|
641
|
+
let sql = needsTagJoin
|
|
642
|
+
? 'SELECT COUNT(DISTINCT e.id) as count FROM nestlens_entries e INNER JOIN nestlens_tags t ON e.id = t.entry_id WHERE 1=1'
|
|
643
|
+
: 'SELECT COUNT(*) as count FROM nestlens_entries e WHERE 1=1';
|
|
644
|
+
if (type) {
|
|
645
|
+
sql += ' AND e.type = ?';
|
|
646
|
+
sqlParams.push(type);
|
|
647
|
+
}
|
|
648
|
+
// Apply filters using centralized method
|
|
649
|
+
const { conditions, params: filterParams } = this.buildFilterConditions(filters);
|
|
650
|
+
if (conditions.length > 0) {
|
|
651
|
+
sql += ' AND ' + conditions.join(' AND ');
|
|
652
|
+
sqlParams.push(...filterParams);
|
|
653
|
+
}
|
|
654
|
+
const stmt = this.db.prepare(sql);
|
|
655
|
+
const row = stmt.get(...sqlParams);
|
|
656
|
+
return row.count;
|
|
657
|
+
}
|
|
658
|
+
async getLatestSequence(type) {
|
|
659
|
+
let sql = 'SELECT MAX(id) as maxId FROM nestlens_entries';
|
|
660
|
+
const params = [];
|
|
661
|
+
if (type) {
|
|
662
|
+
sql += ' WHERE type = ?';
|
|
663
|
+
params.push(type);
|
|
664
|
+
}
|
|
665
|
+
const stmt = this.db.prepare(sql);
|
|
666
|
+
const row = stmt.get(...params);
|
|
667
|
+
return row.maxId;
|
|
668
|
+
}
|
|
669
|
+
async hasEntriesAfter(sequence, type) {
|
|
670
|
+
let sql = 'SELECT COUNT(*) as count FROM nestlens_entries WHERE id > ?';
|
|
671
|
+
const params = [sequence];
|
|
672
|
+
if (type) {
|
|
673
|
+
sql += ' AND type = ?';
|
|
674
|
+
params.push(type);
|
|
675
|
+
}
|
|
676
|
+
const stmt = this.db.prepare(sql);
|
|
677
|
+
const row = stmt.get(...params);
|
|
678
|
+
return row.count;
|
|
679
|
+
}
|
|
680
|
+
async getStorageStats() {
|
|
681
|
+
const totalStmt = this.db.prepare('SELECT COUNT(*) as count FROM nestlens_entries');
|
|
682
|
+
const total = totalStmt.get().count;
|
|
683
|
+
const byTypeStmt = this.db.prepare(`
|
|
684
|
+
SELECT type, COUNT(*) as count
|
|
685
|
+
FROM nestlens_entries
|
|
686
|
+
GROUP BY type
|
|
687
|
+
`);
|
|
688
|
+
const byTypeRows = byTypeStmt.all();
|
|
689
|
+
const byType = byTypeRows.reduce((acc, row) => {
|
|
690
|
+
acc[row.type] = row.count;
|
|
691
|
+
return acc;
|
|
692
|
+
}, {});
|
|
693
|
+
const oldestStmt = this.db.prepare('SELECT created_at FROM nestlens_entries ORDER BY id ASC LIMIT 1');
|
|
694
|
+
const oldestRow = oldestStmt.get();
|
|
695
|
+
const newestStmt = this.db.prepare('SELECT created_at FROM nestlens_entries ORDER BY id DESC LIMIT 1');
|
|
696
|
+
const newestRow = newestStmt.get();
|
|
697
|
+
let databaseSize;
|
|
698
|
+
try {
|
|
699
|
+
const stats = fs.statSync(this.filename);
|
|
700
|
+
databaseSize = stats.size;
|
|
701
|
+
}
|
|
702
|
+
catch {
|
|
703
|
+
// File might not exist or be inaccessible
|
|
704
|
+
}
|
|
705
|
+
return {
|
|
706
|
+
total,
|
|
707
|
+
byType,
|
|
708
|
+
oldestEntry: oldestRow?.created_at || null,
|
|
709
|
+
newestEntry: newestRow?.created_at || null,
|
|
710
|
+
databaseSize,
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
async clear() {
|
|
714
|
+
this.db.exec('DELETE FROM nestlens_tags');
|
|
715
|
+
this.db.exec('DELETE FROM nestlens_entries');
|
|
716
|
+
}
|
|
717
|
+
async close() {
|
|
718
|
+
this.db.close();
|
|
719
|
+
}
|
|
720
|
+
// ==================== Tag Methods ====================
|
|
721
|
+
async addTags(entryId, tags) {
|
|
722
|
+
const stmt = this.db.prepare(`
|
|
723
|
+
INSERT OR IGNORE INTO nestlens_tags (entry_id, tag)
|
|
724
|
+
VALUES (?, ?)
|
|
725
|
+
`);
|
|
726
|
+
const insertMany = this.db.transaction((items) => {
|
|
727
|
+
for (const tag of items) {
|
|
728
|
+
stmt.run(entryId, tag);
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
insertMany(tags);
|
|
732
|
+
}
|
|
733
|
+
async removeTags(entryId, tags) {
|
|
734
|
+
const stmt = this.db.prepare(`
|
|
735
|
+
DELETE FROM nestlens_tags
|
|
736
|
+
WHERE entry_id = ? AND tag = ?
|
|
737
|
+
`);
|
|
738
|
+
const deleteMany = this.db.transaction((items) => {
|
|
739
|
+
for (const tag of items) {
|
|
740
|
+
stmt.run(entryId, tag);
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
deleteMany(tags);
|
|
744
|
+
}
|
|
745
|
+
async getEntryTags(entryId) {
|
|
746
|
+
const stmt = this.db.prepare(`
|
|
747
|
+
SELECT tag FROM nestlens_tags
|
|
748
|
+
WHERE entry_id = ?
|
|
749
|
+
ORDER BY tag
|
|
750
|
+
`);
|
|
751
|
+
const rows = stmt.all(entryId);
|
|
752
|
+
return rows.map(r => r.tag);
|
|
753
|
+
}
|
|
754
|
+
async getAllTags() {
|
|
755
|
+
const stmt = this.db.prepare(`
|
|
756
|
+
SELECT tag, COUNT(*) as count
|
|
757
|
+
FROM nestlens_tags
|
|
758
|
+
GROUP BY tag
|
|
759
|
+
ORDER BY count DESC, tag ASC
|
|
760
|
+
`);
|
|
761
|
+
const rows = stmt.all();
|
|
762
|
+
return rows;
|
|
763
|
+
}
|
|
764
|
+
async findByTags(tags, logic = 'OR', limit = 50) {
|
|
765
|
+
if (tags.length === 0) {
|
|
766
|
+
return [];
|
|
767
|
+
}
|
|
768
|
+
let sql;
|
|
769
|
+
const params = [];
|
|
770
|
+
if (logic === 'AND') {
|
|
771
|
+
// Entries that have ALL specified tags
|
|
772
|
+
const placeholders = tags.map(() => '?').join(', ');
|
|
773
|
+
sql = `
|
|
774
|
+
SELECT e.* FROM nestlens_entries e
|
|
775
|
+
WHERE e.id IN (
|
|
776
|
+
SELECT entry_id FROM nestlens_tags
|
|
777
|
+
WHERE tag IN (${placeholders})
|
|
778
|
+
GROUP BY entry_id
|
|
779
|
+
HAVING COUNT(DISTINCT tag) = ?
|
|
780
|
+
)
|
|
781
|
+
ORDER BY e.id DESC
|
|
782
|
+
LIMIT ?
|
|
783
|
+
`;
|
|
784
|
+
params.push(...tags, tags.length, limit);
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
// Entries that have ANY of the specified tags
|
|
788
|
+
const placeholders = tags.map(() => '?').join(', ');
|
|
789
|
+
sql = `
|
|
790
|
+
SELECT DISTINCT e.* FROM nestlens_entries e
|
|
791
|
+
INNER JOIN nestlens_tags t ON e.id = t.entry_id
|
|
792
|
+
WHERE t.tag IN (${placeholders})
|
|
793
|
+
ORDER BY e.id DESC
|
|
794
|
+
LIMIT ?
|
|
795
|
+
`;
|
|
796
|
+
params.push(...tags, limit);
|
|
797
|
+
}
|
|
798
|
+
const stmt = this.db.prepare(sql);
|
|
799
|
+
const rows = stmt.all(...params);
|
|
800
|
+
return rows.map(row => this.rowToEntry(row));
|
|
801
|
+
}
|
|
802
|
+
// ==================== Monitored Tags ====================
|
|
803
|
+
async addMonitoredTag(tag) {
|
|
804
|
+
const stmt = this.db.prepare(`
|
|
805
|
+
INSERT OR IGNORE INTO nestlens_monitored_tags (tag)
|
|
806
|
+
VALUES (?)
|
|
807
|
+
`);
|
|
808
|
+
stmt.run(tag);
|
|
809
|
+
const selectStmt = this.db.prepare(`
|
|
810
|
+
SELECT * FROM nestlens_monitored_tags WHERE tag = ?
|
|
811
|
+
`);
|
|
812
|
+
const row = selectStmt.get(tag);
|
|
813
|
+
return {
|
|
814
|
+
id: row.id,
|
|
815
|
+
tag: row.tag,
|
|
816
|
+
createdAt: row.created_at,
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
async removeMonitoredTag(tag) {
|
|
820
|
+
const stmt = this.db.prepare(`
|
|
821
|
+
DELETE FROM nestlens_monitored_tags WHERE tag = ?
|
|
822
|
+
`);
|
|
823
|
+
stmt.run(tag);
|
|
824
|
+
}
|
|
825
|
+
async getMonitoredTags() {
|
|
826
|
+
const stmt = this.db.prepare(`
|
|
827
|
+
SELECT * FROM nestlens_monitored_tags ORDER BY tag
|
|
828
|
+
`);
|
|
829
|
+
const rows = stmt.all();
|
|
830
|
+
return rows.map(row => ({
|
|
831
|
+
id: row.id,
|
|
832
|
+
tag: row.tag,
|
|
833
|
+
createdAt: row.created_at,
|
|
834
|
+
}));
|
|
835
|
+
}
|
|
836
|
+
// ==================== Resolution ====================
|
|
837
|
+
async resolveEntry(id) {
|
|
838
|
+
const stmt = this.db.prepare(`
|
|
839
|
+
UPDATE nestlens_entries
|
|
840
|
+
SET resolved_at = CURRENT_TIMESTAMP
|
|
841
|
+
WHERE id = ?
|
|
842
|
+
`);
|
|
843
|
+
stmt.run(id);
|
|
844
|
+
}
|
|
845
|
+
async unresolveEntry(id) {
|
|
846
|
+
const stmt = this.db.prepare(`
|
|
847
|
+
UPDATE nestlens_entries
|
|
848
|
+
SET resolved_at = NULL
|
|
849
|
+
WHERE id = ?
|
|
850
|
+
`);
|
|
851
|
+
stmt.run(id);
|
|
852
|
+
}
|
|
853
|
+
// ==================== Family Hash ====================
|
|
854
|
+
async updateFamilyHash(id, familyHash) {
|
|
855
|
+
const stmt = this.db.prepare(`
|
|
856
|
+
UPDATE nestlens_entries
|
|
857
|
+
SET family_hash = ?
|
|
858
|
+
WHERE id = ?
|
|
859
|
+
`);
|
|
860
|
+
stmt.run(familyHash, id);
|
|
861
|
+
}
|
|
862
|
+
async findByFamilyHash(familyHash, limit = 50) {
|
|
863
|
+
const stmt = this.db.prepare(`
|
|
864
|
+
SELECT * FROM nestlens_entries
|
|
865
|
+
WHERE family_hash = ?
|
|
866
|
+
ORDER BY id DESC
|
|
867
|
+
LIMIT ?
|
|
868
|
+
`);
|
|
869
|
+
const rows = stmt.all(familyHash, limit);
|
|
870
|
+
return rows.map(row => this.rowToEntry(row));
|
|
871
|
+
}
|
|
872
|
+
async getGroupedByFamilyHash(type, limit = 50) {
|
|
873
|
+
let sql = `
|
|
874
|
+
SELECT family_hash, COUNT(*) as count, MAX(id) as latest_id
|
|
875
|
+
FROM nestlens_entries
|
|
876
|
+
WHERE family_hash IS NOT NULL
|
|
877
|
+
`;
|
|
878
|
+
const params = [];
|
|
879
|
+
if (type) {
|
|
880
|
+
sql += ' AND type = ?';
|
|
881
|
+
params.push(type);
|
|
882
|
+
}
|
|
883
|
+
sql += `
|
|
884
|
+
GROUP BY family_hash
|
|
885
|
+
ORDER BY count DESC, latest_id DESC
|
|
886
|
+
LIMIT ?
|
|
887
|
+
`;
|
|
888
|
+
params.push(limit);
|
|
889
|
+
const stmt = this.db.prepare(sql);
|
|
890
|
+
const rows = stmt.all(...params);
|
|
891
|
+
if (rows.length === 0) {
|
|
892
|
+
return [];
|
|
893
|
+
}
|
|
894
|
+
// Fetch all entries in a single query to avoid N+1
|
|
895
|
+
const ids = rows.map(row => row.latest_id);
|
|
896
|
+
const placeholders = ids.map(() => '?').join(', ');
|
|
897
|
+
const entriesStmt = this.db.prepare(`
|
|
898
|
+
SELECT * FROM nestlens_entries WHERE id IN (${placeholders})
|
|
899
|
+
`);
|
|
900
|
+
const entryRows = entriesStmt.all(...ids);
|
|
901
|
+
// Create a map for O(1) lookup
|
|
902
|
+
const entryMap = new Map();
|
|
903
|
+
for (const row of entryRows) {
|
|
904
|
+
entryMap.set(row.id, this.rowToEntry(row));
|
|
905
|
+
}
|
|
906
|
+
// Build results maintaining the original order
|
|
907
|
+
const results = [];
|
|
908
|
+
for (const row of rows) {
|
|
909
|
+
const entry = entryMap.get(row.latest_id);
|
|
910
|
+
if (entry) {
|
|
911
|
+
results.push({
|
|
912
|
+
familyHash: row.family_hash,
|
|
913
|
+
count: row.count,
|
|
914
|
+
latestEntry: entry,
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return results;
|
|
919
|
+
}
|
|
920
|
+
onModuleDestroy() {
|
|
921
|
+
this.db.close();
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
exports.SqliteStorage = SqliteStorage;
|
|
925
|
+
exports.SqliteStorage = SqliteStorage = SqliteStorage_1 = __decorate([
|
|
926
|
+
(0, common_1.Injectable)(),
|
|
927
|
+
__metadata("design:paramtypes", [String])
|
|
928
|
+
], SqliteStorage);
|
|
929
|
+
//# sourceMappingURL=sqlite.storage.js.map
|