@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,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Adapter Wrapper Tests
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for the hot-reload adapter wrapper.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
8
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
9
|
+
import { createAdapterWrapper } from './adapter-wrapper.js';
|
|
10
|
+
import type { AuthAdapter, AuthenticatedUser } from './types.js';
|
|
11
|
+
|
|
12
|
+
// Helper to create a mock adapter
|
|
13
|
+
function createMockAdapter(name: string, overrides: Partial<AuthAdapter> = {}): AuthAdapter {
|
|
14
|
+
return {
|
|
15
|
+
name,
|
|
16
|
+
initialize: vi.fn().mockReturnValue((_req: Request, _res: Response, next: NextFunction) => next()),
|
|
17
|
+
isAuthenticated: vi.fn().mockReturnValue(false),
|
|
18
|
+
getUser: vi.fn().mockReturnValue(null),
|
|
19
|
+
hasRoles: vi.fn().mockReturnValue(false),
|
|
20
|
+
getAccessToken: vi.fn().mockReturnValue(null),
|
|
21
|
+
onUnauthorized: vi.fn(),
|
|
22
|
+
shutdown: vi.fn().mockResolvedValue(undefined),
|
|
23
|
+
...overrides,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Helper to create mock request/response
|
|
28
|
+
function createMockReq(): Request {
|
|
29
|
+
return {} as Request;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createMockRes(): Response {
|
|
33
|
+
return {
|
|
34
|
+
status: vi.fn().mockReturnThis(),
|
|
35
|
+
json: vi.fn().mockReturnThis(),
|
|
36
|
+
} as unknown as Response;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe('createAdapterWrapper', () => {
|
|
40
|
+
describe('initialization', () => {
|
|
41
|
+
it('should create wrapper with no-op adapter by default', () => {
|
|
42
|
+
const wrapper = createAdapterWrapper();
|
|
43
|
+
|
|
44
|
+
expect(wrapper.name).toBe('none');
|
|
45
|
+
expect(wrapper.hasAdapter()).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should create wrapper with initial adapter', () => {
|
|
49
|
+
const mockAdapter = createMockAdapter('test');
|
|
50
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
51
|
+
|
|
52
|
+
expect(wrapper.name).toBe('test');
|
|
53
|
+
expect(wrapper.hasAdapter()).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should return adapter info', () => {
|
|
57
|
+
const mockAdapter = createMockAdapter('test');
|
|
58
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
59
|
+
|
|
60
|
+
const info = wrapper.getAdapterInfo();
|
|
61
|
+
|
|
62
|
+
expect(info.name).toBe('test');
|
|
63
|
+
expect(info.initialized).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('initialize', () => {
|
|
68
|
+
it('should call underlying adapter initialize', () => {
|
|
69
|
+
const mockAdapter = createMockAdapter('test');
|
|
70
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
71
|
+
|
|
72
|
+
wrapper.initialize();
|
|
73
|
+
|
|
74
|
+
expect(mockAdapter.initialize).toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should mark wrapper as initialized', () => {
|
|
78
|
+
const mockAdapter = createMockAdapter('test');
|
|
79
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
80
|
+
|
|
81
|
+
wrapper.initialize();
|
|
82
|
+
|
|
83
|
+
expect(wrapper.getAdapterInfo().initialized).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should return middleware from underlying adapter', () => {
|
|
87
|
+
const mockMiddleware = vi.fn();
|
|
88
|
+
const mockAdapter = createMockAdapter('test', {
|
|
89
|
+
initialize: vi.fn().mockReturnValue(mockMiddleware),
|
|
90
|
+
});
|
|
91
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
92
|
+
|
|
93
|
+
const result = wrapper.initialize();
|
|
94
|
+
|
|
95
|
+
expect(result).toBe(mockMiddleware);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('isAuthenticated', () => {
|
|
100
|
+
it('should delegate to current adapter', () => {
|
|
101
|
+
const mockAdapter = createMockAdapter('test', {
|
|
102
|
+
isAuthenticated: vi.fn().mockReturnValue(true),
|
|
103
|
+
});
|
|
104
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
105
|
+
const req = createMockReq();
|
|
106
|
+
|
|
107
|
+
const result = wrapper.isAuthenticated(req);
|
|
108
|
+
|
|
109
|
+
expect(mockAdapter.isAuthenticated).toHaveBeenCalledWith(req);
|
|
110
|
+
expect(result).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should use new adapter after swap', async () => {
|
|
114
|
+
const oldAdapter = createMockAdapter('old', {
|
|
115
|
+
isAuthenticated: vi.fn().mockReturnValue(false),
|
|
116
|
+
});
|
|
117
|
+
const newAdapter = createMockAdapter('new', {
|
|
118
|
+
isAuthenticated: vi.fn().mockReturnValue(true),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const wrapper = createAdapterWrapper(oldAdapter);
|
|
122
|
+
await wrapper.setAdapter(newAdapter);
|
|
123
|
+
|
|
124
|
+
const req = createMockReq();
|
|
125
|
+
const result = wrapper.isAuthenticated(req);
|
|
126
|
+
|
|
127
|
+
expect(result).toBe(true);
|
|
128
|
+
expect(newAdapter.isAuthenticated).toHaveBeenCalledWith(req);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('getUser', () => {
|
|
133
|
+
it('should delegate to current adapter', () => {
|
|
134
|
+
const mockUser: AuthenticatedUser = {
|
|
135
|
+
id: '123',
|
|
136
|
+
email: 'test@example.com',
|
|
137
|
+
name: 'Test User',
|
|
138
|
+
};
|
|
139
|
+
const mockAdapter = createMockAdapter('test', {
|
|
140
|
+
getUser: vi.fn().mockReturnValue(mockUser),
|
|
141
|
+
});
|
|
142
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
143
|
+
const req = createMockReq();
|
|
144
|
+
|
|
145
|
+
const result = wrapper.getUser(req);
|
|
146
|
+
|
|
147
|
+
expect(mockAdapter.getUser).toHaveBeenCalledWith(req);
|
|
148
|
+
expect(result).toEqual(mockUser);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should return null for no-op adapter', () => {
|
|
152
|
+
const wrapper = createAdapterWrapper();
|
|
153
|
+
const req = createMockReq();
|
|
154
|
+
|
|
155
|
+
const result = wrapper.getUser(req);
|
|
156
|
+
|
|
157
|
+
expect(result).toBeNull();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('hasRoles', () => {
|
|
162
|
+
it('should delegate to current adapter if method exists', () => {
|
|
163
|
+
const mockAdapter = createMockAdapter('test', {
|
|
164
|
+
hasRoles: vi.fn().mockReturnValue(true),
|
|
165
|
+
});
|
|
166
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
167
|
+
const req = createMockReq();
|
|
168
|
+
|
|
169
|
+
// Wrapper always implements hasRoles
|
|
170
|
+
const result = wrapper.hasRoles!(req, ['admin']);
|
|
171
|
+
|
|
172
|
+
expect(mockAdapter.hasRoles).toHaveBeenCalledWith(req, ['admin']);
|
|
173
|
+
expect(result).toBe(true);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should return false if adapter has no hasRoles method', () => {
|
|
177
|
+
const mockAdapter = createMockAdapter('test');
|
|
178
|
+
delete (mockAdapter as Partial<AuthAdapter>).hasRoles;
|
|
179
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
180
|
+
const req = createMockReq();
|
|
181
|
+
|
|
182
|
+
// Wrapper always implements hasRoles, even if underlying adapter doesn't
|
|
183
|
+
const result = wrapper.hasRoles!(req, ['admin']);
|
|
184
|
+
|
|
185
|
+
expect(result).toBe(false);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('getAccessToken', () => {
|
|
190
|
+
it('should delegate to current adapter if method exists', () => {
|
|
191
|
+
const mockAdapter = createMockAdapter('test', {
|
|
192
|
+
getAccessToken: vi.fn().mockReturnValue('token123'),
|
|
193
|
+
});
|
|
194
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
195
|
+
const req = createMockReq();
|
|
196
|
+
|
|
197
|
+
// Wrapper always implements getAccessToken
|
|
198
|
+
const result = wrapper.getAccessToken!(req);
|
|
199
|
+
|
|
200
|
+
expect(mockAdapter.getAccessToken).toHaveBeenCalledWith(req);
|
|
201
|
+
expect(result).toBe('token123');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should return null if adapter has no getAccessToken method', () => {
|
|
205
|
+
const mockAdapter = createMockAdapter('test');
|
|
206
|
+
delete (mockAdapter as Partial<AuthAdapter>).getAccessToken;
|
|
207
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
208
|
+
const req = createMockReq();
|
|
209
|
+
|
|
210
|
+
// Wrapper always implements getAccessToken, returns null when adapter doesn't have it
|
|
211
|
+
const result = wrapper.getAccessToken!(req);
|
|
212
|
+
|
|
213
|
+
expect(result).toBeNull();
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe('onUnauthorized', () => {
|
|
218
|
+
it('should delegate to current adapter if method exists', () => {
|
|
219
|
+
const mockAdapter = createMockAdapter('test');
|
|
220
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
221
|
+
const req = createMockReq();
|
|
222
|
+
const res = createMockRes();
|
|
223
|
+
|
|
224
|
+
// Wrapper always implements onUnauthorized
|
|
225
|
+
wrapper.onUnauthorized!(req, res);
|
|
226
|
+
|
|
227
|
+
expect(mockAdapter.onUnauthorized).toHaveBeenCalledWith(req, res);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should return 401 JSON response if adapter has no onUnauthorized', () => {
|
|
231
|
+
const mockAdapter = createMockAdapter('test');
|
|
232
|
+
delete (mockAdapter as Partial<AuthAdapter>).onUnauthorized;
|
|
233
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
234
|
+
const req = createMockReq();
|
|
235
|
+
const res = createMockRes();
|
|
236
|
+
|
|
237
|
+
// Wrapper always implements onUnauthorized with default behavior
|
|
238
|
+
wrapper.onUnauthorized!(req, res);
|
|
239
|
+
|
|
240
|
+
expect(res.status).toHaveBeenCalledWith(401);
|
|
241
|
+
expect(res.json).toHaveBeenCalledWith({
|
|
242
|
+
error: 'Unauthorized',
|
|
243
|
+
message: 'Authentication required',
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
describe('setAdapter (hot-reload)', () => {
|
|
249
|
+
it('should swap adapter successfully', async () => {
|
|
250
|
+
const oldAdapter = createMockAdapter('old');
|
|
251
|
+
const newAdapter = createMockAdapter('new');
|
|
252
|
+
const wrapper = createAdapterWrapper(oldAdapter);
|
|
253
|
+
|
|
254
|
+
await wrapper.setAdapter(newAdapter);
|
|
255
|
+
|
|
256
|
+
expect(wrapper.name).toBe('new');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should shutdown old adapter before swap', async () => {
|
|
260
|
+
const oldAdapter = createMockAdapter('old');
|
|
261
|
+
const newAdapter = createMockAdapter('new');
|
|
262
|
+
const wrapper = createAdapterWrapper(oldAdapter);
|
|
263
|
+
|
|
264
|
+
await wrapper.setAdapter(newAdapter);
|
|
265
|
+
|
|
266
|
+
expect(oldAdapter.shutdown).toHaveBeenCalled();
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should initialize new adapter if wrapper was initialized', async () => {
|
|
270
|
+
const oldAdapter = createMockAdapter('old');
|
|
271
|
+
const newAdapter = createMockAdapter('new');
|
|
272
|
+
const wrapper = createAdapterWrapper(oldAdapter);
|
|
273
|
+
|
|
274
|
+
// Initialize wrapper
|
|
275
|
+
wrapper.initialize();
|
|
276
|
+
|
|
277
|
+
// Swap adapter
|
|
278
|
+
await wrapper.setAdapter(newAdapter);
|
|
279
|
+
|
|
280
|
+
expect(newAdapter.initialize).toHaveBeenCalled();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should not initialize new adapter if wrapper was not initialized', async () => {
|
|
284
|
+
const oldAdapter = createMockAdapter('old');
|
|
285
|
+
const newAdapter = createMockAdapter('new');
|
|
286
|
+
const wrapper = createAdapterWrapper(oldAdapter);
|
|
287
|
+
|
|
288
|
+
// Don't initialize wrapper
|
|
289
|
+
|
|
290
|
+
// Swap adapter
|
|
291
|
+
await wrapper.setAdapter(newAdapter);
|
|
292
|
+
|
|
293
|
+
expect(newAdapter.initialize).not.toHaveBeenCalled();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('should prevent concurrent adapter swaps', async () => {
|
|
297
|
+
const oldAdapter = createMockAdapter('old', {
|
|
298
|
+
shutdown: vi.fn().mockImplementation(() => new Promise((resolve) => setTimeout(resolve, 100))),
|
|
299
|
+
});
|
|
300
|
+
const newAdapter1 = createMockAdapter('new1');
|
|
301
|
+
const newAdapter2 = createMockAdapter('new2');
|
|
302
|
+
const wrapper = createAdapterWrapper(oldAdapter);
|
|
303
|
+
|
|
304
|
+
// Start first swap
|
|
305
|
+
const swap1 = wrapper.setAdapter(newAdapter1);
|
|
306
|
+
|
|
307
|
+
// Try second swap immediately (should fail)
|
|
308
|
+
await expect(wrapper.setAdapter(newAdapter2)).rejects.toThrow('Adapter swap already in progress');
|
|
309
|
+
|
|
310
|
+
// Wait for first swap to complete
|
|
311
|
+
await swap1;
|
|
312
|
+
|
|
313
|
+
// Now second swap should work
|
|
314
|
+
await wrapper.setAdapter(newAdapter2);
|
|
315
|
+
expect(wrapper.name).toBe('new2');
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('should handle shutdown errors gracefully', async () => {
|
|
319
|
+
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
320
|
+
|
|
321
|
+
const oldAdapter = createMockAdapter('old', {
|
|
322
|
+
shutdown: vi.fn().mockRejectedValue(new Error('Shutdown failed')),
|
|
323
|
+
});
|
|
324
|
+
const newAdapter = createMockAdapter('new');
|
|
325
|
+
const wrapper = createAdapterWrapper(oldAdapter);
|
|
326
|
+
|
|
327
|
+
// Should not throw
|
|
328
|
+
await wrapper.setAdapter(newAdapter);
|
|
329
|
+
|
|
330
|
+
expect(wrapper.name).toBe('new');
|
|
331
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
332
|
+
'[AdapterWrapper] Error shutting down old adapter:',
|
|
333
|
+
expect.any(Error)
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
consoleErrorSpy.mockRestore();
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
describe('shutdown', () => {
|
|
341
|
+
it('should shutdown current adapter', async () => {
|
|
342
|
+
const mockAdapter = createMockAdapter('test');
|
|
343
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
344
|
+
wrapper.initialize();
|
|
345
|
+
|
|
346
|
+
// Wrapper always implements shutdown
|
|
347
|
+
await wrapper.shutdown!();
|
|
348
|
+
|
|
349
|
+
expect(mockAdapter.shutdown).toHaveBeenCalled();
|
|
350
|
+
expect(wrapper.getAdapterInfo().initialized).toBe(false);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('should handle adapters without shutdown method', async () => {
|
|
354
|
+
const mockAdapter = createMockAdapter('test');
|
|
355
|
+
delete (mockAdapter as Partial<AuthAdapter>).shutdown;
|
|
356
|
+
const wrapper = createAdapterWrapper(mockAdapter);
|
|
357
|
+
wrapper.initialize();
|
|
358
|
+
|
|
359
|
+
// Should not throw - wrapper handles missing shutdown gracefully
|
|
360
|
+
await wrapper.shutdown!();
|
|
361
|
+
|
|
362
|
+
expect(wrapper.getAdapterInfo().initialized).toBe(false);
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
describe('no-op adapter', () => {
|
|
367
|
+
it('should return false for isAuthenticated', () => {
|
|
368
|
+
const wrapper = createAdapterWrapper();
|
|
369
|
+
const req = createMockReq();
|
|
370
|
+
|
|
371
|
+
expect(wrapper.isAuthenticated(req)).toBe(false);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('should return null for getUser', () => {
|
|
375
|
+
const wrapper = createAdapterWrapper();
|
|
376
|
+
const req = createMockReq();
|
|
377
|
+
|
|
378
|
+
expect(wrapper.getUser(req)).toBeNull();
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('should return middleware that calls next', () => {
|
|
382
|
+
const wrapper = createAdapterWrapper();
|
|
383
|
+
const middleware = wrapper.initialize();
|
|
384
|
+
|
|
385
|
+
const req = createMockReq();
|
|
386
|
+
const res = createMockRes();
|
|
387
|
+
const next = vi.fn();
|
|
388
|
+
|
|
389
|
+
if (typeof middleware === 'function') {
|
|
390
|
+
middleware(req, res, next);
|
|
391
|
+
expect(next).toHaveBeenCalled();
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Adapter Wrapper
|
|
3
|
+
*
|
|
4
|
+
* Wraps an auth adapter to enable hot-reload without server restart.
|
|
5
|
+
* All method calls are delegated to the underlying adapter, which can
|
|
6
|
+
* be swapped at runtime via setAdapter().
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Request, Response, RequestHandler } from 'express';
|
|
12
|
+
import type { AuthAdapter, AuthenticatedUser } from './types.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extended adapter interface with hot-reload capabilities
|
|
16
|
+
*/
|
|
17
|
+
export interface AdapterWrapper extends AuthAdapter {
|
|
18
|
+
/**
|
|
19
|
+
* Replace the underlying adapter (for hot-reload)
|
|
20
|
+
* Calls shutdown() on the old adapter before swapping
|
|
21
|
+
*/
|
|
22
|
+
setAdapter(adapter: AuthAdapter): Promise<void>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get information about the current adapter
|
|
26
|
+
*/
|
|
27
|
+
getAdapterInfo(): { name: string; initialized: boolean };
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if an adapter is currently set
|
|
31
|
+
*/
|
|
32
|
+
hasAdapter(): boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a no-op adapter for when auth is disabled
|
|
37
|
+
*/
|
|
38
|
+
function createNoopAdapter(): AuthAdapter {
|
|
39
|
+
return {
|
|
40
|
+
name: 'none',
|
|
41
|
+
initialize: () => ((_req, _res, next) => next()) as RequestHandler,
|
|
42
|
+
isAuthenticated: () => false,
|
|
43
|
+
getUser: () => null,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Create an adapter wrapper for hot-reload support
|
|
49
|
+
*
|
|
50
|
+
* @param initialAdapter Optional initial adapter (defaults to no-op)
|
|
51
|
+
* @returns AdapterWrapper that delegates to the underlying adapter
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const wrapper = createAdapterWrapper(supertokensAdapter(config));
|
|
56
|
+
*
|
|
57
|
+
* // Later, swap the adapter without restart:
|
|
58
|
+
* await wrapper.setAdapter(auth0Adapter(newConfig));
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function createAdapterWrapper(initialAdapter?: AuthAdapter): AdapterWrapper {
|
|
62
|
+
let currentAdapter: AuthAdapter = initialAdapter || createNoopAdapter();
|
|
63
|
+
let isInitialized = false;
|
|
64
|
+
let isSwapping = false; // Prevent concurrent adapter swaps
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
// Delegate name to current adapter
|
|
68
|
+
get name(): string {
|
|
69
|
+
return currentAdapter.name;
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Initialize returns the middleware
|
|
74
|
+
* Note: This is called once at startup. The middleware itself
|
|
75
|
+
* will delegate to currentAdapter, which can be swapped.
|
|
76
|
+
*/
|
|
77
|
+
initialize(): RequestHandler | RequestHandler[] {
|
|
78
|
+
isInitialized = true;
|
|
79
|
+
|
|
80
|
+
// Get the initial middleware
|
|
81
|
+
const initialMiddleware = currentAdapter.initialize();
|
|
82
|
+
|
|
83
|
+
// Return a wrapper middleware that delegates to current adapter's middleware
|
|
84
|
+
// This allows hot-reload to work - new adapter's middleware will be used
|
|
85
|
+
// Note: For simplicity, we return the initial middleware. Full hot-reload
|
|
86
|
+
// of middleware would require more complex Express route manipulation.
|
|
87
|
+
// The key hot-reload capability is in isAuthenticated/getUser which ARE
|
|
88
|
+
// delegated dynamically.
|
|
89
|
+
return initialMiddleware;
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Delegate isAuthenticated to current adapter
|
|
94
|
+
*/
|
|
95
|
+
isAuthenticated(req: Request): boolean {
|
|
96
|
+
return currentAdapter.isAuthenticated(req);
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Delegate getUser to current adapter
|
|
101
|
+
*/
|
|
102
|
+
getUser(req: Request): AuthenticatedUser | null | Promise<AuthenticatedUser | null> {
|
|
103
|
+
return currentAdapter.getUser(req);
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Delegate hasRoles to current adapter (if available)
|
|
108
|
+
*/
|
|
109
|
+
hasRoles(req: Request, roles: string[]): boolean {
|
|
110
|
+
if (currentAdapter.hasRoles) {
|
|
111
|
+
return currentAdapter.hasRoles(req, roles);
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Delegate getAccessToken to current adapter (if available)
|
|
118
|
+
*/
|
|
119
|
+
getAccessToken(req: Request): string | null {
|
|
120
|
+
if (currentAdapter.getAccessToken) {
|
|
121
|
+
return currentAdapter.getAccessToken(req);
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Delegate onUnauthorized to current adapter (if available)
|
|
128
|
+
*/
|
|
129
|
+
onUnauthorized(req: Request, res: Response): void {
|
|
130
|
+
if (currentAdapter.onUnauthorized) {
|
|
131
|
+
currentAdapter.onUnauthorized(req, res);
|
|
132
|
+
} else {
|
|
133
|
+
res.status(401).json({
|
|
134
|
+
error: 'Unauthorized',
|
|
135
|
+
message: 'Authentication required',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Shutdown the current adapter
|
|
142
|
+
*/
|
|
143
|
+
async shutdown(): Promise<void> {
|
|
144
|
+
if (currentAdapter.shutdown) {
|
|
145
|
+
await currentAdapter.shutdown();
|
|
146
|
+
}
|
|
147
|
+
isInitialized = false;
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Hot-reload: Replace the underlying adapter
|
|
152
|
+
* @throws Error if another adapter swap is already in progress
|
|
153
|
+
*/
|
|
154
|
+
async setAdapter(adapter: AuthAdapter): Promise<void> {
|
|
155
|
+
// Prevent concurrent adapter swaps
|
|
156
|
+
if (isSwapping) {
|
|
157
|
+
throw new Error('Adapter swap already in progress');
|
|
158
|
+
}
|
|
159
|
+
isSwapping = true;
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const oldAdapter = currentAdapter;
|
|
163
|
+
|
|
164
|
+
// Shutdown old adapter
|
|
165
|
+
if (oldAdapter.shutdown) {
|
|
166
|
+
try {
|
|
167
|
+
await oldAdapter.shutdown();
|
|
168
|
+
} catch (err) {
|
|
169
|
+
console.error('[AdapterWrapper] Error shutting down old adapter:', err);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Set new adapter
|
|
174
|
+
currentAdapter = adapter;
|
|
175
|
+
|
|
176
|
+
// Initialize new adapter if we're already running
|
|
177
|
+
if (isInitialized) {
|
|
178
|
+
// Note: We initialize the new adapter but can't easily swap Express middleware
|
|
179
|
+
// The new adapter's isAuthenticated/getUser will be used immediately
|
|
180
|
+
// Full middleware hot-reload would require server restart
|
|
181
|
+
currentAdapter.initialize();
|
|
182
|
+
}
|
|
183
|
+
} finally {
|
|
184
|
+
isSwapping = false;
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get info about the current adapter
|
|
190
|
+
*/
|
|
191
|
+
getAdapterInfo(): { name: string; initialized: boolean } {
|
|
192
|
+
return {
|
|
193
|
+
name: currentAdapter.name,
|
|
194
|
+
initialized: isInitialized,
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Check if a real adapter is set (not the no-op)
|
|
200
|
+
*/
|
|
201
|
+
hasAdapter(): boolean {
|
|
202
|
+
return currentAdapter.name !== 'none';
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|