nuxt-observe 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -0
- package/dist/module.d.mts +7 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +393 -0
- package/dist/runtime/app/assets/css/main.css +1 -0
- package/dist/runtime/app/components/ObserveActivityFeed.d.vue.ts +13 -0
- package/dist/runtime/app/components/ObserveActivityFeed.vue +77 -0
- package/dist/runtime/app/components/ObserveActivityFeed.vue.d.ts +13 -0
- package/dist/runtime/app/components/ObserveActivityTable.d.vue.ts +30 -0
- package/dist/runtime/app/components/ObserveActivityTable.vue +187 -0
- package/dist/runtime/app/components/ObserveActivityTable.vue.d.ts +30 -0
- package/dist/runtime/app/components/ObserveCan.d.vue.ts +27 -0
- package/dist/runtime/app/components/ObserveCan.vue +16 -0
- package/dist/runtime/app/components/ObserveCan.vue.d.ts +27 -0
- package/dist/runtime/app/components/ObserveErrorsTable.d.vue.ts +19 -0
- package/dist/runtime/app/components/ObserveErrorsTable.vue +105 -0
- package/dist/runtime/app/components/ObserveErrorsTable.vue.d.ts +19 -0
- package/dist/runtime/app/components/ObserveHealthHero.d.vue.ts +16 -0
- package/dist/runtime/app/components/ObserveHealthHero.vue +114 -0
- package/dist/runtime/app/components/ObserveHealthHero.vue.d.ts +16 -0
- package/dist/runtime/app/components/ObserveJourneySearch.d.vue.ts +13 -0
- package/dist/runtime/app/components/ObserveJourneySearch.vue +55 -0
- package/dist/runtime/app/components/ObserveJourneySearch.vue.d.ts +13 -0
- package/dist/runtime/app/components/ObserveJourneyTimeline.d.vue.ts +14 -0
- package/dist/runtime/app/components/ObserveJourneyTimeline.vue +119 -0
- package/dist/runtime/app/components/ObserveJourneyTimeline.vue.d.ts +14 -0
- package/dist/runtime/app/components/ObserveLogDetail.d.vue.ts +12 -0
- package/dist/runtime/app/components/ObserveLogDetail.vue +187 -0
- package/dist/runtime/app/components/ObserveLogDetail.vue.d.ts +12 -0
- package/dist/runtime/app/components/ObserveLogLevelBadge.d.vue.ts +10 -0
- package/dist/runtime/app/components/ObserveLogLevelBadge.vue +29 -0
- package/dist/runtime/app/components/ObserveLogLevelBadge.vue.d.ts +10 -0
- package/dist/runtime/app/components/ObserveLogsFilterBar.d.vue.ts +20 -0
- package/dist/runtime/app/components/ObserveLogsFilterBar.vue +134 -0
- package/dist/runtime/app/components/ObserveLogsFilterBar.vue.d.ts +20 -0
- package/dist/runtime/app/components/ObserveLogsTable.d.vue.ts +20 -0
- package/dist/runtime/app/components/ObserveLogsTable.vue +92 -0
- package/dist/runtime/app/components/ObserveLogsTable.vue.d.ts +20 -0
- package/dist/runtime/app/components/ObservePeriodSelector.d.vue.ts +3 -0
- package/dist/runtime/app/components/ObservePeriodSelector.vue +22 -0
- package/dist/runtime/app/components/ObservePeriodSelector.vue.d.ts +3 -0
- package/dist/runtime/app/components/ObserveRegressionAlert.d.vue.ts +12 -0
- package/dist/runtime/app/components/ObserveRegressionAlert.vue +27 -0
- package/dist/runtime/app/components/ObserveRegressionAlert.vue.d.ts +12 -0
- package/dist/runtime/app/components/ObserveServiceSwitcher.d.vue.ts +3 -0
- package/dist/runtime/app/components/ObserveServiceSwitcher.vue +49 -0
- package/dist/runtime/app/components/ObserveServiceSwitcher.vue.d.ts +3 -0
- package/dist/runtime/app/components/ObserveServicesTable.d.vue.ts +15 -0
- package/dist/runtime/app/components/ObserveServicesTable.vue +109 -0
- package/dist/runtime/app/components/ObserveServicesTable.vue.d.ts +15 -0
- package/dist/runtime/app/components/ObserveStatCard.d.vue.ts +14 -0
- package/dist/runtime/app/components/ObserveStatCard.vue +34 -0
- package/dist/runtime/app/components/ObserveStatCard.vue.d.ts +14 -0
- package/dist/runtime/app/components/charts/ObserveErrorRateChart.client.d.vue.ts +15 -0
- package/dist/runtime/app/components/charts/ObserveErrorRateChart.client.vue +170 -0
- package/dist/runtime/app/components/charts/ObserveErrorRateChart.client.vue.d.ts +15 -0
- package/dist/runtime/app/components/charts/ObserveServiceBreakdownChart.client.d.vue.ts +17 -0
- package/dist/runtime/app/components/charts/ObserveServiceBreakdownChart.client.vue +208 -0
- package/dist/runtime/app/components/charts/ObserveServiceBreakdownChart.client.vue.d.ts +17 -0
- package/dist/runtime/app/components/charts/ObserveVersionAdoptionChart.client.d.vue.ts +14 -0
- package/dist/runtime/app/components/charts/ObserveVersionAdoptionChart.client.vue +208 -0
- package/dist/runtime/app/components/charts/ObserveVersionAdoptionChart.client.vue.d.ts +14 -0
- package/dist/runtime/app/components/charts/ObserveVersionCompareChart.client.d.vue.ts +14 -0
- package/dist/runtime/app/components/charts/ObserveVersionCompareChart.client.vue +190 -0
- package/dist/runtime/app/components/charts/ObserveVersionCompareChart.client.vue.d.ts +14 -0
- package/dist/runtime/app/components/charts/ObserveVolumeChart.client.d.vue.ts +16 -0
- package/dist/runtime/app/components/charts/ObserveVolumeChart.client.vue +199 -0
- package/dist/runtime/app/components/charts/ObserveVolumeChart.client.vue.d.ts +16 -0
- package/dist/runtime/app/components/charts/chart-core.d.ts +64 -0
- package/dist/runtime/app/components/charts/chart-core.js +136 -0
- package/dist/runtime/app/components/settings/ObserveApiKeyPanel.d.vue.ts +8 -0
- package/dist/runtime/app/components/settings/ObserveApiKeyPanel.vue +145 -0
- package/dist/runtime/app/components/settings/ObserveApiKeyPanel.vue.d.ts +8 -0
- package/dist/runtime/app/components/settings/ObserveApiKeyRevealModal.d.vue.ts +19 -0
- package/dist/runtime/app/components/settings/ObserveApiKeyRevealModal.vue +106 -0
- package/dist/runtime/app/components/settings/ObserveApiKeyRevealModal.vue.d.ts +19 -0
- package/dist/runtime/app/components/settings/ObserveAssignmentEditor.d.vue.ts +12 -0
- package/dist/runtime/app/components/settings/ObserveAssignmentEditor.vue +67 -0
- package/dist/runtime/app/components/settings/ObserveAssignmentEditor.vue.d.ts +12 -0
- package/dist/runtime/app/components/settings/ObserveGroupFormModal.d.vue.ts +18 -0
- package/dist/runtime/app/components/settings/ObserveGroupFormModal.vue +60 -0
- package/dist/runtime/app/components/settings/ObserveGroupFormModal.vue.d.ts +18 -0
- package/dist/runtime/app/components/settings/ObserveGroupMembershipEditor.d.vue.ts +20 -0
- package/dist/runtime/app/components/settings/ObserveGroupMembershipEditor.vue +21 -0
- package/dist/runtime/app/components/settings/ObserveGroupMembershipEditor.vue.d.ts +20 -0
- package/dist/runtime/app/components/settings/ObserveOriginAllowlistEditor.d.vue.ts +15 -0
- package/dist/runtime/app/components/settings/ObserveOriginAllowlistEditor.vue +63 -0
- package/dist/runtime/app/components/settings/ObserveOriginAllowlistEditor.vue.d.ts +15 -0
- package/dist/runtime/app/components/settings/ObserveServiceEditForm.d.vue.ts +38 -0
- package/dist/runtime/app/components/settings/ObserveServiceEditForm.vue +216 -0
- package/dist/runtime/app/components/settings/ObserveServiceEditForm.vue.d.ts +38 -0
- package/dist/runtime/app/components/settings/ObserveServiceFormModal.d.vue.ts +37 -0
- package/dist/runtime/app/components/settings/ObserveServiceFormModal.vue +192 -0
- package/dist/runtime/app/components/settings/ObserveServiceFormModal.vue.d.ts +37 -0
- package/dist/runtime/app/components/settings/ObserveServiceTypeBadge.d.vue.ts +11 -0
- package/dist/runtime/app/components/settings/ObserveServiceTypeBadge.vue +18 -0
- package/dist/runtime/app/components/settings/ObserveServiceTypeBadge.vue.d.ts +11 -0
- package/dist/runtime/app/components/settings/ObserveSettingsServicesTable.d.vue.ts +19 -0
- package/dist/runtime/app/components/settings/ObserveSettingsServicesTable.vue +132 -0
- package/dist/runtime/app/components/settings/ObserveSettingsServicesTable.vue.d.ts +19 -0
- package/dist/runtime/app/components/settings/ObserveUserFormModal.d.vue.ts +27 -0
- package/dist/runtime/app/components/settings/ObserveUserFormModal.vue +108 -0
- package/dist/runtime/app/components/settings/ObserveUserFormModal.vue.d.ts +27 -0
- package/dist/runtime/app/components/settings/ObserveVersionTrackingField.d.vue.ts +17 -0
- package/dist/runtime/app/components/settings/ObserveVersionTrackingField.vue +20 -0
- package/dist/runtime/app/components/settings/ObserveVersionTrackingField.vue.d.ts +17 -0
- package/dist/runtime/app/composables/useObserveAbility.d.ts +15 -0
- package/dist/runtime/app/composables/useObserveAbility.js +20 -0
- package/dist/runtime/app/composables/useObserveActivity.d.ts +22 -0
- package/dist/runtime/app/composables/useObserveActivity.js +44 -0
- package/dist/runtime/app/composables/useObserveApiKeys.d.ts +15 -0
- package/dist/runtime/app/composables/useObserveApiKeys.js +19 -0
- package/dist/runtime/app/composables/useObserveAssignments.d.ts +19 -0
- package/dist/runtime/app/composables/useObserveAssignments.js +16 -0
- package/dist/runtime/app/composables/useObserveErrors.d.ts +33 -0
- package/dist/runtime/app/composables/useObserveErrors.js +85 -0
- package/dist/runtime/app/composables/useObserveGroups.d.ts +27 -0
- package/dist/runtime/app/composables/useObserveGroups.js +33 -0
- package/dist/runtime/app/composables/useObserveJourney.d.ts +19 -0
- package/dist/runtime/app/composables/useObserveJourney.js +19 -0
- package/dist/runtime/app/composables/useObserveLogFacets.d.ts +11 -0
- package/dist/runtime/app/composables/useObserveLogFacets.js +21 -0
- package/dist/runtime/app/composables/useObserveLogs.d.ts +28 -0
- package/dist/runtime/app/composables/useObserveLogs.js +100 -0
- package/dist/runtime/app/composables/useObserveMigrations.d.ts +17 -0
- package/dist/runtime/app/composables/useObserveMigrations.js +49 -0
- package/dist/runtime/app/composables/useObserveOverview.d.ts +14 -0
- package/dist/runtime/app/composables/useObserveOverview.js +23 -0
- package/dist/runtime/app/composables/useObservePeriod.d.ts +11 -0
- package/dist/runtime/app/composables/useObservePeriod.js +18 -0
- package/dist/runtime/app/composables/useObserveRollout.d.ts +20 -0
- package/dist/runtime/app/composables/useObserveRollout.js +55 -0
- package/dist/runtime/app/composables/useObserveScope.d.ts +13 -0
- package/dist/runtime/app/composables/useObserveScope.js +17 -0
- package/dist/runtime/app/composables/useObserveServices.d.ts +26 -0
- package/dist/runtime/app/composables/useObserveServices.js +33 -0
- package/dist/runtime/app/composables/useObserveStats.d.ts +14 -0
- package/dist/runtime/app/composables/useObserveStats.js +23 -0
- package/dist/runtime/app/composables/useObserveUsers.d.ts +29 -0
- package/dist/runtime/app/composables/useObserveUsers.js +33 -0
- package/dist/runtime/app/layouts/observe.d.vue.ts +13 -0
- package/dist/runtime/app/layouts/observe.vue +138 -0
- package/dist/runtime/app/layouts/observe.vue.d.ts +13 -0
- package/dist/runtime/app/middleware/observe-auth.global.d.ts +9 -0
- package/dist/runtime/app/middleware/observe-auth.global.js +8 -0
- package/dist/runtime/app/pages/activity.d.vue.ts +3 -0
- package/dist/runtime/app/pages/activity.vue +54 -0
- package/dist/runtime/app/pages/activity.vue.d.ts +3 -0
- package/dist/runtime/app/pages/error-detail.d.vue.ts +3 -0
- package/dist/runtime/app/pages/error-detail.vue +190 -0
- package/dist/runtime/app/pages/error-detail.vue.d.ts +3 -0
- package/dist/runtime/app/pages/errors.d.vue.ts +3 -0
- package/dist/runtime/app/pages/errors.vue +47 -0
- package/dist/runtime/app/pages/errors.vue.d.ts +3 -0
- package/dist/runtime/app/pages/journey.d.vue.ts +3 -0
- package/dist/runtime/app/pages/journey.vue +96 -0
- package/dist/runtime/app/pages/journey.vue.d.ts +3 -0
- package/dist/runtime/app/pages/log-detail.d.vue.ts +3 -0
- package/dist/runtime/app/pages/log-detail.vue +35 -0
- package/dist/runtime/app/pages/log-detail.vue.d.ts +3 -0
- package/dist/runtime/app/pages/login.d.vue.ts +3 -0
- package/dist/runtime/app/pages/login.vue +69 -0
- package/dist/runtime/app/pages/login.vue.d.ts +3 -0
- package/dist/runtime/app/pages/logs.d.vue.ts +3 -0
- package/dist/runtime/app/pages/logs.vue +36 -0
- package/dist/runtime/app/pages/logs.vue.d.ts +3 -0
- package/dist/runtime/app/pages/metrics.d.vue.ts +3 -0
- package/dist/runtime/app/pages/metrics.vue +68 -0
- package/dist/runtime/app/pages/metrics.vue.d.ts +3 -0
- package/dist/runtime/app/pages/overview.d.vue.ts +3 -0
- package/dist/runtime/app/pages/overview.vue +65 -0
- package/dist/runtime/app/pages/overview.vue.d.ts +3 -0
- package/dist/runtime/app/pages/rollout.d.vue.ts +3 -0
- package/dist/runtime/app/pages/rollout.vue +188 -0
- package/dist/runtime/app/pages/rollout.vue.d.ts +3 -0
- package/dist/runtime/app/pages/settings/group-detail.d.vue.ts +3 -0
- package/dist/runtime/app/pages/settings/group-detail.vue +149 -0
- package/dist/runtime/app/pages/settings/group-detail.vue.d.ts +3 -0
- package/dist/runtime/app/pages/settings/groups.d.vue.ts +3 -0
- package/dist/runtime/app/pages/settings/groups.vue +107 -0
- package/dist/runtime/app/pages/settings/groups.vue.d.ts +3 -0
- package/dist/runtime/app/pages/settings/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/settings/index.vue +47 -0
- package/dist/runtime/app/pages/settings/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/settings/migrations.d.vue.ts +3 -0
- package/dist/runtime/app/pages/settings/migrations.vue +275 -0
- package/dist/runtime/app/pages/settings/migrations.vue.d.ts +3 -0
- package/dist/runtime/app/pages/settings/service-detail.d.vue.ts +3 -0
- package/dist/runtime/app/pages/settings/service-detail.vue +133 -0
- package/dist/runtime/app/pages/settings/service-detail.vue.d.ts +3 -0
- package/dist/runtime/app/pages/settings/services.d.vue.ts +3 -0
- package/dist/runtime/app/pages/settings/services.vue +66 -0
- package/dist/runtime/app/pages/settings/services.vue.d.ts +3 -0
- package/dist/runtime/app/pages/settings/users/[id].d.vue.ts +3 -0
- package/dist/runtime/app/pages/settings/users/[id].vue +243 -0
- package/dist/runtime/app/pages/settings/users/[id].vue.d.ts +3 -0
- package/dist/runtime/app/pages/settings/users/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/settings/users/index.vue +129 -0
- package/dist/runtime/app/pages/settings/users/index.vue.d.ts +3 -0
- package/dist/runtime/options.d.ts +1 -0
- package/dist/runtime/options.js +1 -0
- package/dist/runtime/server/api/observe/activity.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/activity.get.js +30 -0
- package/dist/runtime/server/api/observe/auth/login.post.d.ts +4 -0
- package/dist/runtime/server/api/observe/auth/login.post.js +13 -0
- package/dist/runtime/server/api/observe/auth/logout.post.d.ts +4 -0
- package/dist/runtime/server/api/observe/auth/logout.post.js +6 -0
- package/dist/runtime/server/api/observe/auth/me.get.d.ts +2 -0
- package/dist/runtime/server/api/observe/auth/me.get.js +3 -0
- package/dist/runtime/server/api/observe/errors/[fingerprint].get.d.ts +3 -0
- package/dist/runtime/server/api/observe/errors/[fingerprint].get.js +56 -0
- package/dist/runtime/server/api/observe/errors/index.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/errors/index.get.js +41 -0
- package/dist/runtime/server/api/observe/facets.get.d.ts +8 -0
- package/dist/runtime/server/api/observe/facets.get.js +12 -0
- package/dist/runtime/server/api/observe/groups/[id]/assignments.put.d.ts +3 -0
- package/dist/runtime/server/api/observe/groups/[id]/assignments.put.js +12 -0
- package/dist/runtime/server/api/observe/groups/[id]/services.put.d.ts +5 -0
- package/dist/runtime/server/api/observe/groups/[id]/services.put.js +13 -0
- package/dist/runtime/server/api/observe/groups/[id].delete.d.ts +5 -0
- package/dist/runtime/server/api/observe/groups/[id].delete.js +11 -0
- package/dist/runtime/server/api/observe/groups/[id].get.d.ts +6 -0
- package/dist/runtime/server/api/observe/groups/[id].get.js +14 -0
- package/dist/runtime/server/api/observe/groups/[id].patch.d.ts +3 -0
- package/dist/runtime/server/api/observe/groups/[id].patch.js +12 -0
- package/dist/runtime/server/api/observe/groups/index.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/groups/index.get.js +7 -0
- package/dist/runtime/server/api/observe/groups/index.post.d.ts +3 -0
- package/dist/runtime/server/api/observe/groups/index.post.js +11 -0
- package/dist/runtime/server/api/observe/health.get.d.ts +6 -0
- package/dist/runtime/server/api/observe/health.get.js +10 -0
- package/dist/runtime/server/api/observe/ingest/frogger.d.ts +5 -0
- package/dist/runtime/server/api/observe/ingest/frogger.js +42 -0
- package/dist/runtime/server/api/observe/ingest.d.ts +5 -0
- package/dist/runtime/server/api/observe/ingest.js +38 -0
- package/dist/runtime/server/api/observe/journey.get.d.ts +9 -0
- package/dist/runtime/server/api/observe/journey.get.js +31 -0
- package/dist/runtime/server/api/observe/logs/[id].get.d.ts +3 -0
- package/dist/runtime/server/api/observe/logs/[id].get.js +19 -0
- package/dist/runtime/server/api/observe/logs.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/logs.get.js +54 -0
- package/dist/runtime/server/api/observe/migrations/index.get.d.ts +9 -0
- package/dist/runtime/server/api/observe/migrations/index.get.js +14 -0
- package/dist/runtime/server/api/observe/migrations/run.post.d.ts +13 -0
- package/dist/runtime/server/api/observe/migrations/run.post.js +35 -0
- package/dist/runtime/server/api/observe/overview.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/overview.get.js +19 -0
- package/dist/runtime/server/api/observe/rollout/compare.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/rollout/compare.get.js +24 -0
- package/dist/runtime/server/api/observe/rollout/regressions.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/rollout/regressions.get.js +31 -0
- package/dist/runtime/server/api/observe/rollout/versions.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/rollout/versions.get.js +20 -0
- package/dist/runtime/server/api/observe/services/[id]/assignments.put.d.ts +7 -0
- package/dist/runtime/server/api/observe/services/[id]/assignments.put.js +12 -0
- package/dist/runtime/server/api/observe/services/[id]/keys/[keyId]/rotate.post.d.ts +4 -0
- package/dist/runtime/server/api/observe/services/[id]/keys/[keyId]/rotate.post.js +14 -0
- package/dist/runtime/server/api/observe/services/[id]/keys/[keyId].delete.d.ts +4 -0
- package/dist/runtime/server/api/observe/services/[id]/keys/[keyId].delete.js +14 -0
- package/dist/runtime/server/api/observe/services/[id]/keys/index.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/services/[id]/keys/index.get.js +10 -0
- package/dist/runtime/server/api/observe/services/[id]/keys/index.post.d.ts +3 -0
- package/dist/runtime/server/api/observe/services/[id]/keys/index.post.js +11 -0
- package/dist/runtime/server/api/observe/services/[id]/restore.post.d.ts +4 -0
- package/dist/runtime/server/api/observe/services/[id]/restore.post.js +11 -0
- package/dist/runtime/server/api/observe/services/[id].delete.d.ts +11 -0
- package/dist/runtime/server/api/observe/services/[id].delete.js +11 -0
- package/dist/runtime/server/api/observe/services/[id].get.d.ts +3 -0
- package/dist/runtime/server/api/observe/services/[id].get.js +12 -0
- package/dist/runtime/server/api/observe/services/[id].patch.d.ts +3 -0
- package/dist/runtime/server/api/observe/services/[id].patch.js +13 -0
- package/dist/runtime/server/api/observe/services/index.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/services/index.get.js +7 -0
- package/dist/runtime/server/api/observe/services/index.post.d.ts +3 -0
- package/dist/runtime/server/api/observe/services/index.post.js +16 -0
- package/dist/runtime/server/api/observe/stats.get.d.ts +3 -0
- package/dist/runtime/server/api/observe/stats.get.js +28 -0
- package/dist/runtime/server/api/observe/users/[id]/assignments.put.d.ts +3 -0
- package/dist/runtime/server/api/observe/users/[id]/assignments.put.js +14 -0
- package/dist/runtime/server/api/observe/users/[id].delete.d.ts +4 -0
- package/dist/runtime/server/api/observe/users/[id].delete.js +15 -0
- package/dist/runtime/server/api/observe/users/[id].get.d.ts +3 -0
- package/dist/runtime/server/api/observe/users/[id].get.js +11 -0
- package/dist/runtime/server/api/observe/users/[id].patch.d.ts +3 -0
- package/dist/runtime/server/api/observe/users/[id].patch.js +25 -0
- package/dist/runtime/server/api/observe/users/index.get.d.ts +8 -0
- package/dist/runtime/server/api/observe/users/index.get.js +7 -0
- package/dist/runtime/server/api/observe/users/index.post.d.ts +3 -0
- package/dist/runtime/server/api/observe/users/index.post.js +29 -0
- package/dist/runtime/server/auth/authorization.d.ts +7 -0
- package/dist/runtime/server/auth/authorization.js +5 -0
- package/dist/runtime/server/auth/provider.d.ts +17 -0
- package/dist/runtime/server/auth/provider.js +44 -0
- package/dist/runtime/server/auth/providers/config-provider.d.ts +18 -0
- package/dist/runtime/server/auth/providers/config-provider.js +54 -0
- package/dist/runtime/server/auth/providers/db-provider.d.ts +16 -0
- package/dist/runtime/server/auth/providers/db-provider.js +42 -0
- package/dist/runtime/server/auth/providers/jwt-provider.d.ts +24 -0
- package/dist/runtime/server/auth/providers/jwt-provider.js +72 -0
- package/dist/runtime/server/migrations/0001-services-kind.d.ts +8 -0
- package/dist/runtime/server/migrations/0001-services-kind.js +14 -0
- package/dist/runtime/server/migrations/0002-services-type.d.ts +7 -0
- package/dist/runtime/server/migrations/0002-services-type.js +14 -0
- package/dist/runtime/server/migrations/0003-services-deleted-at.d.ts +6 -0
- package/dist/runtime/server/migrations/0003-services-deleted-at.js +14 -0
- package/dist/runtime/server/migrations/0004-logs-error-fingerprint.d.ts +11 -0
- package/dist/runtime/server/migrations/0004-logs-error-fingerprint.js +15 -0
- package/dist/runtime/server/migrations/0005-users-columns.d.ts +9 -0
- package/dist/runtime/server/migrations/0005-users-columns.js +25 -0
- package/dist/runtime/server/migrations/index.d.ts +13 -0
- package/dist/runtime/server/migrations/index.js +13 -0
- package/dist/runtime/server/migrations/types.d.ts +15 -0
- package/dist/runtime/server/migrations/types.js +0 -0
- package/dist/runtime/server/plugins/observe-migrate.server.d.ts +2 -0
- package/dist/runtime/server/plugins/observe-migrate.server.js +18 -0
- package/dist/runtime/server/tasks/backfill-fingerprints.d.ts +11 -0
- package/dist/runtime/server/tasks/backfill-fingerprints.js +41 -0
- package/dist/runtime/server/tasks/purge.d.ts +5 -0
- package/dist/runtime/server/tasks/purge.js +12 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/activity-query.d.ts +28 -0
- package/dist/runtime/server/utils/activity-query.js +70 -0
- package/dist/runtime/server/utils/api-keys.d.ts +48 -0
- package/dist/runtime/server/utils/api-keys.js +67 -0
- package/dist/runtime/server/utils/authz.d.ts +50 -0
- package/dist/runtime/server/utils/authz.js +60 -0
- package/dist/runtime/server/utils/db/users.d.ts +91 -0
- package/dist/runtime/server/utils/db/users.js +128 -0
- package/dist/runtime/server/utils/db.d.ts +10 -0
- package/dist/runtime/server/utils/db.js +5 -0
- package/dist/runtime/server/utils/frogger-adapter.d.ts +40 -0
- package/dist/runtime/server/utils/frogger-adapter.js +97 -0
- package/dist/runtime/server/utils/groups.d.ts +35 -0
- package/dist/runtime/server/utils/groups.js +59 -0
- package/dist/runtime/server/utils/ingest-cors.d.ts +23 -0
- package/dist/runtime/server/utils/ingest-cors.js +27 -0
- package/dist/runtime/server/utils/journey.d.ts +20 -0
- package/dist/runtime/server/utils/journey.js +44 -0
- package/dist/runtime/server/utils/logs.d.ts +50 -0
- package/dist/runtime/server/utils/logs.js +154 -0
- package/dist/runtime/server/utils/loop-guard.d.ts +11 -0
- package/dist/runtime/server/utils/loop-guard.js +11 -0
- package/dist/runtime/server/utils/migrate.d.ts +21 -0
- package/dist/runtime/server/utils/migrate.js +144 -0
- package/dist/runtime/server/utils/migration-runner.d.ts +42 -0
- package/dist/runtime/server/utils/migration-runner.js +129 -0
- package/dist/runtime/server/utils/observe-errors.d.ts +58 -0
- package/dist/runtime/server/utils/observe-errors.js +206 -0
- package/dist/runtime/server/utils/overview.d.ts +20 -0
- package/dist/runtime/server/utils/overview.js +119 -0
- package/dist/runtime/server/utils/provisioning.d.ts +62 -0
- package/dist/runtime/server/utils/provisioning.js +299 -0
- package/dist/runtime/server/utils/rate-limit.d.ts +11 -0
- package/dist/runtime/server/utils/rate-limit.js +22 -0
- package/dist/runtime/server/utils/require-observe-session.d.ts +15 -0
- package/dist/runtime/server/utils/require-observe-session.js +25 -0
- package/dist/runtime/server/utils/rollout.d.ts +19 -0
- package/dist/runtime/server/utils/rollout.js +56 -0
- package/dist/runtime/server/utils/scope.d.ts +14 -0
- package/dist/runtime/server/utils/scope.js +28 -0
- package/dist/runtime/server/utils/seed.d.ts +18 -0
- package/dist/runtime/server/utils/seed.js +70 -0
- package/dist/runtime/server/utils/services.d.ts +91 -0
- package/dist/runtime/server/utils/services.js +142 -0
- package/dist/runtime/server/utils/stats-query.d.ts +40 -0
- package/dist/runtime/server/utils/stats-query.js +104 -0
- package/dist/runtime/shared/auth/roles.d.ts +34 -0
- package/dist/runtime/shared/auth/roles.js +6 -0
- package/dist/runtime/shared/auth/schema.d.ts +85 -0
- package/dist/runtime/shared/auth/schema.js +41 -0
- package/dist/runtime/shared/auth/types.d.ts +68 -0
- package/dist/runtime/shared/auth/types.js +0 -0
- package/dist/runtime/shared/rbac/capabilities.d.ts +46 -0
- package/dist/runtime/shared/rbac/capabilities.js +48 -0
- package/dist/runtime/shared/schema/activity.d.ts +77 -0
- package/dist/runtime/shared/schema/activity.js +22 -0
- package/dist/runtime/shared/schema/adapters/frogger.d.ts +52 -0
- package/dist/runtime/shared/schema/adapters/frogger.js +17 -0
- package/dist/runtime/shared/schema/batch.d.ts +33 -0
- package/dist/runtime/shared/schema/batch.js +9 -0
- package/dist/runtime/shared/schema/error-fingerprint.d.ts +53 -0
- package/dist/runtime/shared/schema/error-fingerprint.js +47 -0
- package/dist/runtime/shared/schema/errors-query.d.ts +136 -0
- package/dist/runtime/shared/schema/errors-query.js +47 -0
- package/dist/runtime/shared/schema/event.d.ts +48 -0
- package/dist/runtime/shared/schema/event.js +41 -0
- package/dist/runtime/shared/schema/frogger-map.d.ts +62 -0
- package/dist/runtime/shared/schema/frogger-map.js +30 -0
- package/dist/runtime/shared/schema/index.d.ts +17 -0
- package/dist/runtime/shared/schema/index.js +17 -0
- package/dist/runtime/shared/schema/journey.d.ts +99 -0
- package/dist/runtime/shared/schema/journey.js +96 -0
- package/dist/runtime/shared/schema/levels.d.ts +37 -0
- package/dist/runtime/shared/schema/levels.js +72 -0
- package/dist/runtime/shared/schema/log-row.d.ts +31 -0
- package/dist/runtime/shared/schema/log-row.js +0 -0
- package/dist/runtime/shared/schema/logs-query.d.ts +91 -0
- package/dist/runtime/shared/schema/logs-query.js +72 -0
- package/dist/runtime/shared/schema/migrations.d.ts +34 -0
- package/dist/runtime/shared/schema/migrations.js +0 -0
- package/dist/runtime/shared/schema/overview.d.ts +78 -0
- package/dist/runtime/shared/schema/overview.js +9 -0
- package/dist/runtime/shared/schema/provisioning.d.ts +230 -0
- package/dist/runtime/shared/schema/provisioning.js +52 -0
- package/dist/runtime/shared/schema/registry.d.ts +115 -0
- package/dist/runtime/shared/schema/registry.js +27 -0
- package/dist/runtime/shared/schema/rollout.d.ts +103 -0
- package/dist/runtime/shared/schema/rollout.js +66 -0
- package/dist/runtime/shared/schema/stats.d.ts +64 -0
- package/dist/runtime/shared/schema/stats.js +15 -0
- package/dist/runtime/shared/schema/tiers.d.ts +5 -0
- package/dist/runtime/shared/schema/tiers.js +9 -0
- package/dist/runtime/shared/types/module-options.d.ts +119 -0
- package/dist/runtime/shared/types/module-options.js +13 -0
- package/dist/runtime/shared/types/storage.d.ts +31 -0
- package/dist/runtime/shared/types/storage.js +0 -0
- package/dist/runtime/shared/utils/format-relative.d.ts +7 -0
- package/dist/runtime/shared/utils/format-relative.js +11 -0
- package/dist/runtime/shared/utils/frogger-snippet.d.ts +19 -0
- package/dist/runtime/shared/utils/frogger-snippet.js +33 -0
- package/dist/runtime/shared/utils/observe-config.d.ts +9 -0
- package/dist/runtime/shared/utils/observe-config.js +17 -0
- package/dist/runtime/shared/utils/period.d.ts +13 -0
- package/dist/runtime/shared/utils/period.js +15 -0
- package/dist/runtime/shared/utils/slug.d.ts +1 -0
- package/dist/runtime/shared/utils/slug.js +5 -0
- package/dist/runtime/shared/utils/uuid.d.ts +187 -0
- package/dist/runtime/shared/utils/uuid.js +345 -0
- package/dist/runtime/types/nuxt-auth-utils-imports.d.ts +25 -0
- package/dist/runtime/types/observe-app-imports.d.ts +20 -0
- package/dist/runtime/types/session.d.ts +17 -0
- package/dist/schema.d.mts +1318 -0
- package/dist/schema.mjs +629 -0
- package/dist/types.d.mts +3 -0
- package/package.json +93 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type H3Event } from 'h3';
|
|
2
|
+
import { type Database } from './db.js';
|
|
3
|
+
interface DbOpts {
|
|
4
|
+
db?: Database;
|
|
5
|
+
}
|
|
6
|
+
export declare function hashApiKey(raw: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Mint a new ingest key for a service. The raw key is returned exactly ONCE;
|
|
9
|
+
* only its sha256 hash + a short prefix (for UI identification) are persisted.
|
|
10
|
+
*/
|
|
11
|
+
export declare function mintApiKey(serviceId: string, label?: string, opts?: DbOpts): Promise<{
|
|
12
|
+
id: string;
|
|
13
|
+
raw: string;
|
|
14
|
+
prefix: string;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Frogger's client transport sends no auth header by default (bare $fetch), so
|
|
18
|
+
* the `?key=` query path is mandatory; `x-api-key` is the alternative for BYO sources.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getApiKeyFromEvent(event: H3Event): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a raw key to its service id. Single indexed key_hash lookup with a
|
|
23
|
+
* revoked filter; preimage resistance replaces a constant-time compare. Bumps
|
|
24
|
+
* last_used_at best-effort. Returns null for an unknown or revoked key.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveServiceIdByKey(raw: string, opts?: DbOpts): Promise<string | null>;
|
|
27
|
+
export declare function revokeApiKey(id: string, opts?: DbOpts): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Atomic key rotation: revoke `oldKeyId` and mint a fresh key for the same service
|
|
30
|
+
* in one transaction, so a client is never left with two live keys or none. The new
|
|
31
|
+
* raw key is returned exactly ONCE (same contract as mintApiKey). The mint SQL is
|
|
32
|
+
* inlined rather than calling mintApiKey so it shares the single BEGIN.
|
|
33
|
+
*/
|
|
34
|
+
export declare function rotateApiKey(oldKeyId: string, serviceId: string, label?: string, opts?: DbOpts): Promise<{
|
|
35
|
+
id: string;
|
|
36
|
+
raw: string;
|
|
37
|
+
prefix: string;
|
|
38
|
+
}>;
|
|
39
|
+
/** Lists a service's keys WITHOUT ever exposing key_hash or the raw key. */
|
|
40
|
+
export declare function listApiKeys(serviceId: string, opts?: DbOpts): Promise<Array<{
|
|
41
|
+
id: string;
|
|
42
|
+
key_prefix: string;
|
|
43
|
+
label: string | null;
|
|
44
|
+
created_at: number;
|
|
45
|
+
revoked_at: number | null;
|
|
46
|
+
last_used_at: number | null;
|
|
47
|
+
}>>;
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { getQuery, getHeader } from "h3";
|
|
3
|
+
import { uuidv7 } from "../../shared/utils/uuid.js";
|
|
4
|
+
import { useObserveDb } from "./db.js";
|
|
5
|
+
const KEY_PREFIX = "obsk_";
|
|
6
|
+
export function hashApiKey(raw) {
|
|
7
|
+
return createHash("sha256").update(raw).digest("hex");
|
|
8
|
+
}
|
|
9
|
+
export async function mintApiKey(serviceId, label, opts = {}) {
|
|
10
|
+
const db = opts.db ?? useObserveDb();
|
|
11
|
+
const raw = KEY_PREFIX + randomBytes(32).toString("base64url");
|
|
12
|
+
const prefix = raw.slice(0, KEY_PREFIX.length + 6);
|
|
13
|
+
const id = uuidv7();
|
|
14
|
+
await db.sql`
|
|
15
|
+
INSERT INTO api_keys (id, service_id, key_hash, key_prefix, label, created_at)
|
|
16
|
+
VALUES (${id}, ${serviceId}, ${hashApiKey(raw)}, ${prefix}, ${label ?? null}, ${Date.now()})
|
|
17
|
+
`;
|
|
18
|
+
return { id, raw, prefix };
|
|
19
|
+
}
|
|
20
|
+
export function getApiKeyFromEvent(event) {
|
|
21
|
+
const fromQuery = getQuery(event).key;
|
|
22
|
+
if (typeof fromQuery === "string" && fromQuery.length > 0) return fromQuery;
|
|
23
|
+
const fromHeader = getHeader(event, "x-api-key");
|
|
24
|
+
return fromHeader && fromHeader.length > 0 ? fromHeader : null;
|
|
25
|
+
}
|
|
26
|
+
export async function resolveServiceIdByKey(raw, opts = {}) {
|
|
27
|
+
const db = opts.db ?? useObserveDb();
|
|
28
|
+
const row = await db.prepare(
|
|
29
|
+
"SELECT id, service_id FROM api_keys WHERE key_hash = ? AND revoked_at IS NULL"
|
|
30
|
+
).get(hashApiKey(raw));
|
|
31
|
+
if (!row) return null;
|
|
32
|
+
try {
|
|
33
|
+
await db.sql`UPDATE api_keys SET last_used_at = ${Date.now()} WHERE id = ${row.id}`;
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
return row.service_id;
|
|
37
|
+
}
|
|
38
|
+
export async function revokeApiKey(id, opts = {}) {
|
|
39
|
+
const db = opts.db ?? useObserveDb();
|
|
40
|
+
await db.sql`UPDATE api_keys SET revoked_at = ${Date.now()} WHERE id = ${id}`;
|
|
41
|
+
}
|
|
42
|
+
export async function rotateApiKey(oldKeyId, serviceId, label, opts = {}) {
|
|
43
|
+
const db = opts.db ?? useObserveDb();
|
|
44
|
+
const raw = KEY_PREFIX + randomBytes(32).toString("base64url");
|
|
45
|
+
const prefix = raw.slice(0, KEY_PREFIX.length + 6);
|
|
46
|
+
const id = uuidv7();
|
|
47
|
+
const now = Date.now();
|
|
48
|
+
await db.sql`BEGIN`;
|
|
49
|
+
try {
|
|
50
|
+
await db.sql`UPDATE api_keys SET revoked_at = ${now} WHERE id = ${oldKeyId} AND service_id = ${serviceId}`;
|
|
51
|
+
await db.sql`
|
|
52
|
+
INSERT INTO api_keys (id, service_id, key_hash, key_prefix, label, created_at)
|
|
53
|
+
VALUES (${id}, ${serviceId}, ${hashApiKey(raw)}, ${prefix}, ${label ?? null}, ${now})
|
|
54
|
+
`;
|
|
55
|
+
await db.sql`COMMIT`;
|
|
56
|
+
} catch (e) {
|
|
57
|
+
await db.sql`ROLLBACK`;
|
|
58
|
+
throw e;
|
|
59
|
+
}
|
|
60
|
+
return { id, raw, prefix };
|
|
61
|
+
}
|
|
62
|
+
export async function listApiKeys(serviceId, opts = {}) {
|
|
63
|
+
const db = opts.db ?? useObserveDb();
|
|
64
|
+
return await db.prepare(
|
|
65
|
+
"SELECT id, key_prefix, label, created_at, revoked_at, last_used_at FROM api_keys WHERE service_id = ? ORDER BY created_at"
|
|
66
|
+
).all(serviceId);
|
|
67
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import type { Principal } from '../../shared/auth/types.js';
|
|
3
|
+
import type { Capability, Scope } from '../../shared/rbac/capabilities.js';
|
|
4
|
+
import { type Database } from './db.js';
|
|
5
|
+
interface DbOpts {
|
|
6
|
+
db?: Database;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The single server-side authorization choke point every gated /api/observe/* route
|
|
10
|
+
* composes. Resolves the session first (requireObserveSession throws 401 when absent),
|
|
11
|
+
* then the (role, capability) scope. A capability the role holds at no scope is the ONLY
|
|
12
|
+
* 403 CP6 mints; the 401 is never hand-rolled. Returns the resolved scope so the caller
|
|
13
|
+
* decides whether it must additionally scope rows (serviceScopeFilter) or a named
|
|
14
|
+
* resource (assertServiceInScope). No DB access happens here, so nothing is caught.
|
|
15
|
+
*/
|
|
16
|
+
export declare function requireCapability(event: H3Event, capability: Capability): Promise<{
|
|
17
|
+
principal: Principal;
|
|
18
|
+
scope: Exclude<Scope, 'none'>;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Expand a principal's slug-level Assignment into the concrete service ids it may act on,
|
|
22
|
+
* memoized on event.context.observe for the request so the group->service expansion query
|
|
23
|
+
* runs at most once even when a route calls both serviceScopeFilter and assertServiceInScope.
|
|
24
|
+
* Returns '*' for an admin (any '*' in services/groups => no restriction) or a possibly-empty
|
|
25
|
+
* id list. IDs are TEXT (uuidv7), hence string[] — not number[].
|
|
26
|
+
*/
|
|
27
|
+
export declare function getAllowedServiceIds(event: H3Event, principal: Principal, opts?: DbOpts): Promise<string[] | '*'>;
|
|
28
|
+
/**
|
|
29
|
+
* A bare boolean SQL fragment (NO `WHERE` keyword) callers AND into any query to scope it
|
|
30
|
+
* by service. Three shapes: '' = no restriction (admin); '1=0' = matches nothing (empty
|
|
31
|
+
* assignment — a 200-with-zero-rows, never an error); `service_id IN (?,?)` otherwise.
|
|
32
|
+
* Splice `params` in positional order. `opts.column` retargets the id column for
|
|
33
|
+
* services/api-keys queries; `opts.db` injects a connection for unit tests. See
|
|
34
|
+
* CP6-HANDOFF §4.6 for the two composition patterns (LogFilter.serviceIds vs. this fragment).
|
|
35
|
+
*/
|
|
36
|
+
export declare function serviceScopeFilter(event: H3Event, principal: Principal, opts?: {
|
|
37
|
+
column?: string;
|
|
38
|
+
db?: Database;
|
|
39
|
+
}): Promise<{
|
|
40
|
+
clause: string;
|
|
41
|
+
params: string[];
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* 403 when a principal names a service id outside its scope. For write/detail routes that
|
|
45
|
+
* take a validated :id (validate with getValidatedRouterParams -> 400 BEFORE this call).
|
|
46
|
+
* Admin ('*') and in-scope ids pass silently. 403 (not 404) is intentional: in a
|
|
47
|
+
* self-hosted single-tenant dashboard, existence is not sensitive (CP6-HANDOFF §9.7).
|
|
48
|
+
*/
|
|
49
|
+
export declare function assertServiceInScope(event: H3Event, principal: Principal, serviceId: string, opts?: DbOpts): Promise<void>;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createError } from "h3";
|
|
2
|
+
import { roleCan } from "../../shared/rbac/capabilities.js";
|
|
3
|
+
import { requireObserveSession } from "./require-observe-session.js";
|
|
4
|
+
import { useObserveDb } from "./db.js";
|
|
5
|
+
export async function requireCapability(event, capability) {
|
|
6
|
+
const principal = await requireObserveSession(event);
|
|
7
|
+
const scope = roleCan(principal.role, capability);
|
|
8
|
+
if (!scope || scope === "none") {
|
|
9
|
+
throw createError({
|
|
10
|
+
statusCode: 403,
|
|
11
|
+
statusMessage: "Forbidden",
|
|
12
|
+
data: { error: "FORBIDDEN", capability }
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return { principal, scope };
|
|
16
|
+
}
|
|
17
|
+
export async function getAllowedServiceIds(event, principal, opts = {}) {
|
|
18
|
+
const ctx = event.context.observe ??= {};
|
|
19
|
+
if (ctx.allowedServiceIds !== void 0) return ctx.allowedServiceIds;
|
|
20
|
+
const { services, groups } = principal.assignment;
|
|
21
|
+
if (services.includes("*") || groups.includes("*")) {
|
|
22
|
+
return ctx.allowedServiceIds = "*";
|
|
23
|
+
}
|
|
24
|
+
if (services.length === 0 && groups.length === 0) {
|
|
25
|
+
return ctx.allowedServiceIds = [];
|
|
26
|
+
}
|
|
27
|
+
const db = opts.db ?? useObserveDb();
|
|
28
|
+
const wheres = [];
|
|
29
|
+
const params = [];
|
|
30
|
+
if (services.length) {
|
|
31
|
+
wheres.push(`slug IN (${services.map(() => "?").join(",")})`);
|
|
32
|
+
params.push(...services);
|
|
33
|
+
}
|
|
34
|
+
if (groups.length) {
|
|
35
|
+
wheres.push(`group_id IN (SELECT id FROM groups WHERE slug IN (${groups.map(() => "?").join(",")}))`);
|
|
36
|
+
params.push(...groups);
|
|
37
|
+
}
|
|
38
|
+
const rows = await db.prepare(
|
|
39
|
+
`SELECT id FROM services WHERE ${wheres.join(" OR ")}`
|
|
40
|
+
).all(...params);
|
|
41
|
+
return ctx.allowedServiceIds = rows.map((r) => r.id);
|
|
42
|
+
}
|
|
43
|
+
export async function serviceScopeFilter(event, principal, opts = {}) {
|
|
44
|
+
const column = opts.column ?? "service_id";
|
|
45
|
+
const ids = await getAllowedServiceIds(event, principal, opts);
|
|
46
|
+
if (ids === "*") return { clause: "", params: [] };
|
|
47
|
+
if (ids.length === 0) return { clause: "1=0", params: [] };
|
|
48
|
+
return { clause: `${column} IN (${ids.map(() => "?").join(",")})`, params: ids };
|
|
49
|
+
}
|
|
50
|
+
export async function assertServiceInScope(event, principal, serviceId, opts = {}) {
|
|
51
|
+
const ids = await getAllowedServiceIds(event, principal, opts);
|
|
52
|
+
if (ids === "*") return;
|
|
53
|
+
if (!ids.includes(serviceId)) {
|
|
54
|
+
throw createError({
|
|
55
|
+
statusCode: 403,
|
|
56
|
+
statusMessage: "Forbidden",
|
|
57
|
+
data: { error: "OUT_OF_SCOPE", serviceId }
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Role, Assignment, Principal } from '../../../shared/auth/types.js';
|
|
2
|
+
import { type Database } from '../db.js';
|
|
3
|
+
/**
|
|
4
|
+
* All SQL for DB-backed dashboard users (CP16). Parameterised via db.prepare / db.sql,
|
|
5
|
+
* connection injected `opts.db ?? useObserveDb()` (repo convention). Ids are TEXT uuidv7.
|
|
6
|
+
*
|
|
7
|
+
* The `users` table stores service/group assignments as ids (user_service_roles.service_id,
|
|
8
|
+
* user_group_roles.group_id) but a Principal.assignment carries SLUGS (getAllowedServiceIds
|
|
9
|
+
* expands slugs, not ids). getUserAssignments is the single place that join happens: it
|
|
10
|
+
* returns slugs, never ids. Do not leak raw ids into a Principal, or scoping breaks silently.
|
|
11
|
+
*/
|
|
12
|
+
export interface UserRow {
|
|
13
|
+
id: string;
|
|
14
|
+
username: string;
|
|
15
|
+
display_name: string | null;
|
|
16
|
+
role: Role;
|
|
17
|
+
password_hash: string | null;
|
|
18
|
+
disabled: number;
|
|
19
|
+
source: string;
|
|
20
|
+
created_by: string | null;
|
|
21
|
+
created_at: number;
|
|
22
|
+
updated_at: number | null;
|
|
23
|
+
}
|
|
24
|
+
interface DbOpts {
|
|
25
|
+
db?: Database;
|
|
26
|
+
}
|
|
27
|
+
export interface AssignmentInput {
|
|
28
|
+
services: Array<{
|
|
29
|
+
serviceId: string;
|
|
30
|
+
role: Role;
|
|
31
|
+
}>;
|
|
32
|
+
groups: Array<{
|
|
33
|
+
groupId: string;
|
|
34
|
+
role: Role;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
export declare function listUsers(opts?: DbOpts): Promise<UserRow[]>;
|
|
38
|
+
export declare function getUserById(id: string, opts?: DbOpts): Promise<UserRow | null>;
|
|
39
|
+
export declare function getUserByUsername(username: string, opts?: DbOpts): Promise<UserRow | null>;
|
|
40
|
+
export declare function createUser(input: {
|
|
41
|
+
username: string;
|
|
42
|
+
displayName?: string | null;
|
|
43
|
+
role: Role;
|
|
44
|
+
passwordHash?: string | null;
|
|
45
|
+
createdBy?: string | null;
|
|
46
|
+
}, opts?: DbOpts): Promise<UserRow>;
|
|
47
|
+
export declare function updateUser(id: string, patch: Partial<{
|
|
48
|
+
displayName: string | null;
|
|
49
|
+
role: Role;
|
|
50
|
+
disabled: boolean;
|
|
51
|
+
passwordHash: string | null;
|
|
52
|
+
}>, opts?: DbOpts): Promise<UserRow | null>;
|
|
53
|
+
/**
|
|
54
|
+
* Delete a user and every dependent row (service/group role assignments + identities)
|
|
55
|
+
* in one transaction. FK CASCADE is not enabled on this connection (no per-connection
|
|
56
|
+
* PRAGMA foreign_keys = ON), so dependents are removed explicitly.
|
|
57
|
+
*/
|
|
58
|
+
export declare function deleteUser(id: string, opts?: DbOpts): Promise<void>;
|
|
59
|
+
/** Enabled admins only: the bootstrap-fallback gate and the last-admin guard. */
|
|
60
|
+
export declare function countAdmins(opts?: DbOpts): Promise<number>;
|
|
61
|
+
/**
|
|
62
|
+
* Assignment as SLUGS (not ids): joins user_service_roles.service_id -> services.slug and
|
|
63
|
+
* user_group_roles.group_id -> groups.slug. This is what a Principal.assignment must carry.
|
|
64
|
+
*/
|
|
65
|
+
export declare function getUserAssignments(userId: string, opts?: DbOpts): Promise<Assignment>;
|
|
66
|
+
/**
|
|
67
|
+
* Raw assignment rows (ids + per-scope role) for the management UI, which edits by id and
|
|
68
|
+
* pairs each with a role. Distinct from getUserAssignments, which returns SLUGS for a Principal.
|
|
69
|
+
*/
|
|
70
|
+
export declare function getUserAssignmentRows(userId: string, opts?: DbOpts): Promise<{
|
|
71
|
+
services: Array<{
|
|
72
|
+
serviceId: string;
|
|
73
|
+
role: Role;
|
|
74
|
+
}>;
|
|
75
|
+
groups: Array<{
|
|
76
|
+
groupId: string;
|
|
77
|
+
role: Role;
|
|
78
|
+
}>;
|
|
79
|
+
}>;
|
|
80
|
+
/** Replace a user's full assignment set (service + group roles) in one transaction. */
|
|
81
|
+
export declare function setUserAssignments(userId: string, input: AssignmentInput, opts?: DbOpts): Promise<void>;
|
|
82
|
+
export declare function findUserByIdentity(provider: string, subject: string, opts?: DbOpts): Promise<UserRow | null>;
|
|
83
|
+
/** Link an external identity to a user, idempotent on (provider, subject). */
|
|
84
|
+
export declare function upsertIdentity(userId: string, provider: string, subject: string, opts?: DbOpts): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Assemble a session-shaped Principal from a row + its (slug) assignment. Admins carry the
|
|
87
|
+
* wildcard assignment so getAllowedServiceIds short-circuits; everyone else carries the
|
|
88
|
+
* looked-up slugs. `provider` tags who minted it ('db' by default, 'jwt' for a token identity).
|
|
89
|
+
*/
|
|
90
|
+
export declare function principalFromUser(row: UserRow, assignment: Assignment, provider?: 'db' | 'jwt'): Principal;
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { uuidv7 } from "../../../shared/utils/uuid.js";
|
|
2
|
+
import { ALL } from "../../../shared/auth/roles.js";
|
|
3
|
+
import { useObserveDb } from "../db.js";
|
|
4
|
+
export async function listUsers(opts = {}) {
|
|
5
|
+
const db = opts.db ?? useObserveDb();
|
|
6
|
+
return await db.prepare("SELECT * FROM users ORDER BY username").all();
|
|
7
|
+
}
|
|
8
|
+
export async function getUserById(id, opts = {}) {
|
|
9
|
+
const db = opts.db ?? useObserveDb();
|
|
10
|
+
const row = await db.prepare("SELECT * FROM users WHERE id = ?").get(id);
|
|
11
|
+
return row ?? null;
|
|
12
|
+
}
|
|
13
|
+
export async function getUserByUsername(username, opts = {}) {
|
|
14
|
+
const db = opts.db ?? useObserveDb();
|
|
15
|
+
const row = await db.prepare("SELECT * FROM users WHERE username = ?").get(username);
|
|
16
|
+
return row ?? null;
|
|
17
|
+
}
|
|
18
|
+
export async function createUser(input, opts = {}) {
|
|
19
|
+
const db = opts.db ?? useObserveDb();
|
|
20
|
+
const id = uuidv7();
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
await db.sql`
|
|
23
|
+
INSERT INTO users (id, username, display_name, password_hash, role, disabled, source, created_by, created_at, updated_at)
|
|
24
|
+
VALUES (
|
|
25
|
+
${id}, ${input.username}, ${input.displayName ?? null}, ${input.passwordHash ?? null},
|
|
26
|
+
${input.role}, 0, 'db', ${input.createdBy ?? null}, ${now}, ${now}
|
|
27
|
+
)
|
|
28
|
+
`;
|
|
29
|
+
return await getUserById(id, { db });
|
|
30
|
+
}
|
|
31
|
+
export async function updateUser(id, patch, opts = {}) {
|
|
32
|
+
const db = opts.db ?? useObserveDb();
|
|
33
|
+
const existing = await getUserById(id, { db });
|
|
34
|
+
if (!existing) return null;
|
|
35
|
+
const displayName = "displayName" in patch ? patch.displayName ?? null : existing.display_name;
|
|
36
|
+
const role = patch.role ?? existing.role;
|
|
37
|
+
const disabled = patch.disabled === void 0 ? existing.disabled : patch.disabled ? 1 : 0;
|
|
38
|
+
const passwordHash = "passwordHash" in patch ? patch.passwordHash ?? null : existing.password_hash;
|
|
39
|
+
await db.sql`
|
|
40
|
+
UPDATE users
|
|
41
|
+
SET display_name = ${displayName}, role = ${role}, disabled = ${disabled},
|
|
42
|
+
password_hash = ${passwordHash}, updated_at = ${Date.now()}
|
|
43
|
+
WHERE id = ${id}
|
|
44
|
+
`;
|
|
45
|
+
return await getUserById(id, { db });
|
|
46
|
+
}
|
|
47
|
+
export async function deleteUser(id, opts = {}) {
|
|
48
|
+
const db = opts.db ?? useObserveDb();
|
|
49
|
+
await db.sql`BEGIN`;
|
|
50
|
+
try {
|
|
51
|
+
await db.sql`DELETE FROM user_service_roles WHERE user_id = ${id}`;
|
|
52
|
+
await db.sql`DELETE FROM user_group_roles WHERE user_id = ${id}`;
|
|
53
|
+
await db.sql`DELETE FROM user_identities WHERE user_id = ${id}`;
|
|
54
|
+
await db.sql`DELETE FROM users WHERE id = ${id}`;
|
|
55
|
+
await db.sql`COMMIT`;
|
|
56
|
+
} catch (e) {
|
|
57
|
+
await db.sql`ROLLBACK`;
|
|
58
|
+
throw e;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export async function countAdmins(opts = {}) {
|
|
62
|
+
const db = opts.db ?? useObserveDb();
|
|
63
|
+
const row = await db.prepare(`SELECT COUNT(*) AS c FROM users WHERE role = 'admin' AND disabled = 0`).get();
|
|
64
|
+
return row.c;
|
|
65
|
+
}
|
|
66
|
+
export async function getUserAssignments(userId, opts = {}) {
|
|
67
|
+
const db = opts.db ?? useObserveDb();
|
|
68
|
+
const services = await db.prepare(
|
|
69
|
+
`SELECT s.slug AS slug FROM user_service_roles r JOIN services s ON s.id = r.service_id WHERE r.user_id = ? ORDER BY s.slug`
|
|
70
|
+
).all(userId);
|
|
71
|
+
const groups = await db.prepare(
|
|
72
|
+
`SELECT g.slug AS slug FROM user_group_roles r JOIN groups g ON g.id = r.group_id WHERE r.user_id = ? ORDER BY g.slug`
|
|
73
|
+
).all(userId);
|
|
74
|
+
return { services: services.map((r) => r.slug), groups: groups.map((r) => r.slug) };
|
|
75
|
+
}
|
|
76
|
+
export async function getUserAssignmentRows(userId, opts = {}) {
|
|
77
|
+
const db = opts.db ?? useObserveDb();
|
|
78
|
+
const services = await db.prepare(
|
|
79
|
+
"SELECT service_id AS serviceId, role FROM user_service_roles WHERE user_id = ?"
|
|
80
|
+
).all(userId);
|
|
81
|
+
const groups = await db.prepare(
|
|
82
|
+
"SELECT group_id AS groupId, role FROM user_group_roles WHERE user_id = ?"
|
|
83
|
+
).all(userId);
|
|
84
|
+
return { services, groups };
|
|
85
|
+
}
|
|
86
|
+
export async function setUserAssignments(userId, input, opts = {}) {
|
|
87
|
+
const db = opts.db ?? useObserveDb();
|
|
88
|
+
await db.sql`BEGIN`;
|
|
89
|
+
try {
|
|
90
|
+
await db.sql`DELETE FROM user_service_roles WHERE user_id = ${userId}`;
|
|
91
|
+
await db.sql`DELETE FROM user_group_roles WHERE user_id = ${userId}`;
|
|
92
|
+
for (const s of input.services) {
|
|
93
|
+
await db.sql`INSERT INTO user_service_roles (user_id, service_id, role) VALUES (${userId}, ${s.serviceId}, ${s.role})`;
|
|
94
|
+
}
|
|
95
|
+
for (const g of input.groups) {
|
|
96
|
+
await db.sql`INSERT INTO user_group_roles (user_id, group_id, role) VALUES (${userId}, ${g.groupId}, ${g.role})`;
|
|
97
|
+
}
|
|
98
|
+
await db.sql`COMMIT`;
|
|
99
|
+
} catch (e) {
|
|
100
|
+
await db.sql`ROLLBACK`;
|
|
101
|
+
throw e;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export async function findUserByIdentity(provider, subject, opts = {}) {
|
|
105
|
+
const db = opts.db ?? useObserveDb();
|
|
106
|
+
const row = await db.prepare(
|
|
107
|
+
`SELECT u.* FROM users u JOIN user_identities i ON i.user_id = u.id WHERE i.provider = ? AND i.subject = ?`
|
|
108
|
+
).get(provider, subject);
|
|
109
|
+
return row ?? null;
|
|
110
|
+
}
|
|
111
|
+
export async function upsertIdentity(userId, provider, subject, opts = {}) {
|
|
112
|
+
const db = opts.db ?? useObserveDb();
|
|
113
|
+
const id = uuidv7();
|
|
114
|
+
await db.sql`
|
|
115
|
+
INSERT INTO user_identities (id, user_id, provider, subject, created_at)
|
|
116
|
+
VALUES (${id}, ${userId}, ${provider}, ${subject}, ${Date.now()})
|
|
117
|
+
ON CONFLICT (provider, subject) DO UPDATE SET user_id = ${userId}
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
export function principalFromUser(row, assignment, provider = "db") {
|
|
121
|
+
return {
|
|
122
|
+
sub: row.id,
|
|
123
|
+
name: row.display_name ?? row.username,
|
|
124
|
+
role: row.role,
|
|
125
|
+
assignment: row.role === "admin" ? { services: [ALL], groups: [ALL] } : assignment,
|
|
126
|
+
provider
|
|
127
|
+
};
|
|
128
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Database } from 'db0';
|
|
2
|
+
export declare const OBSERVE_DB = "observe";
|
|
3
|
+
/**
|
|
4
|
+
* The one place the module touches Nitro's database layer. A future swap to a
|
|
5
|
+
* direct better-sqlite3 driver changes only this file. Importing `useDatabase`
|
|
6
|
+
* from 'nitropack/runtime' (not '#imports') keeps this file loadable from
|
|
7
|
+
* node-env unit tests, which resolve real package exports but not unimport aliases.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useObserveDb(): Database;
|
|
10
|
+
export type { Database };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CanonicalEvent } from '../../shared/schema/event.js';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal frogger wire shapes (subset of frogger's LoggerObject/LoggerObjectBatch).
|
|
4
|
+
* Only the fields this adapter reads are typed; the rest ride through `ctx`.
|
|
5
|
+
*/
|
|
6
|
+
export interface FroggerLog {
|
|
7
|
+
time: number;
|
|
8
|
+
lvl: number;
|
|
9
|
+
type?: string;
|
|
10
|
+
msg: string;
|
|
11
|
+
ctx?: Record<string, unknown>;
|
|
12
|
+
tags?: string[];
|
|
13
|
+
env?: string;
|
|
14
|
+
source?: {
|
|
15
|
+
name?: string;
|
|
16
|
+
version?: string;
|
|
17
|
+
};
|
|
18
|
+
trace?: {
|
|
19
|
+
traceId?: string;
|
|
20
|
+
spanId?: string;
|
|
21
|
+
parentId?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface FroggerBatch {
|
|
25
|
+
logs: FroggerLog[];
|
|
26
|
+
app?: {
|
|
27
|
+
name?: string;
|
|
28
|
+
version?: string;
|
|
29
|
+
};
|
|
30
|
+
meta?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Map a frogger log to a CanonicalEvent. Returns null when the level normalises
|
|
34
|
+
* to a drop (e.g. frogger `silent`). Derives the first-class error/session/user/
|
|
35
|
+
* route/feature fields out of ctx per the frozen frogger-map contract, strips the
|
|
36
|
+
* consumed keys from a shallow ctx copy (the caller's object is never mutated),
|
|
37
|
+
* and demotes a non-W3C trace into ctx._trace rather than emitting an invalid one.
|
|
38
|
+
*/
|
|
39
|
+
export declare function froggerLogToEvent(log: FroggerLog, batch: FroggerBatch): CanonicalEvent | null;
|
|
40
|
+
export declare function froggerBatchToEvents(batch: FroggerBatch): CanonicalEvent[];
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { parseLevel } from "../../shared/schema/levels.js";
|
|
2
|
+
const TRACE_ID_RE = /^[0-9a-f]{32}$/;
|
|
3
|
+
const SPAN_ID_RE = /^[0-9a-f]{16}$/;
|
|
4
|
+
const asString = (v) => typeof v === "string" ? v : void 0;
|
|
5
|
+
const asCode = (v) => typeof v === "string" || typeof v === "number" ? v : void 0;
|
|
6
|
+
function deriveError(ctx) {
|
|
7
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
8
|
+
const eo = ctx.error && typeof ctx.error === "object" && !Array.isArray(ctx.error) ? ctx.error : void 0;
|
|
9
|
+
let name = asString(eo?.name);
|
|
10
|
+
if (name === void 0 && asString(ctx.name) !== void 0) {
|
|
11
|
+
name = asString(ctx.name);
|
|
12
|
+
consumed.add("name");
|
|
13
|
+
}
|
|
14
|
+
let message = asString(eo?.message);
|
|
15
|
+
if (message === void 0 && asString(ctx.message) !== void 0) {
|
|
16
|
+
message = asString(ctx.message);
|
|
17
|
+
consumed.add("message");
|
|
18
|
+
}
|
|
19
|
+
let stack = asString(eo?.stack);
|
|
20
|
+
if (stack === void 0 && asString(ctx.stack) !== void 0) {
|
|
21
|
+
stack = asString(ctx.stack);
|
|
22
|
+
consumed.add("stack");
|
|
23
|
+
}
|
|
24
|
+
let code = asCode(eo?.code);
|
|
25
|
+
if (code === void 0 && asCode(ctx.code) !== void 0) {
|
|
26
|
+
code = asCode(ctx.code);
|
|
27
|
+
consumed.add("code");
|
|
28
|
+
} else if (code === void 0 && asCode(ctx.statusCode) !== void 0) {
|
|
29
|
+
code = asCode(ctx.statusCode);
|
|
30
|
+
consumed.add("statusCode");
|
|
31
|
+
}
|
|
32
|
+
if (name === void 0 || message === void 0) return { consumed: /* @__PURE__ */ new Set() };
|
|
33
|
+
if (eo) consumed.add("error");
|
|
34
|
+
const error = { name, message };
|
|
35
|
+
if (stack !== void 0) error.stack = stack;
|
|
36
|
+
if (code !== void 0) error.code = code;
|
|
37
|
+
return { error, consumed };
|
|
38
|
+
}
|
|
39
|
+
export function froggerLogToEvent(log, batch) {
|
|
40
|
+
const level = parseLevel(log.lvl);
|
|
41
|
+
if (level === null) return null;
|
|
42
|
+
const app = log.source?.name ?? batch.app?.name;
|
|
43
|
+
const version = log.source?.version ?? batch.app?.version;
|
|
44
|
+
const event = {
|
|
45
|
+
time: log.time,
|
|
46
|
+
level,
|
|
47
|
+
message: log.msg
|
|
48
|
+
};
|
|
49
|
+
if (app) {
|
|
50
|
+
event.source = { app, ...version ? { version } : {}, ...log.env ? { env: log.env } : {} };
|
|
51
|
+
}
|
|
52
|
+
const srcCtx = log.ctx ?? {};
|
|
53
|
+
const { error, consumed } = deriveError(srcCtx);
|
|
54
|
+
if (error) event.error = error;
|
|
55
|
+
const omit = new Set(consumed);
|
|
56
|
+
if (asString(srcCtx.session) !== void 0) {
|
|
57
|
+
event.session = asString(srcCtx.session);
|
|
58
|
+
omit.add("session");
|
|
59
|
+
}
|
|
60
|
+
if (asString(srcCtx.user) !== void 0) {
|
|
61
|
+
event.user = asString(srcCtx.user);
|
|
62
|
+
omit.add("user");
|
|
63
|
+
}
|
|
64
|
+
if (asString(srcCtx.route) !== void 0) {
|
|
65
|
+
event.route = asString(srcCtx.route);
|
|
66
|
+
omit.add("route");
|
|
67
|
+
}
|
|
68
|
+
if (asString(srcCtx.feature) !== void 0) {
|
|
69
|
+
event.feature = asString(srcCtx.feature);
|
|
70
|
+
omit.add("feature");
|
|
71
|
+
}
|
|
72
|
+
const ctx = {};
|
|
73
|
+
for (const [k, v] of Object.entries(srcCtx)) {
|
|
74
|
+
if (!omit.has(k)) ctx[k] = v;
|
|
75
|
+
}
|
|
76
|
+
const t = log.trace;
|
|
77
|
+
if (t?.traceId && t?.spanId && TRACE_ID_RE.test(t.traceId) && SPAN_ID_RE.test(t.spanId)) {
|
|
78
|
+
event.trace = {
|
|
79
|
+
traceId: t.traceId,
|
|
80
|
+
spanId: t.spanId,
|
|
81
|
+
...t.parentId ? { parentId: t.parentId } : {}
|
|
82
|
+
};
|
|
83
|
+
} else if (t && (t.traceId || t.spanId)) {
|
|
84
|
+
ctx._trace = { ...t };
|
|
85
|
+
}
|
|
86
|
+
if (log.tags && log.tags.length) event.tags = log.tags;
|
|
87
|
+
if (Object.keys(ctx).length) event.ctx = ctx;
|
|
88
|
+
return event;
|
|
89
|
+
}
|
|
90
|
+
export function froggerBatchToEvents(batch) {
|
|
91
|
+
const out = [];
|
|
92
|
+
for (const log of batch.logs ?? []) {
|
|
93
|
+
const event = froggerLogToEvent(log, batch);
|
|
94
|
+
if (event) out.push(event);
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Database } from './db.js';
|
|
2
|
+
import type { ServiceRow } from './services.js';
|
|
3
|
+
export interface GroupRow {
|
|
4
|
+
id: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
name: string;
|
|
7
|
+
created_at: number;
|
|
8
|
+
updated_at: number;
|
|
9
|
+
}
|
|
10
|
+
interface DbOpts {
|
|
11
|
+
db?: Database;
|
|
12
|
+
}
|
|
13
|
+
export declare function createGroup(input: {
|
|
14
|
+
slug: string;
|
|
15
|
+
name: string;
|
|
16
|
+
}, opts?: DbOpts): Promise<GroupRow>;
|
|
17
|
+
export declare function getGroupById(id: string, opts?: DbOpts): Promise<GroupRow | null>;
|
|
18
|
+
export declare function getGroupBySlug(slug: string, opts?: DbOpts): Promise<GroupRow | null>;
|
|
19
|
+
export declare function listGroups(opts?: DbOpts): Promise<GroupRow[]>;
|
|
20
|
+
export declare function updateGroup(id: string, patch: {
|
|
21
|
+
name: string;
|
|
22
|
+
}, opts?: DbOpts): Promise<GroupRow | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Delete a group after detaching its member services (services.group_id = NULL),
|
|
25
|
+
* in one transaction. Services are never deleted with their group; they become
|
|
26
|
+
* ungrouped. Returns false when the group does not exist.
|
|
27
|
+
*/
|
|
28
|
+
export declare function deleteGroup(id: string, opts?: DbOpts): Promise<boolean>;
|
|
29
|
+
export declare function assignServiceToGroup(serviceId: string, groupId: string | null, opts?: DbOpts): Promise<void>;
|
|
30
|
+
export declare function listServicesInGroup(groupId: string, opts?: DbOpts): Promise<ServiceRow[]>;
|
|
31
|
+
export declare function getGroupWithServices(groupId: string, opts?: DbOpts): Promise<{
|
|
32
|
+
group: GroupRow;
|
|
33
|
+
services: ServiceRow[];
|
|
34
|
+
} | null>;
|
|
35
|
+
export {};
|