@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,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Devices Plugin Tests
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for the devices plugin including:
|
|
5
|
+
* - Plugin lifecycle (start, stop)
|
|
6
|
+
* - Device registration
|
|
7
|
+
* - Token verification
|
|
8
|
+
* - Helper functions
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
11
|
+
import { createDevicesPlugin, getDeviceStore, getDeviceAdapter, registerDevice, verifyDeviceToken, getDeviceById, updateDevice, deleteDevice, regenerateToken, listUserDevices, deactivateDevice, activateDevice, } from '../devices-plugin.js';
|
|
12
|
+
describe('Devices Plugin', () => {
|
|
13
|
+
// Mock device data
|
|
14
|
+
const mockDevice = {
|
|
15
|
+
id: 'device-id-123',
|
|
16
|
+
org_id: 'org-123',
|
|
17
|
+
user_id: 'user-123',
|
|
18
|
+
adapter_type: 'mobile',
|
|
19
|
+
name: 'Test Phone',
|
|
20
|
+
token_prefix: 'mob_1234',
|
|
21
|
+
token_expires_at: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
|
|
22
|
+
last_seen_at: new Date(),
|
|
23
|
+
last_ip: '192.168.1.1',
|
|
24
|
+
is_active: true,
|
|
25
|
+
metadata: { device_model: 'iPhone 15', os_name: 'iOS', os_version: '17.0' },
|
|
26
|
+
created_at: new Date(),
|
|
27
|
+
updated_at: new Date(),
|
|
28
|
+
};
|
|
29
|
+
// Mock store factory
|
|
30
|
+
const createMockStore = () => ({
|
|
31
|
+
name: 'mock',
|
|
32
|
+
initialize: vi.fn().mockResolvedValue(undefined),
|
|
33
|
+
getById: vi.fn().mockResolvedValue(mockDevice),
|
|
34
|
+
getByTokenHash: vi.fn().mockResolvedValue(mockDevice),
|
|
35
|
+
create: vi.fn().mockResolvedValue(mockDevice),
|
|
36
|
+
update: vi.fn().mockResolvedValue(mockDevice),
|
|
37
|
+
delete: vi.fn().mockResolvedValue(true),
|
|
38
|
+
search: vi.fn().mockResolvedValue({
|
|
39
|
+
devices: [mockDevice],
|
|
40
|
+
total: 1,
|
|
41
|
+
page: 1,
|
|
42
|
+
limit: 20,
|
|
43
|
+
totalPages: 1,
|
|
44
|
+
}),
|
|
45
|
+
updateLastSeen: vi.fn().mockResolvedValue(undefined),
|
|
46
|
+
updateToken: vi.fn().mockResolvedValue(true),
|
|
47
|
+
cleanupExpired: vi.fn().mockResolvedValue(5),
|
|
48
|
+
shutdown: vi.fn().mockResolvedValue(undefined),
|
|
49
|
+
});
|
|
50
|
+
// Mock adapter factory
|
|
51
|
+
const createMockAdapter = () => ({
|
|
52
|
+
name: 'mobile',
|
|
53
|
+
tokenPrefix: 'mob',
|
|
54
|
+
validateDeviceInput: vi.fn().mockReturnValue({ valid: true }),
|
|
55
|
+
transformForStorage: vi.fn().mockImplementation((input) => input.metadata || {}),
|
|
56
|
+
transformFromStorage: vi.fn().mockImplementation((row) => row),
|
|
57
|
+
onDeviceCreated: vi.fn().mockResolvedValue(undefined),
|
|
58
|
+
onDeviceDeleted: vi.fn().mockResolvedValue(undefined),
|
|
59
|
+
onDeviceVerified: vi.fn().mockResolvedValue(undefined),
|
|
60
|
+
});
|
|
61
|
+
// Mock registry factory
|
|
62
|
+
const createMockRegistry = () => ({
|
|
63
|
+
hasPlugin: vi.fn().mockReturnValue(false),
|
|
64
|
+
getPlugin: vi.fn().mockReturnValue(null),
|
|
65
|
+
listPlugins: vi.fn().mockReturnValue([]),
|
|
66
|
+
addRoute: vi.fn(),
|
|
67
|
+
addMenuItem: vi.fn(),
|
|
68
|
+
addPage: vi.fn(),
|
|
69
|
+
addWidget: vi.fn(),
|
|
70
|
+
getRoutes: vi.fn().mockReturnValue([]),
|
|
71
|
+
getMenuItems: vi.fn().mockReturnValue([]),
|
|
72
|
+
getPages: vi.fn().mockReturnValue([]),
|
|
73
|
+
getWidgets: vi.fn().mockReturnValue([]),
|
|
74
|
+
getConfig: vi.fn().mockReturnValue({}),
|
|
75
|
+
setConfig: vi.fn().mockResolvedValue(undefined),
|
|
76
|
+
subscribe: vi.fn().mockReturnValue(() => { }),
|
|
77
|
+
emit: vi.fn(),
|
|
78
|
+
registerHealthCheck: vi.fn(),
|
|
79
|
+
getApp: vi.fn().mockReturnValue({}),
|
|
80
|
+
getRouter: vi.fn().mockReturnValue({}),
|
|
81
|
+
getLogger: vi.fn().mockReturnValue({
|
|
82
|
+
debug: vi.fn(),
|
|
83
|
+
info: vi.fn(),
|
|
84
|
+
warn: vi.fn(),
|
|
85
|
+
error: vi.fn(),
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
let mockStore;
|
|
89
|
+
let mockAdapter;
|
|
90
|
+
let mockRegistry;
|
|
91
|
+
beforeEach(() => {
|
|
92
|
+
vi.clearAllMocks();
|
|
93
|
+
mockStore = createMockStore();
|
|
94
|
+
mockAdapter = createMockAdapter();
|
|
95
|
+
mockRegistry = createMockRegistry();
|
|
96
|
+
});
|
|
97
|
+
afterEach(async () => {
|
|
98
|
+
// Clean up by stopping the plugin if it was started
|
|
99
|
+
const store = getDeviceStore();
|
|
100
|
+
if (store) {
|
|
101
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
102
|
+
await plugin.onStop?.();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
describe('createDevicesPlugin', () => {
|
|
106
|
+
it('should create a plugin with correct id', () => {
|
|
107
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
108
|
+
expect(plugin.id).toBe('devices');
|
|
109
|
+
});
|
|
110
|
+
it('should create a plugin with correct name', () => {
|
|
111
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
112
|
+
expect(plugin.name).toBe('Devices');
|
|
113
|
+
});
|
|
114
|
+
it('should create a plugin with version', () => {
|
|
115
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
116
|
+
expect(plugin.version).toBe('1.0.0');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('onStart', () => {
|
|
120
|
+
it('should initialize store on start', async () => {
|
|
121
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
122
|
+
await plugin.onStart({}, mockRegistry);
|
|
123
|
+
expect(mockStore.initialize).toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
it('should register health check', async () => {
|
|
126
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
127
|
+
await plugin.onStart({}, mockRegistry);
|
|
128
|
+
expect(mockRegistry.registerHealthCheck).toHaveBeenCalledWith(expect.objectContaining({
|
|
129
|
+
name: 'devices-store',
|
|
130
|
+
type: 'custom',
|
|
131
|
+
}));
|
|
132
|
+
});
|
|
133
|
+
it('should register CRUD routes by default', async () => {
|
|
134
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
135
|
+
await plugin.onStart({}, mockRegistry);
|
|
136
|
+
// GET /devices, GET /devices/:id, POST /devices, PUT /devices/:id,
|
|
137
|
+
// DELETE /devices/:id, POST /devices/:id/regenerate-token, POST /devices/verify
|
|
138
|
+
expect(mockRegistry.addRoute).toHaveBeenCalledTimes(7);
|
|
139
|
+
});
|
|
140
|
+
it('should use custom API prefix when provided', async () => {
|
|
141
|
+
const plugin = createDevicesPlugin({
|
|
142
|
+
store: mockStore,
|
|
143
|
+
adapter: mockAdapter,
|
|
144
|
+
api: { prefix: '/api/devices' },
|
|
145
|
+
});
|
|
146
|
+
await plugin.onStart({}, mockRegistry);
|
|
147
|
+
const calls = mockRegistry.addRoute.mock.calls;
|
|
148
|
+
expect(calls[0][0].path).toBe('/api/devices');
|
|
149
|
+
});
|
|
150
|
+
it('should skip CRUD routes when disabled', async () => {
|
|
151
|
+
const plugin = createDevicesPlugin({
|
|
152
|
+
store: mockStore,
|
|
153
|
+
adapter: mockAdapter,
|
|
154
|
+
api: { crud: false },
|
|
155
|
+
});
|
|
156
|
+
await plugin.onStart({}, mockRegistry);
|
|
157
|
+
// Only verification endpoint
|
|
158
|
+
expect(mockRegistry.addRoute).toHaveBeenCalledTimes(1);
|
|
159
|
+
});
|
|
160
|
+
it('should skip verify endpoint when disabled', async () => {
|
|
161
|
+
const plugin = createDevicesPlugin({
|
|
162
|
+
store: mockStore,
|
|
163
|
+
adapter: mockAdapter,
|
|
164
|
+
api: { verify: false },
|
|
165
|
+
});
|
|
166
|
+
await plugin.onStart({}, mockRegistry);
|
|
167
|
+
// 6 CRUD routes, no verify
|
|
168
|
+
expect(mockRegistry.addRoute).toHaveBeenCalledTimes(6);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
describe('onStop', () => {
|
|
172
|
+
it('should shutdown store', async () => {
|
|
173
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
174
|
+
await plugin.onStart({}, mockRegistry);
|
|
175
|
+
await plugin.onStop?.();
|
|
176
|
+
expect(mockStore.shutdown).toHaveBeenCalled();
|
|
177
|
+
});
|
|
178
|
+
it('should clear store reference', async () => {
|
|
179
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
180
|
+
await plugin.onStart({}, mockRegistry);
|
|
181
|
+
await plugin.onStop?.();
|
|
182
|
+
expect(getDeviceStore()).toBeNull();
|
|
183
|
+
});
|
|
184
|
+
it('should clear adapter reference', async () => {
|
|
185
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
186
|
+
await plugin.onStart({}, mockRegistry);
|
|
187
|
+
await plugin.onStop?.();
|
|
188
|
+
expect(getDeviceAdapter()).toBeNull();
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
describe('helper functions', () => {
|
|
192
|
+
describe('getDeviceStore', () => {
|
|
193
|
+
it('should return null when plugin not started', () => {
|
|
194
|
+
expect(getDeviceStore()).toBeNull();
|
|
195
|
+
});
|
|
196
|
+
it('should return store when plugin started', async () => {
|
|
197
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
198
|
+
await plugin.onStart({}, mockRegistry);
|
|
199
|
+
expect(getDeviceStore()).toBe(mockStore);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
describe('getDeviceAdapter', () => {
|
|
203
|
+
it('should return null when plugin not started', () => {
|
|
204
|
+
expect(getDeviceAdapter()).toBeNull();
|
|
205
|
+
});
|
|
206
|
+
it('should return adapter when plugin started', async () => {
|
|
207
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
208
|
+
await plugin.onStart({}, mockRegistry);
|
|
209
|
+
expect(getDeviceAdapter()).toBe(mockAdapter);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
describe('registerDevice', () => {
|
|
213
|
+
it('should throw when plugin not initialized', async () => {
|
|
214
|
+
await expect(registerDevice({ name: 'Test Device' })).rejects.toThrow('Devices plugin not initialized');
|
|
215
|
+
});
|
|
216
|
+
it('should create device with generated token', async () => {
|
|
217
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
218
|
+
await plugin.onStart({}, mockRegistry);
|
|
219
|
+
const result = await registerDevice({
|
|
220
|
+
name: 'Test Device',
|
|
221
|
+
user_id: 'user-123',
|
|
222
|
+
});
|
|
223
|
+
expect(result.id).toBe(mockDevice.id);
|
|
224
|
+
expect(result.token).toBeDefined();
|
|
225
|
+
expect(mockStore.create).toHaveBeenCalled();
|
|
226
|
+
});
|
|
227
|
+
it('should throw on validation failure', async () => {
|
|
228
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
229
|
+
await plugin.onStart({}, mockRegistry);
|
|
230
|
+
mockAdapter.validateDeviceInput.mockReturnValue({
|
|
231
|
+
valid: false,
|
|
232
|
+
errors: ['Name is required'],
|
|
233
|
+
});
|
|
234
|
+
await expect(registerDevice({ name: '' })).rejects.toThrow('Validation failed: Name is required');
|
|
235
|
+
});
|
|
236
|
+
it('should call adapter onDeviceCreated hook', async () => {
|
|
237
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
238
|
+
await plugin.onStart({}, mockRegistry);
|
|
239
|
+
await registerDevice({ name: 'Test Device' });
|
|
240
|
+
expect(mockAdapter.onDeviceCreated).toHaveBeenCalledWith(mockDevice);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
describe('verifyDeviceToken', () => {
|
|
244
|
+
it('should return error when plugin not initialized', async () => {
|
|
245
|
+
const result = await verifyDeviceToken('mob_testtoken');
|
|
246
|
+
expect(result.valid).toBe(false);
|
|
247
|
+
expect(result.error).toBe('Devices plugin not initialized');
|
|
248
|
+
});
|
|
249
|
+
it('should return error for invalid token format', async () => {
|
|
250
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
251
|
+
await plugin.onStart({}, mockRegistry);
|
|
252
|
+
const result = await verifyDeviceToken('invalid_format');
|
|
253
|
+
expect(result.valid).toBe(false);
|
|
254
|
+
expect(result.error).toBe('Invalid token format');
|
|
255
|
+
});
|
|
256
|
+
it('should return error when token not found', async () => {
|
|
257
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
258
|
+
await plugin.onStart({}, mockRegistry);
|
|
259
|
+
mockStore.getByTokenHash.mockResolvedValue(null);
|
|
260
|
+
// Valid format token (43 chars after prefix)
|
|
261
|
+
const validToken = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
262
|
+
const result = await verifyDeviceToken(validToken);
|
|
263
|
+
expect(result.valid).toBe(false);
|
|
264
|
+
expect(result.error).toBe('Token not found or expired');
|
|
265
|
+
});
|
|
266
|
+
it('should return error for expired token', async () => {
|
|
267
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
268
|
+
await plugin.onStart({}, mockRegistry);
|
|
269
|
+
const expiredDevice = {
|
|
270
|
+
...mockDevice,
|
|
271
|
+
token_expires_at: new Date(Date.now() - 1000), // expired
|
|
272
|
+
};
|
|
273
|
+
mockStore.getByTokenHash.mockResolvedValue(expiredDevice);
|
|
274
|
+
const validToken = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
275
|
+
const result = await verifyDeviceToken(validToken);
|
|
276
|
+
expect(result.valid).toBe(false);
|
|
277
|
+
expect(result.error).toBe('Token has expired');
|
|
278
|
+
});
|
|
279
|
+
it('should return error for inactive device', async () => {
|
|
280
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
281
|
+
await plugin.onStart({}, mockRegistry);
|
|
282
|
+
const inactiveDevice = { ...mockDevice, is_active: false };
|
|
283
|
+
mockStore.getByTokenHash.mockResolvedValue(inactiveDevice);
|
|
284
|
+
const validToken = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
285
|
+
const result = await verifyDeviceToken(validToken);
|
|
286
|
+
expect(result.valid).toBe(false);
|
|
287
|
+
expect(result.error).toBe('Device is not active');
|
|
288
|
+
});
|
|
289
|
+
it('should return valid device and update last seen', async () => {
|
|
290
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
291
|
+
await plugin.onStart({}, mockRegistry);
|
|
292
|
+
const validToken = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
293
|
+
const result = await verifyDeviceToken(validToken, '10.0.0.1');
|
|
294
|
+
expect(result.valid).toBe(true);
|
|
295
|
+
expect(result.device).toEqual(mockDevice);
|
|
296
|
+
expect(mockStore.updateLastSeen).toHaveBeenCalledWith(mockDevice.id, '10.0.0.1');
|
|
297
|
+
});
|
|
298
|
+
it('should call adapter onDeviceVerified hook', async () => {
|
|
299
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
300
|
+
await plugin.onStart({}, mockRegistry);
|
|
301
|
+
const validToken = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
302
|
+
await verifyDeviceToken(validToken, '10.0.0.1');
|
|
303
|
+
expect(mockAdapter.onDeviceVerified).toHaveBeenCalledWith(mockDevice, '10.0.0.1');
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
describe('getDeviceById', () => {
|
|
307
|
+
it('should throw when plugin not initialized', async () => {
|
|
308
|
+
await expect(getDeviceById('device-id')).rejects.toThrow('Devices plugin not initialized');
|
|
309
|
+
});
|
|
310
|
+
it('should return device when found', async () => {
|
|
311
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
312
|
+
await plugin.onStart({}, mockRegistry);
|
|
313
|
+
const result = await getDeviceById(mockDevice.id);
|
|
314
|
+
expect(result).toEqual(mockDevice);
|
|
315
|
+
});
|
|
316
|
+
it('should return null when not found', async () => {
|
|
317
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
318
|
+
await plugin.onStart({}, mockRegistry);
|
|
319
|
+
mockStore.getById.mockResolvedValue(null);
|
|
320
|
+
const result = await getDeviceById('non-existent');
|
|
321
|
+
expect(result).toBeNull();
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
describe('updateDevice', () => {
|
|
325
|
+
it('should throw when plugin not initialized', async () => {
|
|
326
|
+
await expect(updateDevice('device-id', { name: 'New Name' })).rejects.toThrow('Devices plugin not initialized');
|
|
327
|
+
});
|
|
328
|
+
it('should update device', async () => {
|
|
329
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
330
|
+
await plugin.onStart({}, mockRegistry);
|
|
331
|
+
const updated = { ...mockDevice, name: 'Updated Name' };
|
|
332
|
+
mockStore.update.mockResolvedValue(updated);
|
|
333
|
+
const result = await updateDevice(mockDevice.id, { name: 'Updated Name' });
|
|
334
|
+
expect(result?.name).toBe('Updated Name');
|
|
335
|
+
expect(mockStore.update).toHaveBeenCalledWith(mockDevice.id, { name: 'Updated Name' });
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
describe('deleteDevice', () => {
|
|
339
|
+
it('should throw when plugin not initialized', async () => {
|
|
340
|
+
await expect(deleteDevice('device-id')).rejects.toThrow('Devices plugin not initialized');
|
|
341
|
+
});
|
|
342
|
+
it('should delete device and call adapter hook', async () => {
|
|
343
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
344
|
+
await plugin.onStart({}, mockRegistry);
|
|
345
|
+
const result = await deleteDevice(mockDevice.id);
|
|
346
|
+
expect(result).toBe(true);
|
|
347
|
+
expect(mockStore.delete).toHaveBeenCalledWith(mockDevice.id);
|
|
348
|
+
expect(mockAdapter.onDeviceDeleted).toHaveBeenCalledWith(mockDevice);
|
|
349
|
+
});
|
|
350
|
+
it('should return false when device not found', async () => {
|
|
351
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
352
|
+
await plugin.onStart({}, mockRegistry);
|
|
353
|
+
mockStore.getById.mockResolvedValue(null);
|
|
354
|
+
const result = await deleteDevice('non-existent');
|
|
355
|
+
expect(result).toBe(false);
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
describe('regenerateToken', () => {
|
|
359
|
+
it('should throw when plugin not initialized', async () => {
|
|
360
|
+
await expect(regenerateToken('device-id')).rejects.toThrow('Devices plugin not initialized');
|
|
361
|
+
});
|
|
362
|
+
it('should return null when device not found', async () => {
|
|
363
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
364
|
+
await plugin.onStart({}, mockRegistry);
|
|
365
|
+
mockStore.getById.mockResolvedValue(null);
|
|
366
|
+
const result = await regenerateToken('non-existent');
|
|
367
|
+
expect(result).toBeNull();
|
|
368
|
+
});
|
|
369
|
+
it('should regenerate token and return new token', async () => {
|
|
370
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
371
|
+
await plugin.onStart({}, mockRegistry);
|
|
372
|
+
const result = await regenerateToken(mockDevice.id, 30);
|
|
373
|
+
expect(result).not.toBeNull();
|
|
374
|
+
expect(result?.token).toMatch(/^mob_/);
|
|
375
|
+
expect(result?.expiresAt).toBeInstanceOf(Date);
|
|
376
|
+
expect(mockStore.updateToken).toHaveBeenCalled();
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
describe('listUserDevices', () => {
|
|
380
|
+
it('should throw when plugin not initialized', async () => {
|
|
381
|
+
await expect(listUserDevices('user-id')).rejects.toThrow('Devices plugin not initialized');
|
|
382
|
+
});
|
|
383
|
+
it('should return user devices', async () => {
|
|
384
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
385
|
+
await plugin.onStart({}, mockRegistry);
|
|
386
|
+
const result = await listUserDevices('user-123');
|
|
387
|
+
expect(result).toHaveLength(1);
|
|
388
|
+
expect(result[0]).toEqual(mockDevice);
|
|
389
|
+
expect(mockStore.search).toHaveBeenCalledWith({ user_id: 'user-123', limit: 100 });
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
describe('deactivateDevice / activateDevice', () => {
|
|
393
|
+
it('should deactivate device', async () => {
|
|
394
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
395
|
+
await plugin.onStart({}, mockRegistry);
|
|
396
|
+
const result = await deactivateDevice(mockDevice.id);
|
|
397
|
+
expect(result).toBe(true);
|
|
398
|
+
expect(mockStore.update).toHaveBeenCalledWith(mockDevice.id, { is_active: false });
|
|
399
|
+
});
|
|
400
|
+
it('should activate device', async () => {
|
|
401
|
+
const plugin = createDevicesPlugin({ store: mockStore, adapter: mockAdapter });
|
|
402
|
+
await plugin.onStart({}, mockRegistry);
|
|
403
|
+
const result = await activateDevice(mockDevice.id);
|
|
404
|
+
expect(result).toBe(true);
|
|
405
|
+
expect(mockStore.update).toHaveBeenCalledWith(mockDevice.id, { is_active: true });
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
//# sourceMappingURL=devices-plugin.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices-plugin.test.js","sourceRoot":"","sources":["../../../../src/plugins/devices/__tests__/devices-plugin.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-utils.test.d.ts","sourceRoot":"","sources":["../../../../src/plugins/devices/__tests__/token-utils.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Utilities Tests
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for device token generation, hashing, and verification.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import { generateDeviceToken, generatePairingCode, hashToken, verifyToken, isValidTokenFormat, isTokenExpired, getTokenExpiration, } from '../token-utils.js';
|
|
8
|
+
describe('Token Utilities', () => {
|
|
9
|
+
describe('generateDeviceToken', () => {
|
|
10
|
+
it('should generate a token with the correct prefix', async () => {
|
|
11
|
+
const result = await generateDeviceToken('mob');
|
|
12
|
+
expect(result.token).toMatch(/^mob_/);
|
|
13
|
+
});
|
|
14
|
+
it('should generate a 43-character secret after prefix', async () => {
|
|
15
|
+
const result = await generateDeviceToken('mob');
|
|
16
|
+
const secret = result.token.split('_')[1];
|
|
17
|
+
expect(secret.length).toBe(43);
|
|
18
|
+
});
|
|
19
|
+
it('should generate base64url-safe characters', async () => {
|
|
20
|
+
const result = await generateDeviceToken('test');
|
|
21
|
+
const secret = result.token.split('_')[1];
|
|
22
|
+
expect(secret).toMatch(/^[A-Za-z0-9_-]+$/);
|
|
23
|
+
});
|
|
24
|
+
it('should return a SHA-256 hash (64 hex characters)', async () => {
|
|
25
|
+
const result = await generateDeviceToken('mob');
|
|
26
|
+
expect(result.hash).toMatch(/^[a-f0-9]{64}$/);
|
|
27
|
+
});
|
|
28
|
+
it('should return an 8-character prefix for display', async () => {
|
|
29
|
+
const result = await generateDeviceToken('mob');
|
|
30
|
+
expect(result.prefix.length).toBe(8);
|
|
31
|
+
expect(result.token.startsWith(result.prefix)).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
it('should generate unique tokens each time', async () => {
|
|
34
|
+
const result1 = await generateDeviceToken('mob');
|
|
35
|
+
const result2 = await generateDeviceToken('mob');
|
|
36
|
+
expect(result1.token).not.toBe(result2.token);
|
|
37
|
+
expect(result1.hash).not.toBe(result2.hash);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('generatePairingCode', () => {
|
|
41
|
+
it('should generate a 6-character code', () => {
|
|
42
|
+
const code = generatePairingCode();
|
|
43
|
+
expect(code.length).toBe(6);
|
|
44
|
+
});
|
|
45
|
+
it('should only contain uppercase alphanumeric characters', () => {
|
|
46
|
+
const code = generatePairingCode();
|
|
47
|
+
// Excludes confusing chars: 0, O, I, 1
|
|
48
|
+
expect(code).toMatch(/^[ABCDEFGHJKLMNPQRSTUVWXYZ23456789]+$/);
|
|
49
|
+
});
|
|
50
|
+
it('should generate unique codes', () => {
|
|
51
|
+
const codes = new Set();
|
|
52
|
+
for (let i = 0; i < 100; i++) {
|
|
53
|
+
codes.add(generatePairingCode());
|
|
54
|
+
}
|
|
55
|
+
// Should have mostly unique codes (allowing some collisions)
|
|
56
|
+
expect(codes.size).toBeGreaterThan(90);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('hashToken', () => {
|
|
60
|
+
it('should return a 64-character hex string', async () => {
|
|
61
|
+
const hash = await hashToken('test_token');
|
|
62
|
+
expect(hash.length).toBe(64);
|
|
63
|
+
expect(hash).toMatch(/^[a-f0-9]+$/);
|
|
64
|
+
});
|
|
65
|
+
it('should produce consistent hashes for same input', async () => {
|
|
66
|
+
const hash1 = await hashToken('same_token');
|
|
67
|
+
const hash2 = await hashToken('same_token');
|
|
68
|
+
expect(hash1).toBe(hash2);
|
|
69
|
+
});
|
|
70
|
+
it('should produce different hashes for different input', async () => {
|
|
71
|
+
const hash1 = await hashToken('token_one');
|
|
72
|
+
const hash2 = await hashToken('token_two');
|
|
73
|
+
expect(hash1).not.toBe(hash2);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('verifyToken', () => {
|
|
77
|
+
it('should return valid for matching token and hash', async () => {
|
|
78
|
+
const token = 'mob_ABC123testtoken';
|
|
79
|
+
const hash = await hashToken(token);
|
|
80
|
+
const result = await verifyToken(token, hash);
|
|
81
|
+
expect(result.valid).toBe(true);
|
|
82
|
+
expect(result.error).toBeUndefined();
|
|
83
|
+
});
|
|
84
|
+
it('should return invalid for non-matching token', async () => {
|
|
85
|
+
const originalHash = await hashToken('original_token');
|
|
86
|
+
const result = await verifyToken('different_token', originalHash);
|
|
87
|
+
expect(result.valid).toBe(false);
|
|
88
|
+
expect(result.error).toBe('Invalid token');
|
|
89
|
+
});
|
|
90
|
+
it('should handle malformed hash gracefully', async () => {
|
|
91
|
+
const result = await verifyToken('some_token', 'not-a-valid-hex-hash');
|
|
92
|
+
expect(result.valid).toBe(false);
|
|
93
|
+
expect(result.error).toBeDefined();
|
|
94
|
+
});
|
|
95
|
+
it('should use constant-time comparison (timing-safe)', async () => {
|
|
96
|
+
// This test ensures the comparison doesn't leak timing info
|
|
97
|
+
// We can't directly test timing, but we verify the function uses the correct approach
|
|
98
|
+
const token = 'mob_securetoken123';
|
|
99
|
+
const hash = await hashToken(token);
|
|
100
|
+
// Multiple verifications should all succeed
|
|
101
|
+
for (let i = 0; i < 10; i++) {
|
|
102
|
+
const result = await verifyToken(token, hash);
|
|
103
|
+
expect(result.valid).toBe(true);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe('isValidTokenFormat', () => {
|
|
108
|
+
it('should return true for valid token format', () => {
|
|
109
|
+
// 43 base64url characters after prefix (32 bytes = 43 chars in base64url)
|
|
110
|
+
const validToken = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
111
|
+
expect(isValidTokenFormat(validToken, 'mob')).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
it('should return false for wrong prefix', () => {
|
|
114
|
+
const token = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
115
|
+
expect(isValidTokenFormat(token, 'cpute')).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
it('should return false for missing underscore', () => {
|
|
118
|
+
const token = 'mobABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
119
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
it('should return false for too short secret', () => {
|
|
122
|
+
const token = 'mob_tooshort';
|
|
123
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(false);
|
|
124
|
+
});
|
|
125
|
+
it('should return false for too long secret', () => {
|
|
126
|
+
const token = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456extra';
|
|
127
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
it('should return false for invalid characters', () => {
|
|
130
|
+
const token = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()123456';
|
|
131
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
it('should accept base64url characters including - and _', () => {
|
|
134
|
+
const token = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZ-_abcdefghij12345';
|
|
135
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe('isTokenExpired', () => {
|
|
139
|
+
it('should return false for future date', () => {
|
|
140
|
+
const futureDate = new Date();
|
|
141
|
+
futureDate.setDate(futureDate.getDate() + 30);
|
|
142
|
+
expect(isTokenExpired(futureDate)).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
it('should return true for past date', () => {
|
|
145
|
+
const pastDate = new Date();
|
|
146
|
+
pastDate.setDate(pastDate.getDate() - 1);
|
|
147
|
+
expect(isTokenExpired(pastDate)).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
it('should return true for date exactly now (edge case)', () => {
|
|
150
|
+
const now = new Date();
|
|
151
|
+
// Slightly in the past to ensure it's expired
|
|
152
|
+
now.setMilliseconds(now.getMilliseconds() - 1);
|
|
153
|
+
expect(isTokenExpired(now)).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
describe('getTokenExpiration', () => {
|
|
157
|
+
it('should return a date 90 days in the future by default', () => {
|
|
158
|
+
const now = new Date();
|
|
159
|
+
const expiration = getTokenExpiration();
|
|
160
|
+
const daysDiff = Math.round((expiration.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
161
|
+
expect(daysDiff).toBe(90);
|
|
162
|
+
});
|
|
163
|
+
it('should accept custom validity days', () => {
|
|
164
|
+
const now = new Date();
|
|
165
|
+
const expiration = getTokenExpiration(30);
|
|
166
|
+
const daysDiff = Math.round((expiration.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
167
|
+
expect(daysDiff).toBe(30);
|
|
168
|
+
});
|
|
169
|
+
it('should handle 0 days (expires immediately)', () => {
|
|
170
|
+
const now = new Date();
|
|
171
|
+
const expiration = getTokenExpiration(0);
|
|
172
|
+
// Should be very close to now
|
|
173
|
+
const diffMs = Math.abs(expiration.getTime() - now.getTime());
|
|
174
|
+
expect(diffMs).toBeLessThan(1000); // Within 1 second
|
|
175
|
+
});
|
|
176
|
+
it('should handle large values', () => {
|
|
177
|
+
const now = new Date();
|
|
178
|
+
const expiration = getTokenExpiration(365);
|
|
179
|
+
const daysDiff = Math.round((expiration.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
180
|
+
expect(daysDiff).toBe(365);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('integration: generate and verify', () => {
|
|
184
|
+
it('should generate token that can be verified', async () => {
|
|
185
|
+
const { token, hash } = await generateDeviceToken('mob');
|
|
186
|
+
const verifyResult = await verifyToken(token, hash);
|
|
187
|
+
expect(verifyResult.valid).toBe(true);
|
|
188
|
+
});
|
|
189
|
+
it('should reject tampered token', async () => {
|
|
190
|
+
const { hash } = await generateDeviceToken('mob');
|
|
191
|
+
const tamperedToken = 'mob_tamperedtokenthatisdifferentfromoriginal';
|
|
192
|
+
const verifyResult = await verifyToken(tamperedToken, hash);
|
|
193
|
+
expect(verifyResult.valid).toBe(false);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
//# sourceMappingURL=token-utils.test.js.map
|