@qwickapps/server 1.3.1 → 1.5.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/README.md +157 -0
- package/dist/core/control-panel.d.ts.map +1 -1
- package/dist/core/control-panel.js +114 -0
- package/dist/core/control-panel.js.map +1 -1
- package/dist/core/types.d.ts +19 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -3
- package/dist/index.js.map +1 -1
- package/dist/plugins/auth/adapter-wrapper.d.ts +47 -0
- package/dist/plugins/auth/adapter-wrapper.d.ts.map +1 -0
- package/dist/plugins/auth/adapter-wrapper.js +166 -0
- package/dist/plugins/auth/adapter-wrapper.js.map +1 -0
- package/dist/plugins/auth/adapter-wrapper.test.d.ts +7 -0
- package/dist/plugins/auth/adapter-wrapper.test.d.ts.map +1 -0
- package/dist/plugins/auth/adapter-wrapper.test.js +303 -0
- package/dist/plugins/auth/adapter-wrapper.test.js.map +1 -0
- package/dist/plugins/auth/config-store.d.ts +11 -0
- package/dist/plugins/auth/config-store.d.ts.map +1 -0
- package/dist/plugins/auth/config-store.js +232 -0
- package/dist/plugins/auth/config-store.js.map +1 -0
- package/dist/plugins/auth/config-store.test.d.ts +7 -0
- package/dist/plugins/auth/config-store.test.d.ts.map +1 -0
- package/dist/plugins/auth/config-store.test.js +299 -0
- package/dist/plugins/auth/config-store.test.js.map +1 -0
- package/dist/plugins/auth/env-config.d.ts +51 -1
- package/dist/plugins/auth/env-config.d.ts.map +1 -1
- package/dist/plugins/auth/env-config.js +640 -7
- package/dist/plugins/auth/env-config.js.map +1 -1
- package/dist/plugins/auth/index.d.ts +6 -2
- package/dist/plugins/auth/index.d.ts.map +1 -1
- package/dist/plugins/auth/index.js +5 -1
- package/dist/plugins/auth/index.js.map +1 -1
- package/dist/plugins/auth/types.d.ts +106 -0
- package/dist/plugins/auth/types.d.ts.map +1 -1
- package/dist/plugins/bans/bans-plugin.d.ts.map +1 -1
- package/dist/plugins/bans/bans-plugin.js +12 -3
- package/dist/plugins/bans/bans-plugin.js.map +1 -1
- package/dist/plugins/devices/__tests__/devices-plugin.test.d.ts +11 -0
- package/dist/plugins/devices/__tests__/devices-plugin.test.d.ts.map +1 -0
- package/dist/plugins/devices/__tests__/devices-plugin.test.js +410 -0
- package/dist/plugins/devices/__tests__/devices-plugin.test.js.map +1 -0
- package/dist/plugins/devices/__tests__/token-utils.test.d.ts +7 -0
- package/dist/plugins/devices/__tests__/token-utils.test.d.ts.map +1 -0
- package/dist/plugins/devices/__tests__/token-utils.test.js +197 -0
- package/dist/plugins/devices/__tests__/token-utils.test.js.map +1 -0
- package/dist/plugins/devices/adapters/compute-adapter.d.ts +36 -0
- package/dist/plugins/devices/adapters/compute-adapter.d.ts.map +1 -0
- package/dist/plugins/devices/adapters/compute-adapter.js +100 -0
- package/dist/plugins/devices/adapters/compute-adapter.js.map +1 -0
- package/dist/plugins/devices/adapters/index.d.ts +12 -0
- package/dist/plugins/devices/adapters/index.d.ts.map +1 -0
- package/dist/plugins/devices/adapters/index.js +10 -0
- package/dist/plugins/devices/adapters/index.js.map +1 -0
- package/dist/plugins/devices/adapters/mobile-adapter.d.ts +41 -0
- package/dist/plugins/devices/adapters/mobile-adapter.d.ts.map +1 -0
- package/dist/plugins/devices/adapters/mobile-adapter.js +131 -0
- package/dist/plugins/devices/adapters/mobile-adapter.js.map +1 -0
- package/dist/plugins/devices/devices-plugin.d.ts +70 -0
- package/dist/plugins/devices/devices-plugin.d.ts.map +1 -0
- package/dist/plugins/devices/devices-plugin.js +453 -0
- package/dist/plugins/devices/devices-plugin.js.map +1 -0
- package/dist/plugins/devices/index.d.ts +18 -0
- package/dist/plugins/devices/index.d.ts.map +1 -0
- package/dist/plugins/devices/index.js +18 -0
- package/dist/plugins/devices/index.js.map +1 -0
- package/dist/plugins/devices/stores/index.d.ts +9 -0
- package/dist/plugins/devices/stores/index.d.ts.map +1 -0
- package/dist/plugins/devices/stores/index.js +9 -0
- package/dist/plugins/devices/stores/index.js.map +1 -0
- package/dist/plugins/devices/stores/postgres-store.d.ts +26 -0
- package/dist/plugins/devices/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/devices/stores/postgres-store.js +199 -0
- package/dist/plugins/devices/stores/postgres-store.js.map +1 -0
- package/dist/plugins/devices/token-utils.d.ts +100 -0
- package/dist/plugins/devices/token-utils.d.ts.map +1 -0
- package/dist/plugins/devices/token-utils.js +162 -0
- package/dist/plugins/devices/token-utils.js.map +1 -0
- package/dist/plugins/devices/types.d.ts +307 -0
- package/dist/plugins/devices/types.d.ts.map +1 -0
- package/dist/plugins/devices/types.js +10 -0
- package/dist/plugins/devices/types.js.map +1 -0
- package/dist/plugins/index.d.ts +18 -4
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +16 -2
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/notifications/__tests__/notifications-manager.test.d.ts +5 -0
- package/dist/plugins/notifications/__tests__/notifications-manager.test.d.ts.map +1 -0
- package/dist/plugins/notifications/__tests__/notifications-manager.test.js +470 -0
- package/dist/plugins/notifications/__tests__/notifications-manager.test.js.map +1 -0
- package/dist/plugins/notifications/index.d.ts +71 -0
- package/dist/plugins/notifications/index.d.ts.map +1 -0
- package/dist/plugins/notifications/index.js +72 -0
- package/dist/plugins/notifications/index.js.map +1 -0
- package/dist/plugins/notifications/notifications-manager.d.ts +182 -0
- package/dist/plugins/notifications/notifications-manager.d.ts.map +1 -0
- package/dist/plugins/notifications/notifications-manager.js +610 -0
- package/dist/plugins/notifications/notifications-manager.js.map +1 -0
- package/dist/plugins/notifications/notifications-plugin.d.ts +83 -0
- package/dist/plugins/notifications/notifications-plugin.d.ts.map +1 -0
- package/dist/plugins/notifications/notifications-plugin.js +337 -0
- package/dist/plugins/notifications/notifications-plugin.js.map +1 -0
- package/dist/plugins/notifications/types.d.ts +164 -0
- package/dist/plugins/notifications/types.d.ts.map +1 -0
- package/dist/plugins/notifications/types.js +9 -0
- package/dist/plugins/notifications/types.js.map +1 -0
- package/dist/plugins/parental/__tests__/parental-plugin.test.d.ts +12 -0
- package/dist/plugins/parental/__tests__/parental-plugin.test.d.ts.map +1 -0
- package/dist/plugins/parental/__tests__/parental-plugin.test.js +349 -0
- package/dist/plugins/parental/__tests__/parental-plugin.test.js.map +1 -0
- package/dist/plugins/parental/adapters/index.d.ts +8 -0
- package/dist/plugins/parental/adapters/index.d.ts.map +1 -0
- package/dist/plugins/parental/adapters/index.js +7 -0
- package/dist/plugins/parental/adapters/index.js.map +1 -0
- package/dist/plugins/parental/adapters/kids-adapter.d.ts +24 -0
- package/dist/plugins/parental/adapters/kids-adapter.d.ts.map +1 -0
- package/dist/plugins/parental/adapters/kids-adapter.js +174 -0
- package/dist/plugins/parental/adapters/kids-adapter.js.map +1 -0
- package/dist/plugins/parental/index.d.ts +14 -0
- package/dist/plugins/parental/index.d.ts.map +1 -0
- package/dist/plugins/parental/index.js +15 -0
- package/dist/plugins/parental/index.js.map +1 -0
- package/dist/plugins/parental/parental-plugin.d.ts +88 -0
- package/dist/plugins/parental/parental-plugin.d.ts.map +1 -0
- package/dist/plugins/parental/parental-plugin.js +666 -0
- package/dist/plugins/parental/parental-plugin.js.map +1 -0
- package/dist/plugins/parental/stores/index.d.ts +7 -0
- package/dist/plugins/parental/stores/index.d.ts.map +1 -0
- package/dist/plugins/parental/stores/index.js +7 -0
- package/dist/plugins/parental/stores/index.js.map +1 -0
- package/dist/plugins/parental/stores/postgres-store.d.ts +10 -0
- package/dist/plugins/parental/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/parental/stores/postgres-store.js +209 -0
- package/dist/plugins/parental/stores/postgres-store.js.map +1 -0
- package/dist/plugins/parental/types.d.ts +154 -0
- package/dist/plugins/parental/types.d.ts.map +1 -0
- package/dist/plugins/parental/types.js +10 -0
- package/dist/plugins/parental/types.js.map +1 -0
- package/dist/plugins/profiles/__tests__/profiles-plugin.test.d.ts +11 -0
- package/dist/plugins/profiles/__tests__/profiles-plugin.test.d.ts.map +1 -0
- package/dist/plugins/profiles/__tests__/profiles-plugin.test.js +243 -0
- package/dist/plugins/profiles/__tests__/profiles-plugin.test.js.map +1 -0
- package/dist/plugins/profiles/index.d.ts +12 -0
- package/dist/plugins/profiles/index.d.ts.map +1 -0
- package/dist/plugins/profiles/index.js +13 -0
- package/dist/plugins/profiles/index.js.map +1 -0
- package/dist/plugins/profiles/profiles-plugin.d.ts +71 -0
- package/dist/plugins/profiles/profiles-plugin.d.ts.map +1 -0
- package/dist/plugins/profiles/profiles-plugin.js +481 -0
- package/dist/plugins/profiles/profiles-plugin.js.map +1 -0
- package/dist/plugins/profiles/stores/index.d.ts +9 -0
- package/dist/plugins/profiles/stores/index.d.ts.map +1 -0
- package/dist/plugins/profiles/stores/index.js +9 -0
- package/dist/plugins/profiles/stores/index.js.map +1 -0
- package/dist/plugins/profiles/stores/postgres-store.d.ts +18 -0
- package/dist/plugins/profiles/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/profiles/stores/postgres-store.js +310 -0
- package/dist/plugins/profiles/stores/postgres-store.js.map +1 -0
- package/dist/plugins/profiles/types.d.ts +289 -0
- package/dist/plugins/profiles/types.d.ts.map +1 -0
- package/dist/plugins/profiles/types.js +10 -0
- package/dist/plugins/profiles/types.js.map +1 -0
- package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts +7 -0
- package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts.map +1 -0
- package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js +220 -0
- package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js.map +1 -0
- package/dist/plugins/rate-limit/cleanup.d.ts +40 -0
- package/dist/plugins/rate-limit/cleanup.d.ts.map +1 -0
- package/dist/plugins/rate-limit/cleanup.js +72 -0
- package/dist/plugins/rate-limit/cleanup.js.map +1 -0
- package/dist/plugins/rate-limit/env-config.d.ts +91 -0
- package/dist/plugins/rate-limit/env-config.d.ts.map +1 -0
- package/dist/plugins/rate-limit/env-config.js +318 -0
- package/dist/plugins/rate-limit/env-config.js.map +1 -0
- package/dist/plugins/rate-limit/index.d.ts +76 -0
- package/dist/plugins/rate-limit/index.d.ts.map +1 -0
- package/dist/plugins/rate-limit/index.js +79 -0
- package/dist/plugins/rate-limit/index.js.map +1 -0
- package/dist/plugins/rate-limit/middleware.d.ts +40 -0
- package/dist/plugins/rate-limit/middleware.d.ts.map +1 -0
- package/dist/plugins/rate-limit/middleware.js +169 -0
- package/dist/plugins/rate-limit/middleware.js.map +1 -0
- package/dist/plugins/rate-limit/rate-limit-plugin.d.ts +44 -0
- package/dist/plugins/rate-limit/rate-limit-plugin.d.ts.map +1 -0
- package/dist/plugins/rate-limit/rate-limit-plugin.js +354 -0
- package/dist/plugins/rate-limit/rate-limit-plugin.js.map +1 -0
- package/dist/plugins/rate-limit/rate-limit-service.d.ts +110 -0
- package/dist/plugins/rate-limit/rate-limit-service.d.ts.map +1 -0
- package/dist/plugins/rate-limit/rate-limit-service.js +172 -0
- package/dist/plugins/rate-limit/rate-limit-service.js.map +1 -0
- package/dist/plugins/rate-limit/stores/cache-store.d.ts +33 -0
- package/dist/plugins/rate-limit/stores/cache-store.d.ts.map +1 -0
- package/dist/plugins/rate-limit/stores/cache-store.js +225 -0
- package/dist/plugins/rate-limit/stores/cache-store.js.map +1 -0
- package/dist/plugins/rate-limit/stores/index.d.ts +8 -0
- package/dist/plugins/rate-limit/stores/index.d.ts.map +1 -0
- package/dist/plugins/rate-limit/stores/index.js +8 -0
- package/dist/plugins/rate-limit/stores/index.js.map +1 -0
- package/dist/plugins/rate-limit/stores/postgres-store.d.ts +34 -0
- package/dist/plugins/rate-limit/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/rate-limit/stores/postgres-store.js +320 -0
- package/dist/plugins/rate-limit/stores/postgres-store.js.map +1 -0
- package/dist/plugins/rate-limit/strategies/fixed-window.d.ts +21 -0
- package/dist/plugins/rate-limit/strategies/fixed-window.d.ts.map +1 -0
- package/dist/plugins/rate-limit/strategies/fixed-window.js +97 -0
- package/dist/plugins/rate-limit/strategies/fixed-window.js.map +1 -0
- package/dist/plugins/rate-limit/strategies/index.d.ts +14 -0
- package/dist/plugins/rate-limit/strategies/index.d.ts.map +1 -0
- package/dist/plugins/rate-limit/strategies/index.js +27 -0
- package/dist/plugins/rate-limit/strategies/index.js.map +1 -0
- package/dist/plugins/rate-limit/strategies/sliding-window.d.ts +22 -0
- package/dist/plugins/rate-limit/strategies/sliding-window.d.ts.map +1 -0
- package/dist/plugins/rate-limit/strategies/sliding-window.js +122 -0
- package/dist/plugins/rate-limit/strategies/sliding-window.js.map +1 -0
- package/dist/plugins/rate-limit/strategies/token-bucket.d.ts +28 -0
- package/dist/plugins/rate-limit/strategies/token-bucket.d.ts.map +1 -0
- package/dist/plugins/rate-limit/strategies/token-bucket.js +121 -0
- package/dist/plugins/rate-limit/strategies/token-bucket.js.map +1 -0
- package/dist/plugins/rate-limit/types.d.ts +265 -0
- package/dist/plugins/rate-limit/types.d.ts.map +1 -0
- package/dist/plugins/rate-limit/types.js +9 -0
- package/dist/plugins/rate-limit/types.js.map +1 -0
- package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.d.ts +11 -0
- package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.d.ts.map +1 -0
- package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.js +305 -0
- package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.js.map +1 -0
- package/dist/plugins/subscriptions/index.d.ts +12 -0
- package/dist/plugins/subscriptions/index.d.ts.map +1 -0
- package/dist/plugins/subscriptions/index.js +13 -0
- package/dist/plugins/subscriptions/index.js.map +1 -0
- package/dist/plugins/subscriptions/stores/index.d.ts +9 -0
- package/dist/plugins/subscriptions/stores/index.d.ts.map +1 -0
- package/dist/plugins/subscriptions/stores/index.js +9 -0
- package/dist/plugins/subscriptions/stores/index.js.map +1 -0
- package/dist/plugins/subscriptions/stores/postgres-store.d.ts +14 -0
- package/dist/plugins/subscriptions/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/subscriptions/stores/postgres-store.js +359 -0
- package/dist/plugins/subscriptions/stores/postgres-store.js.map +1 -0
- package/dist/plugins/subscriptions/subscriptions-plugin.d.ts +82 -0
- package/dist/plugins/subscriptions/subscriptions-plugin.d.ts.map +1 -0
- package/dist/plugins/subscriptions/subscriptions-plugin.js +449 -0
- package/dist/plugins/subscriptions/subscriptions-plugin.js.map +1 -0
- package/dist/plugins/subscriptions/types.d.ts +308 -0
- package/dist/plugins/subscriptions/types.d.ts.map +1 -0
- package/dist/plugins/subscriptions/types.js +10 -0
- package/dist/plugins/subscriptions/types.js.map +1 -0
- package/dist/plugins/usage/__tests__/usage-plugin.test.d.ts +11 -0
- package/dist/plugins/usage/__tests__/usage-plugin.test.d.ts.map +1 -0
- package/dist/plugins/usage/__tests__/usage-plugin.test.js +218 -0
- package/dist/plugins/usage/__tests__/usage-plugin.test.js.map +1 -0
- package/dist/plugins/usage/index.d.ts +12 -0
- package/dist/plugins/usage/index.d.ts.map +1 -0
- package/dist/plugins/usage/index.js +13 -0
- package/dist/plugins/usage/index.js.map +1 -0
- package/dist/plugins/usage/stores/index.d.ts +9 -0
- package/dist/plugins/usage/stores/index.d.ts.map +1 -0
- package/dist/plugins/usage/stores/index.js +9 -0
- package/dist/plugins/usage/stores/index.js.map +1 -0
- package/dist/plugins/usage/stores/postgres-store.d.ts +14 -0
- package/dist/plugins/usage/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/usage/stores/postgres-store.js +146 -0
- package/dist/plugins/usage/stores/postgres-store.js.map +1 -0
- package/dist/plugins/usage/types.d.ts +195 -0
- package/dist/plugins/usage/types.d.ts.map +1 -0
- package/dist/plugins/usage/types.js +10 -0
- package/dist/plugins/usage/types.js.map +1 -0
- package/dist/plugins/usage/usage-plugin.d.ts +51 -0
- package/dist/plugins/usage/usage-plugin.d.ts.map +1 -0
- package/dist/plugins/usage/usage-plugin.js +412 -0
- package/dist/plugins/usage/usage-plugin.js.map +1 -0
- package/dist/plugins/users/__tests__/postgres-store.test.d.ts +10 -0
- package/dist/plugins/users/__tests__/postgres-store.test.d.ts.map +1 -0
- package/dist/plugins/users/__tests__/postgres-store.test.js +229 -0
- package/dist/plugins/users/__tests__/postgres-store.test.js.map +1 -0
- package/dist/plugins/users/__tests__/users-plugin.test.js +3 -0
- package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -1
- package/dist/plugins/users/index.d.ts +2 -2
- package/dist/plugins/users/index.d.ts.map +1 -1
- package/dist/plugins/users/index.js +1 -1
- package/dist/plugins/users/index.js.map +1 -1
- package/dist/plugins/users/stores/postgres-store.d.ts.map +1 -1
- package/dist/plugins/users/stores/postgres-store.js +76 -0
- package/dist/plugins/users/stores/postgres-store.js.map +1 -1
- package/dist/plugins/users/types.d.ts +74 -6
- package/dist/plugins/users/types.d.ts.map +1 -1
- package/dist/plugins/users/users-plugin.d.ts +15 -1
- package/dist/plugins/users/users-plugin.d.ts.map +1 -1
- package/dist/plugins/users/users-plugin.js +29 -0
- package/dist/plugins/users/users-plugin.js.map +1 -1
- package/dist-ui/assets/index-CynOqPkb.js +469 -0
- package/dist-ui/assets/{index-BY8OxNgO.js.map → index-CynOqPkb.js.map} +1 -1
- package/dist-ui/index.html +1 -1
- package/dist-ui-lib/api/controlPanelApi.d.ts +187 -0
- package/dist-ui-lib/components/StatCard.d.ts +16 -0
- package/dist-ui-lib/dashboard/widgets/AuthStatusWidget.d.ts +9 -0
- package/dist-ui-lib/dashboard/widgets/IntegrationStatusWidget.d.ts +9 -0
- package/dist-ui-lib/dashboard/widgets/NotificationsStatsWidget.d.ts +12 -0
- package/dist-ui-lib/dashboard/widgets/index.d.ts +3 -0
- package/dist-ui-lib/index.js +3579 -2379
- package/dist-ui-lib/index.js.map +1 -1
- package/dist-ui-lib/pages/IntegrationsPage.d.ts +1 -0
- package/dist-ui-lib/pages/NotificationsPage.d.ts +9 -0
- package/dist-ui-lib/pages/RateLimitPage.d.ts +1 -0
- package/dist-ui-lib/utils/formatters.d.ts +19 -0
- package/package.json +1 -1
- package/src/core/control-panel.ts +128 -0
- package/src/core/types.ts +17 -0
- package/src/index.ts +216 -0
- package/src/plugins/auth/adapter-wrapper.test.ts +395 -0
- package/src/plugins/auth/adapter-wrapper.ts +205 -0
- package/src/plugins/auth/config-store.test.ts +417 -0
- package/src/plugins/auth/config-store.ts +305 -0
- package/src/plugins/auth/env-config.ts +714 -7
- package/src/plugins/auth/index.ts +22 -1
- package/src/plugins/auth/types.ts +138 -0
- package/src/plugins/bans/bans-plugin.ts +15 -3
- package/src/plugins/devices/__tests__/devices-plugin.test.ts +551 -0
- package/src/plugins/devices/__tests__/token-utils.test.ts +264 -0
- package/src/plugins/devices/adapters/compute-adapter.ts +139 -0
- package/src/plugins/devices/adapters/index.ts +13 -0
- package/src/plugins/devices/adapters/mobile-adapter.ts +179 -0
- package/src/plugins/devices/devices-plugin.ts +538 -0
- package/src/plugins/devices/index.ts +69 -0
- package/src/plugins/devices/stores/index.ts +9 -0
- package/src/plugins/devices/stores/postgres-store.ts +304 -0
- package/src/plugins/devices/token-utils.ts +213 -0
- package/src/plugins/devices/types.ts +351 -0
- package/src/plugins/index.ts +267 -0
- package/src/plugins/notifications/__tests__/notifications-manager.test.ts +637 -0
- package/src/plugins/notifications/index.ts +91 -0
- package/src/plugins/notifications/notifications-manager.ts +773 -0
- package/src/plugins/notifications/notifications-plugin.ts +398 -0
- package/src/plugins/notifications/types.ts +207 -0
- package/src/plugins/parental/__tests__/parental-plugin.test.ts +465 -0
- package/src/plugins/parental/adapters/index.ts +8 -0
- package/src/plugins/parental/adapters/kids-adapter.ts +206 -0
- package/src/plugins/parental/index.ts +55 -0
- package/src/plugins/parental/parental-plugin.ts +759 -0
- package/src/plugins/parental/stores/index.ts +7 -0
- package/src/plugins/parental/stores/postgres-store.ts +304 -0
- package/src/plugins/parental/types.ts +180 -0
- package/src/plugins/profiles/__tests__/profiles-plugin.test.ts +321 -0
- package/src/plugins/profiles/index.ts +49 -0
- package/src/plugins/profiles/profiles-plugin.ts +546 -0
- package/src/plugins/profiles/stores/index.ts +9 -0
- package/src/plugins/profiles/stores/postgres-store.ts +439 -0
- package/src/plugins/profiles/types.ts +338 -0
- package/src/plugins/rate-limit/__tests__/rate-limit-plugin.test.ts +259 -0
- package/src/plugins/rate-limit/cleanup.ts +117 -0
- package/src/plugins/rate-limit/env-config.ts +400 -0
- package/src/plugins/rate-limit/index.ts +128 -0
- package/src/plugins/rate-limit/middleware.ts +212 -0
- package/src/plugins/rate-limit/rate-limit-plugin.ts +400 -0
- package/src/plugins/rate-limit/rate-limit-service.ts +228 -0
- package/src/plugins/rate-limit/stores/cache-store.ts +261 -0
- package/src/plugins/rate-limit/stores/index.ts +8 -0
- package/src/plugins/rate-limit/stores/postgres-store.ts +402 -0
- package/src/plugins/rate-limit/strategies/fixed-window.ts +116 -0
- package/src/plugins/rate-limit/strategies/index.ts +30 -0
- package/src/plugins/rate-limit/strategies/sliding-window.ts +157 -0
- package/src/plugins/rate-limit/strategies/token-bucket.ts +154 -0
- package/src/plugins/rate-limit/types.ts +338 -0
- package/src/plugins/subscriptions/__tests__/subscriptions-plugin.test.ts +404 -0
- package/src/plugins/subscriptions/index.ts +51 -0
- package/src/plugins/subscriptions/stores/index.ts +9 -0
- package/src/plugins/subscriptions/stores/postgres-store.ts +482 -0
- package/src/plugins/subscriptions/subscriptions-plugin.ts +530 -0
- package/src/plugins/subscriptions/types.ts +355 -0
- package/src/plugins/usage/__tests__/usage-plugin.test.ts +288 -0
- package/src/plugins/usage/index.ts +39 -0
- package/src/plugins/usage/stores/index.ts +9 -0
- package/src/plugins/usage/stores/postgres-store.ts +213 -0
- package/src/plugins/usage/types.ts +222 -0
- package/src/plugins/usage/usage-plugin.ts +484 -0
- package/src/plugins/users/__tests__/postgres-store.test.ts +326 -0
- package/src/plugins/users/__tests__/users-plugin.test.ts +3 -0
- package/src/plugins/users/index.ts +6 -0
- package/src/plugins/users/stores/postgres-store.ts +104 -0
- package/src/plugins/users/types.ts +82 -6
- package/src/plugins/users/users-plugin.ts +37 -0
- package/ui/src/App.tsx +36 -14
- package/ui/src/api/controlPanelApi.ts +329 -6
- package/ui/src/components/StatCard.tsx +58 -0
- package/ui/src/dashboard/builtInWidgets.tsx +7 -1
- package/ui/src/dashboard/widgets/AuthStatusWidget.tsx +143 -0
- package/ui/src/dashboard/widgets/IntegrationStatusWidget.tsx +135 -0
- package/ui/src/dashboard/widgets/NotificationsStatsWidget.tsx +167 -0
- package/ui/src/dashboard/widgets/index.ts +3 -0
- package/ui/src/pages/AuthPage.tsx +986 -142
- package/ui/src/pages/IntegrationsPage.tsx +288 -0
- package/ui/src/pages/NotificationsPage.tsx +417 -0
- package/ui/src/pages/RateLimitPage.tsx +292 -0
- package/ui/src/utils/formatters.ts +33 -0
- package/dist-ui/assets/index-BY8OxNgO.js +0 -465
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage Plugin
|
|
3
|
+
*
|
|
4
|
+
* Usage tracking plugin for @qwickapps/server.
|
|
5
|
+
* Tracks daily/monthly feature usage and enforces limits.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Request, Response } from 'express';
|
|
11
|
+
import type { Plugin, PluginConfig, PluginRegistry } from '../../core/plugin-registry.js';
|
|
12
|
+
import type {
|
|
13
|
+
UsagePluginConfig,
|
|
14
|
+
UsageStore,
|
|
15
|
+
DailyUsage,
|
|
16
|
+
UsageIncrementResult,
|
|
17
|
+
UsageStatus,
|
|
18
|
+
UsageSummary,
|
|
19
|
+
} from './types.js';
|
|
20
|
+
|
|
21
|
+
// Import subscription helpers if available
|
|
22
|
+
let getFeatureLimitFn: ((userId: string, featureCode: string) => Promise<number | null>) | null = null;
|
|
23
|
+
|
|
24
|
+
// Store instance for helper access
|
|
25
|
+
let currentStore: UsageStore | null = null;
|
|
26
|
+
let currentConfig: UsagePluginConfig | null = null;
|
|
27
|
+
let cleanupIntervalId: NodeJS.Timeout | null = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get current date in YYYY-MM-DD format
|
|
31
|
+
*/
|
|
32
|
+
function getCurrentDate(): string {
|
|
33
|
+
return new Date().toISOString().split('T')[0];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get tomorrow's date at midnight (for reset time)
|
|
38
|
+
*/
|
|
39
|
+
function getTomorrowMidnight(): Date {
|
|
40
|
+
const tomorrow = new Date();
|
|
41
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
42
|
+
tomorrow.setHours(0, 0, 0, 0);
|
|
43
|
+
return tomorrow;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create the Usage plugin
|
|
48
|
+
*/
|
|
49
|
+
export function createUsagePlugin(config: UsagePluginConfig): Plugin {
|
|
50
|
+
const debug = config.debug || false;
|
|
51
|
+
const apiPrefix = config.api?.prefix || '/usage';
|
|
52
|
+
|
|
53
|
+
function log(message: string, data?: Record<string, unknown>) {
|
|
54
|
+
if (debug) {
|
|
55
|
+
console.log(`[UsagePlugin] ${message}`, data || '');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
id: 'usage',
|
|
61
|
+
name: 'Usage',
|
|
62
|
+
version: '1.0.0',
|
|
63
|
+
|
|
64
|
+
async onStart(_pluginConfig: PluginConfig, registry: PluginRegistry): Promise<void> {
|
|
65
|
+
log('Starting usage plugin');
|
|
66
|
+
|
|
67
|
+
// Initialize the store (creates tables if needed)
|
|
68
|
+
await config.store.initialize();
|
|
69
|
+
log('Usage plugin migrations complete');
|
|
70
|
+
|
|
71
|
+
// Store references for helper access
|
|
72
|
+
currentStore = config.store;
|
|
73
|
+
currentConfig = config;
|
|
74
|
+
|
|
75
|
+
// Try to get the feature limit function from subscriptions plugin
|
|
76
|
+
try {
|
|
77
|
+
const subscriptions = await import('../subscriptions/index.js');
|
|
78
|
+
getFeatureLimitFn = subscriptions.getFeatureLimit;
|
|
79
|
+
log('Subscriptions plugin integration enabled');
|
|
80
|
+
} catch {
|
|
81
|
+
log('Subscriptions plugin not available, limits will not be enforced');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Register health check
|
|
85
|
+
registry.registerHealthCheck({
|
|
86
|
+
name: 'usage-store',
|
|
87
|
+
type: 'custom',
|
|
88
|
+
check: async () => {
|
|
89
|
+
try {
|
|
90
|
+
// Simple health check
|
|
91
|
+
return { healthy: true };
|
|
92
|
+
} catch {
|
|
93
|
+
return { healthy: false };
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Run cleanup on startup if configured
|
|
99
|
+
if (config.cleanup?.runOnStartup) {
|
|
100
|
+
const dailyDays = config.cleanup.dailyRetentionDays || 90;
|
|
101
|
+
const monthlyMonths = config.cleanup.monthlyRetentionMonths || 24;
|
|
102
|
+
|
|
103
|
+
const dailyDeleted = await config.store.cleanupOldDaily(dailyDays);
|
|
104
|
+
const monthlyDeleted = await config.store.cleanupOldMonthly(monthlyMonths);
|
|
105
|
+
log('Startup cleanup complete', { dailyDeleted, monthlyDeleted });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Set up periodic cleanup if configured
|
|
109
|
+
if (config.cleanup?.cleanupIntervalHours && config.cleanup.cleanupIntervalHours > 0) {
|
|
110
|
+
const intervalMs = config.cleanup.cleanupIntervalHours * 60 * 60 * 1000;
|
|
111
|
+
cleanupIntervalId = setInterval(async () => {
|
|
112
|
+
try {
|
|
113
|
+
const dailyDays = config.cleanup?.dailyRetentionDays || 90;
|
|
114
|
+
const monthlyMonths = config.cleanup?.monthlyRetentionMonths || 24;
|
|
115
|
+
|
|
116
|
+
const dailyDeleted = await config.store.cleanupOldDaily(dailyDays);
|
|
117
|
+
const monthlyDeleted = await config.store.cleanupOldMonthly(monthlyMonths);
|
|
118
|
+
log('Periodic cleanup complete', { dailyDeleted, monthlyDeleted });
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('[UsagePlugin] Cleanup error:', error);
|
|
121
|
+
}
|
|
122
|
+
}, intervalMs);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Add API routes if enabled
|
|
126
|
+
if (config.api?.enabled !== false) {
|
|
127
|
+
// Get daily usage summary
|
|
128
|
+
registry.addRoute({
|
|
129
|
+
method: 'get',
|
|
130
|
+
path: `${apiPrefix}/user/:userId/daily`,
|
|
131
|
+
pluginId: 'usage',
|
|
132
|
+
handler: async (req: Request, res: Response) => {
|
|
133
|
+
try {
|
|
134
|
+
const { userId } = req.params;
|
|
135
|
+
const date = (req.query.date as string) || getCurrentDate();
|
|
136
|
+
|
|
137
|
+
const summary = await getDailyUsageSummary(userId, date);
|
|
138
|
+
res.json(summary);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error('[UsagePlugin] Get daily usage error:', error);
|
|
141
|
+
res.status(500).json({ error: 'Failed to get daily usage' });
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Get usage for a specific feature
|
|
147
|
+
registry.addRoute({
|
|
148
|
+
method: 'get',
|
|
149
|
+
path: `${apiPrefix}/user/:userId/feature/:featureCode`,
|
|
150
|
+
pluginId: 'usage',
|
|
151
|
+
handler: async (req: Request, res: Response) => {
|
|
152
|
+
try {
|
|
153
|
+
const { userId, featureCode } = req.params;
|
|
154
|
+
const status = await getFeatureUsageStatus(userId, featureCode);
|
|
155
|
+
res.json(status);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error('[UsagePlugin] Get feature usage error:', error);
|
|
158
|
+
res.status(500).json({ error: 'Failed to get feature usage' });
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Increment usage (with limit check)
|
|
164
|
+
registry.addRoute({
|
|
165
|
+
method: 'post',
|
|
166
|
+
path: `${apiPrefix}/user/:userId/feature/:featureCode/increment`,
|
|
167
|
+
pluginId: 'usage',
|
|
168
|
+
handler: async (req: Request, res: Response) => {
|
|
169
|
+
try {
|
|
170
|
+
const { userId, featureCode } = req.params;
|
|
171
|
+
const amount = parseInt(req.body.amount as string) || 1;
|
|
172
|
+
|
|
173
|
+
const result = await incrementUsage(userId, featureCode, amount);
|
|
174
|
+
res.json(result);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('[UsagePlugin] Increment usage error:', error);
|
|
177
|
+
res.status(500).json({ error: 'Failed to increment usage' });
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Check if usage is within limit (without incrementing)
|
|
183
|
+
registry.addRoute({
|
|
184
|
+
method: 'get',
|
|
185
|
+
path: `${apiPrefix}/user/:userId/feature/:featureCode/check`,
|
|
186
|
+
pluginId: 'usage',
|
|
187
|
+
handler: async (req: Request, res: Response) => {
|
|
188
|
+
try {
|
|
189
|
+
const { userId, featureCode } = req.params;
|
|
190
|
+
const amount = parseInt(req.query.amount as string) || 1;
|
|
191
|
+
|
|
192
|
+
const result = await checkUsageLimit(userId, featureCode, amount);
|
|
193
|
+
res.json(result);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error('[UsagePlugin] Check usage error:', error);
|
|
196
|
+
res.status(500).json({ error: 'Failed to check usage' });
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
log('Usage plugin started');
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
async onStop(): Promise<void> {
|
|
206
|
+
log('Stopping usage plugin');
|
|
207
|
+
|
|
208
|
+
// Clear cleanup interval
|
|
209
|
+
if (cleanupIntervalId) {
|
|
210
|
+
clearInterval(cleanupIntervalId);
|
|
211
|
+
cleanupIntervalId = null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
await config.store.shutdown();
|
|
215
|
+
currentStore = null;
|
|
216
|
+
currentConfig = null;
|
|
217
|
+
log('Usage plugin stopped');
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
223
|
+
// Helper Functions
|
|
224
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get the current usage store instance
|
|
228
|
+
*/
|
|
229
|
+
export function getUsageStore(): UsageStore | null {
|
|
230
|
+
return currentStore;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get current daily usage for a feature
|
|
235
|
+
*/
|
|
236
|
+
export async function getDailyUsage(userId: string, featureCode: string): Promise<number> {
|
|
237
|
+
if (!currentStore) {
|
|
238
|
+
throw new Error('Usage plugin not initialized');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const usage = await currentStore.getDailyUsage(userId, featureCode);
|
|
242
|
+
return usage?.count || 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Increment usage and check limit
|
|
247
|
+
*/
|
|
248
|
+
export async function incrementUsage(
|
|
249
|
+
userId: string,
|
|
250
|
+
featureCode: string,
|
|
251
|
+
amount = 1
|
|
252
|
+
): Promise<UsageIncrementResult> {
|
|
253
|
+
if (!currentStore) {
|
|
254
|
+
throw new Error('Usage plugin not initialized');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Get current usage
|
|
258
|
+
const currentUsage = await getDailyUsage(userId, featureCode);
|
|
259
|
+
|
|
260
|
+
// Get limit from subscriptions plugin
|
|
261
|
+
let limit: number | null = null;
|
|
262
|
+
if (getFeatureLimitFn) {
|
|
263
|
+
limit = await getFeatureLimitFn(userId, featureCode);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Check if increment is allowed
|
|
267
|
+
// limit = -1 means unlimited, null means no subscription/feature disabled
|
|
268
|
+
if (limit === null) {
|
|
269
|
+
return {
|
|
270
|
+
allowed: false,
|
|
271
|
+
current_count: currentUsage,
|
|
272
|
+
limit: null,
|
|
273
|
+
remaining: null,
|
|
274
|
+
reason: 'Feature not available in your subscription',
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (limit === 0) {
|
|
279
|
+
return {
|
|
280
|
+
allowed: false,
|
|
281
|
+
current_count: currentUsage,
|
|
282
|
+
limit: 0,
|
|
283
|
+
remaining: 0,
|
|
284
|
+
reason: 'Feature is disabled',
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Check if within limit (-1 = unlimited)
|
|
289
|
+
if (limit !== -1 && currentUsage + amount > limit) {
|
|
290
|
+
return {
|
|
291
|
+
allowed: false,
|
|
292
|
+
current_count: currentUsage,
|
|
293
|
+
limit,
|
|
294
|
+
remaining: Math.max(0, limit - currentUsage),
|
|
295
|
+
resets_at: getTomorrowMidnight(),
|
|
296
|
+
reason: 'Daily limit reached',
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Increment usage
|
|
301
|
+
const newCount = await currentStore.incrementDaily(userId, featureCode, amount);
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
allowed: true,
|
|
305
|
+
current_count: newCount,
|
|
306
|
+
limit,
|
|
307
|
+
remaining: limit === -1 ? -1 : Math.max(0, limit - newCount),
|
|
308
|
+
resets_at: getTomorrowMidnight(),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Check if usage is within limit (without incrementing)
|
|
314
|
+
*/
|
|
315
|
+
export async function checkUsageLimit(
|
|
316
|
+
userId: string,
|
|
317
|
+
featureCode: string,
|
|
318
|
+
amount = 1
|
|
319
|
+
): Promise<UsageIncrementResult> {
|
|
320
|
+
if (!currentStore) {
|
|
321
|
+
throw new Error('Usage plugin not initialized');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const currentUsage = await getDailyUsage(userId, featureCode);
|
|
325
|
+
|
|
326
|
+
// Get limit from subscriptions plugin
|
|
327
|
+
let limit: number | null = null;
|
|
328
|
+
if (getFeatureLimitFn) {
|
|
329
|
+
limit = await getFeatureLimitFn(userId, featureCode);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (limit === null) {
|
|
333
|
+
return {
|
|
334
|
+
allowed: false,
|
|
335
|
+
current_count: currentUsage,
|
|
336
|
+
limit: null,
|
|
337
|
+
remaining: null,
|
|
338
|
+
reason: 'Feature not available in your subscription',
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (limit === 0) {
|
|
343
|
+
return {
|
|
344
|
+
allowed: false,
|
|
345
|
+
current_count: currentUsage,
|
|
346
|
+
limit: 0,
|
|
347
|
+
remaining: 0,
|
|
348
|
+
reason: 'Feature is disabled',
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Check if within limit
|
|
353
|
+
const wouldExceed = limit !== -1 && currentUsage + amount > limit;
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
allowed: !wouldExceed,
|
|
357
|
+
current_count: currentUsage,
|
|
358
|
+
limit,
|
|
359
|
+
remaining: limit === -1 ? -1 : Math.max(0, limit - currentUsage),
|
|
360
|
+
resets_at: getTomorrowMidnight(),
|
|
361
|
+
reason: wouldExceed ? 'Would exceed daily limit' : undefined,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Get usage status for a specific feature
|
|
367
|
+
*/
|
|
368
|
+
export async function getFeatureUsageStatus(userId: string, featureCode: string): Promise<UsageStatus> {
|
|
369
|
+
if (!currentStore) {
|
|
370
|
+
throw new Error('Usage plugin not initialized');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const currentUsage = await getDailyUsage(userId, featureCode);
|
|
374
|
+
|
|
375
|
+
// Get limit from subscriptions plugin
|
|
376
|
+
let limit: number | null = null;
|
|
377
|
+
if (getFeatureLimitFn) {
|
|
378
|
+
limit = await getFeatureLimitFn(userId, featureCode);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let remaining: number | null = null;
|
|
382
|
+
let percentageUsed: number | null = null;
|
|
383
|
+
|
|
384
|
+
if (limit !== null) {
|
|
385
|
+
if (limit === -1) {
|
|
386
|
+
remaining = -1; // Unlimited
|
|
387
|
+
} else if (limit > 0) {
|
|
388
|
+
remaining = Math.max(0, limit - currentUsage);
|
|
389
|
+
percentageUsed = Math.min(100, Math.round((currentUsage / limit) * 100));
|
|
390
|
+
} else {
|
|
391
|
+
remaining = 0;
|
|
392
|
+
percentageUsed = 100;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
feature_code: featureCode,
|
|
398
|
+
current: currentUsage,
|
|
399
|
+
limit,
|
|
400
|
+
remaining,
|
|
401
|
+
resets_at: getTomorrowMidnight(),
|
|
402
|
+
percentage_used: percentageUsed,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Get daily usage summary for all features
|
|
408
|
+
*/
|
|
409
|
+
export async function getDailyUsageSummary(userId: string, date?: string): Promise<UsageSummary> {
|
|
410
|
+
if (!currentStore) {
|
|
411
|
+
throw new Error('Usage plugin not initialized');
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const targetDate = date || getCurrentDate();
|
|
415
|
+
const dailyUsages = await currentStore.getAllDailyUsage(userId, targetDate);
|
|
416
|
+
|
|
417
|
+
// Get status for each feature
|
|
418
|
+
const features: UsageStatus[] = await Promise.all(
|
|
419
|
+
dailyUsages.map(async (usage) => {
|
|
420
|
+
let limit: number | null = null;
|
|
421
|
+
if (getFeatureLimitFn) {
|
|
422
|
+
limit = await getFeatureLimitFn(userId, usage.feature_code);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
let remaining: number | null = null;
|
|
426
|
+
let percentageUsed: number | null = null;
|
|
427
|
+
|
|
428
|
+
if (limit !== null) {
|
|
429
|
+
if (limit === -1) {
|
|
430
|
+
remaining = -1;
|
|
431
|
+
} else if (limit > 0) {
|
|
432
|
+
remaining = Math.max(0, limit - usage.count);
|
|
433
|
+
percentageUsed = Math.min(100, Math.round((usage.count / limit) * 100));
|
|
434
|
+
} else {
|
|
435
|
+
remaining = 0;
|
|
436
|
+
percentageUsed = 100;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
feature_code: usage.feature_code,
|
|
442
|
+
current: usage.count,
|
|
443
|
+
limit,
|
|
444
|
+
remaining,
|
|
445
|
+
resets_at: getTomorrowMidnight(),
|
|
446
|
+
percentage_used: percentageUsed,
|
|
447
|
+
};
|
|
448
|
+
})
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
return {
|
|
452
|
+
user_id: userId,
|
|
453
|
+
period: 'daily',
|
|
454
|
+
period_value: targetDate,
|
|
455
|
+
features,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Reset usage for a feature (admin function)
|
|
461
|
+
*/
|
|
462
|
+
export async function resetUsage(userId: string, featureCode: string): Promise<void> {
|
|
463
|
+
if (!currentStore) {
|
|
464
|
+
throw new Error('Usage plugin not initialized');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
await currentStore.resetDailyUsage(userId, featureCode);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Get remaining quota for a feature
|
|
472
|
+
*/
|
|
473
|
+
export async function getRemainingQuota(userId: string, featureCode: string): Promise<number | null> {
|
|
474
|
+
const status = await getFeatureUsageStatus(userId, featureCode);
|
|
475
|
+
return status.remaining;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Check if user can use a feature (has remaining quota)
|
|
480
|
+
*/
|
|
481
|
+
export async function canUseFeature(userId: string, featureCode: string, amount = 1): Promise<boolean> {
|
|
482
|
+
const result = await checkUsageLimit(userId, featureCode, amount);
|
|
483
|
+
return result.allowed;
|
|
484
|
+
}
|