@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,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Utilities Tests
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for device token generation, hashing, and verification.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from 'vitest';
|
|
8
|
+
import {
|
|
9
|
+
generateDeviceToken,
|
|
10
|
+
generatePairingCode,
|
|
11
|
+
hashToken,
|
|
12
|
+
verifyToken,
|
|
13
|
+
isValidTokenFormat,
|
|
14
|
+
isTokenExpired,
|
|
15
|
+
getTokenExpiration,
|
|
16
|
+
} from '../token-utils.js';
|
|
17
|
+
|
|
18
|
+
describe('Token Utilities', () => {
|
|
19
|
+
describe('generateDeviceToken', () => {
|
|
20
|
+
it('should generate a token with the correct prefix', async () => {
|
|
21
|
+
const result = await generateDeviceToken('mob');
|
|
22
|
+
expect(result.token).toMatch(/^mob_/);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should generate a 43-character secret after prefix', async () => {
|
|
26
|
+
const result = await generateDeviceToken('mob');
|
|
27
|
+
const secret = result.token.split('_')[1];
|
|
28
|
+
expect(secret.length).toBe(43);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should generate base64url-safe characters', async () => {
|
|
32
|
+
const result = await generateDeviceToken('test');
|
|
33
|
+
const secret = result.token.split('_')[1];
|
|
34
|
+
expect(secret).toMatch(/^[A-Za-z0-9_-]+$/);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should return a SHA-256 hash (64 hex characters)', async () => {
|
|
38
|
+
const result = await generateDeviceToken('mob');
|
|
39
|
+
expect(result.hash).toMatch(/^[a-f0-9]{64}$/);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should return an 8-character prefix for display', async () => {
|
|
43
|
+
const result = await generateDeviceToken('mob');
|
|
44
|
+
expect(result.prefix.length).toBe(8);
|
|
45
|
+
expect(result.token.startsWith(result.prefix)).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should generate unique tokens each time', async () => {
|
|
49
|
+
const result1 = await generateDeviceToken('mob');
|
|
50
|
+
const result2 = await generateDeviceToken('mob');
|
|
51
|
+
|
|
52
|
+
expect(result1.token).not.toBe(result2.token);
|
|
53
|
+
expect(result1.hash).not.toBe(result2.hash);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('generatePairingCode', () => {
|
|
58
|
+
it('should generate a 6-character code', () => {
|
|
59
|
+
const code = generatePairingCode();
|
|
60
|
+
expect(code.length).toBe(6);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should only contain uppercase alphanumeric characters', () => {
|
|
64
|
+
const code = generatePairingCode();
|
|
65
|
+
// Excludes confusing chars: 0, O, I, 1
|
|
66
|
+
expect(code).toMatch(/^[ABCDEFGHJKLMNPQRSTUVWXYZ23456789]+$/);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should generate unique codes', () => {
|
|
70
|
+
const codes = new Set<string>();
|
|
71
|
+
for (let i = 0; i < 100; i++) {
|
|
72
|
+
codes.add(generatePairingCode());
|
|
73
|
+
}
|
|
74
|
+
// Should have mostly unique codes (allowing some collisions)
|
|
75
|
+
expect(codes.size).toBeGreaterThan(90);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('hashToken', () => {
|
|
80
|
+
it('should return a 64-character hex string', async () => {
|
|
81
|
+
const hash = await hashToken('test_token');
|
|
82
|
+
expect(hash.length).toBe(64);
|
|
83
|
+
expect(hash).toMatch(/^[a-f0-9]+$/);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should produce consistent hashes for same input', async () => {
|
|
87
|
+
const hash1 = await hashToken('same_token');
|
|
88
|
+
const hash2 = await hashToken('same_token');
|
|
89
|
+
expect(hash1).toBe(hash2);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should produce different hashes for different input', async () => {
|
|
93
|
+
const hash1 = await hashToken('token_one');
|
|
94
|
+
const hash2 = await hashToken('token_two');
|
|
95
|
+
expect(hash1).not.toBe(hash2);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('verifyToken', () => {
|
|
100
|
+
it('should return valid for matching token and hash', async () => {
|
|
101
|
+
const token = 'mob_ABC123testtoken';
|
|
102
|
+
const hash = await hashToken(token);
|
|
103
|
+
|
|
104
|
+
const result = await verifyToken(token, hash);
|
|
105
|
+
|
|
106
|
+
expect(result.valid).toBe(true);
|
|
107
|
+
expect(result.error).toBeUndefined();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should return invalid for non-matching token', async () => {
|
|
111
|
+
const originalHash = await hashToken('original_token');
|
|
112
|
+
|
|
113
|
+
const result = await verifyToken('different_token', originalHash);
|
|
114
|
+
|
|
115
|
+
expect(result.valid).toBe(false);
|
|
116
|
+
expect(result.error).toBe('Invalid token');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should handle malformed hash gracefully', async () => {
|
|
120
|
+
const result = await verifyToken('some_token', 'not-a-valid-hex-hash');
|
|
121
|
+
|
|
122
|
+
expect(result.valid).toBe(false);
|
|
123
|
+
expect(result.error).toBeDefined();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should use constant-time comparison (timing-safe)', async () => {
|
|
127
|
+
// This test ensures the comparison doesn't leak timing info
|
|
128
|
+
// We can't directly test timing, but we verify the function uses the correct approach
|
|
129
|
+
const token = 'mob_securetoken123';
|
|
130
|
+
const hash = await hashToken(token);
|
|
131
|
+
|
|
132
|
+
// Multiple verifications should all succeed
|
|
133
|
+
for (let i = 0; i < 10; i++) {
|
|
134
|
+
const result = await verifyToken(token, hash);
|
|
135
|
+
expect(result.valid).toBe(true);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('isValidTokenFormat', () => {
|
|
141
|
+
it('should return true for valid token format', () => {
|
|
142
|
+
// 43 base64url characters after prefix (32 bytes = 43 chars in base64url)
|
|
143
|
+
const validToken = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
144
|
+
expect(isValidTokenFormat(validToken, 'mob')).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should return false for wrong prefix', () => {
|
|
148
|
+
const token = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
149
|
+
expect(isValidTokenFormat(token, 'cpute')).toBe(false);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should return false for missing underscore', () => {
|
|
153
|
+
const token = 'mobABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456';
|
|
154
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should return false for too short secret', () => {
|
|
158
|
+
const token = 'mob_tooshort';
|
|
159
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(false);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should return false for too long secret', () => {
|
|
163
|
+
const token = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk123456extra';
|
|
164
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should return false for invalid characters', () => {
|
|
168
|
+
const token = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()123456';
|
|
169
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(false);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should accept base64url characters including - and _', () => {
|
|
173
|
+
const token = 'mob_ABCDEFGHIJKLMNOPQRSTUVWXYZ-_abcdefghij12345';
|
|
174
|
+
expect(isValidTokenFormat(token, 'mob')).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe('isTokenExpired', () => {
|
|
179
|
+
it('should return false for future date', () => {
|
|
180
|
+
const futureDate = new Date();
|
|
181
|
+
futureDate.setDate(futureDate.getDate() + 30);
|
|
182
|
+
|
|
183
|
+
expect(isTokenExpired(futureDate)).toBe(false);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should return true for past date', () => {
|
|
187
|
+
const pastDate = new Date();
|
|
188
|
+
pastDate.setDate(pastDate.getDate() - 1);
|
|
189
|
+
|
|
190
|
+
expect(isTokenExpired(pastDate)).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should return true for date exactly now (edge case)', () => {
|
|
194
|
+
const now = new Date();
|
|
195
|
+
// Slightly in the past to ensure it's expired
|
|
196
|
+
now.setMilliseconds(now.getMilliseconds() - 1);
|
|
197
|
+
|
|
198
|
+
expect(isTokenExpired(now)).toBe(true);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
describe('getTokenExpiration', () => {
|
|
203
|
+
it('should return a date 90 days in the future by default', () => {
|
|
204
|
+
const now = new Date();
|
|
205
|
+
const expiration = getTokenExpiration();
|
|
206
|
+
|
|
207
|
+
const daysDiff = Math.round(
|
|
208
|
+
(expiration.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
expect(daysDiff).toBe(90);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should accept custom validity days', () => {
|
|
215
|
+
const now = new Date();
|
|
216
|
+
const expiration = getTokenExpiration(30);
|
|
217
|
+
|
|
218
|
+
const daysDiff = Math.round(
|
|
219
|
+
(expiration.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
expect(daysDiff).toBe(30);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should handle 0 days (expires immediately)', () => {
|
|
226
|
+
const now = new Date();
|
|
227
|
+
const expiration = getTokenExpiration(0);
|
|
228
|
+
|
|
229
|
+
// Should be very close to now
|
|
230
|
+
const diffMs = Math.abs(expiration.getTime() - now.getTime());
|
|
231
|
+
expect(diffMs).toBeLessThan(1000); // Within 1 second
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should handle large values', () => {
|
|
235
|
+
const now = new Date();
|
|
236
|
+
const expiration = getTokenExpiration(365);
|
|
237
|
+
|
|
238
|
+
const daysDiff = Math.round(
|
|
239
|
+
(expiration.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
expect(daysDiff).toBe(365);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
describe('integration: generate and verify', () => {
|
|
247
|
+
it('should generate token that can be verified', async () => {
|
|
248
|
+
const { token, hash } = await generateDeviceToken('mob');
|
|
249
|
+
|
|
250
|
+
const verifyResult = await verifyToken(token, hash);
|
|
251
|
+
|
|
252
|
+
expect(verifyResult.valid).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should reject tampered token', async () => {
|
|
256
|
+
const { hash } = await generateDeviceToken('mob');
|
|
257
|
+
const tamperedToken = 'mob_tamperedtokenthatisdifferentfromoriginal';
|
|
258
|
+
|
|
259
|
+
const verifyResult = await verifyToken(tamperedToken, hash);
|
|
260
|
+
|
|
261
|
+
expect(verifyResult.valid).toBe(false);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute Device Adapter
|
|
3
|
+
*
|
|
4
|
+
* Adapter for computing devices (laptops, desktops, containers).
|
|
5
|
+
* Used by QwickForge for CLI device management.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
DeviceAdapter,
|
|
12
|
+
CreateDeviceInput,
|
|
13
|
+
ValidationResult,
|
|
14
|
+
Device,
|
|
15
|
+
ComputeDeviceMetadata,
|
|
16
|
+
} from '../types.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Compute adapter configuration
|
|
20
|
+
*/
|
|
21
|
+
export interface ComputeAdapterConfig {
|
|
22
|
+
/** Token prefix (default: 'qwf_dev') */
|
|
23
|
+
tokenPrefix?: string;
|
|
24
|
+
/** Require hostname in metadata */
|
|
25
|
+
requireHostname?: boolean;
|
|
26
|
+
/** Allowed OS types (optional, allows all if not specified) */
|
|
27
|
+
allowedOS?: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a compute device adapter
|
|
32
|
+
*
|
|
33
|
+
* @param config - Adapter configuration
|
|
34
|
+
* @returns DeviceAdapter for compute devices
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const adapter = computeDeviceAdapter({
|
|
39
|
+
* tokenPrefix: 'qwf_dev',
|
|
40
|
+
* requireHostname: true,
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function computeDeviceAdapter(config: ComputeAdapterConfig = {}): DeviceAdapter {
|
|
45
|
+
const {
|
|
46
|
+
tokenPrefix = 'qwf_dev',
|
|
47
|
+
requireHostname = false,
|
|
48
|
+
allowedOS,
|
|
49
|
+
} = config;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
name: 'compute',
|
|
53
|
+
tokenPrefix,
|
|
54
|
+
|
|
55
|
+
validateDeviceInput(input: CreateDeviceInput): ValidationResult {
|
|
56
|
+
const errors: string[] = [];
|
|
57
|
+
const metadata = input.metadata as ComputeDeviceMetadata | undefined;
|
|
58
|
+
|
|
59
|
+
// Validate name
|
|
60
|
+
if (!input.name || input.name.trim().length === 0) {
|
|
61
|
+
errors.push('Device name is required');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (input.name && input.name.length > 255) {
|
|
65
|
+
errors.push('Device name must be 255 characters or less');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Validate hostname if required
|
|
69
|
+
if (requireHostname && (!metadata?.hostname || metadata.hostname.trim().length === 0)) {
|
|
70
|
+
errors.push('Hostname is required for compute devices');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Validate OS if allowedOS is specified
|
|
74
|
+
if (allowedOS && metadata?.os) {
|
|
75
|
+
if (!allowedOS.includes(metadata.os)) {
|
|
76
|
+
errors.push(`OS '${metadata.os}' is not allowed. Allowed: ${allowedOS.join(', ')}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Validate architecture
|
|
81
|
+
if (metadata?.arch) {
|
|
82
|
+
const validArchs = ['x64', 'arm64', 'ia32', 'arm'];
|
|
83
|
+
if (!validArchs.includes(metadata.arch)) {
|
|
84
|
+
errors.push(`Invalid architecture '${metadata.arch}'. Valid: ${validArchs.join(', ')}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
valid: errors.length === 0,
|
|
90
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
transformForStorage(input: CreateDeviceInput): Record<string, unknown> {
|
|
95
|
+
const metadata = (input.metadata || {}) as ComputeDeviceMetadata;
|
|
96
|
+
|
|
97
|
+
// Ensure compute-specific defaults
|
|
98
|
+
return {
|
|
99
|
+
hostname: metadata.hostname || null,
|
|
100
|
+
os: metadata.os || null,
|
|
101
|
+
os_version: metadata.os_version || null,
|
|
102
|
+
arch: metadata.arch || null,
|
|
103
|
+
cli_capabilities: metadata.cli_capabilities || [],
|
|
104
|
+
container_id: metadata.container_id || null,
|
|
105
|
+
node_version: metadata.node_version || null,
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
transformFromStorage(row: Record<string, unknown>): Record<string, unknown> {
|
|
110
|
+
const metadata = (row.metadata || {}) as Record<string, unknown>;
|
|
111
|
+
|
|
112
|
+
// Extract compute-specific fields from metadata
|
|
113
|
+
return {
|
|
114
|
+
hostname: metadata.hostname,
|
|
115
|
+
os: metadata.os,
|
|
116
|
+
os_version: metadata.os_version,
|
|
117
|
+
arch: metadata.arch,
|
|
118
|
+
cli_capabilities: metadata.cli_capabilities || [],
|
|
119
|
+
container_id: metadata.container_id,
|
|
120
|
+
node_version: metadata.node_version,
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
async onDeviceCreated(device: Device): Promise<void> {
|
|
125
|
+
// Optional: Log device creation, send notifications, etc.
|
|
126
|
+
console.log(`[ComputeAdapter] Device created: ${device.name} (${device.id})`);
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
async onDeviceDeleted(device: Device): Promise<void> {
|
|
130
|
+
// Optional: Cleanup, revoke certificates, etc.
|
|
131
|
+
console.log(`[ComputeAdapter] Device deleted: ${device.name} (${device.id})`);
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
async onDeviceVerified(device: Device, ip?: string): Promise<void> {
|
|
135
|
+
// Optional: Log device verification, track activity
|
|
136
|
+
console.log(`[ComputeAdapter] Device verified: ${device.name} from ${ip || 'unknown'}`);
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device Adapters
|
|
3
|
+
*
|
|
4
|
+
* Export all built-in device adapters.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { computeDeviceAdapter } from './compute-adapter.js';
|
|
10
|
+
export type { ComputeAdapterConfig } from './compute-adapter.js';
|
|
11
|
+
|
|
12
|
+
export { mobileDeviceAdapter } from './mobile-adapter.js';
|
|
13
|
+
export type { MobileAdapterConfig } from './mobile-adapter.js';
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mobile Device Adapter
|
|
3
|
+
*
|
|
4
|
+
* Adapter for mobile devices (phones, tablets).
|
|
5
|
+
* Used by QwickBot for mobile app device management.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
DeviceAdapter,
|
|
12
|
+
CreateDeviceInput,
|
|
13
|
+
ValidationResult,
|
|
14
|
+
Device,
|
|
15
|
+
MobileDeviceMetadata,
|
|
16
|
+
} from '../types.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Mobile adapter configuration
|
|
20
|
+
*/
|
|
21
|
+
export interface MobileAdapterConfig {
|
|
22
|
+
/** Token prefix (default: 'qwb_mob') */
|
|
23
|
+
tokenPrefix?: string;
|
|
24
|
+
/** Require device model in metadata */
|
|
25
|
+
requireDeviceModel?: boolean;
|
|
26
|
+
/** Require app version in metadata */
|
|
27
|
+
requireAppVersion?: boolean;
|
|
28
|
+
/** Allowed OS names (optional, allows all if not specified) */
|
|
29
|
+
allowedOS?: string[];
|
|
30
|
+
/** Minimum app version (optional, uses semver) */
|
|
31
|
+
minAppVersion?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Compare semver versions (simplified)
|
|
36
|
+
*/
|
|
37
|
+
function compareSemver(v1: string, v2: string): number {
|
|
38
|
+
const parts1 = v1.split('.').map(Number);
|
|
39
|
+
const parts2 = v2.split('.').map(Number);
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < 3; i++) {
|
|
42
|
+
const p1 = parts1[i] || 0;
|
|
43
|
+
const p2 = parts2[i] || 0;
|
|
44
|
+
if (p1 > p2) return 1;
|
|
45
|
+
if (p1 < p2) return -1;
|
|
46
|
+
}
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create a mobile device adapter
|
|
52
|
+
*
|
|
53
|
+
* @param config - Adapter configuration
|
|
54
|
+
* @returns DeviceAdapter for mobile devices
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const adapter = mobileDeviceAdapter({
|
|
59
|
+
* tokenPrefix: 'qwb_mob',
|
|
60
|
+
* requireDeviceModel: true,
|
|
61
|
+
* allowedOS: ['iOS', 'Android'],
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export function mobileDeviceAdapter(config: MobileAdapterConfig = {}): DeviceAdapter {
|
|
66
|
+
const {
|
|
67
|
+
tokenPrefix = 'qwb_mob',
|
|
68
|
+
requireDeviceModel = false,
|
|
69
|
+
requireAppVersion = false,
|
|
70
|
+
allowedOS,
|
|
71
|
+
minAppVersion,
|
|
72
|
+
} = config;
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
name: 'mobile',
|
|
76
|
+
tokenPrefix,
|
|
77
|
+
|
|
78
|
+
validateDeviceInput(input: CreateDeviceInput): ValidationResult {
|
|
79
|
+
const errors: string[] = [];
|
|
80
|
+
const metadata = input.metadata as MobileDeviceMetadata | undefined;
|
|
81
|
+
|
|
82
|
+
// Validate name
|
|
83
|
+
if (!input.name || input.name.trim().length === 0) {
|
|
84
|
+
errors.push('Device name is required');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (input.name && input.name.length > 255) {
|
|
88
|
+
errors.push('Device name must be 255 characters or less');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Validate device model if required
|
|
92
|
+
if (requireDeviceModel && (!metadata?.device_model || metadata.device_model.trim().length === 0)) {
|
|
93
|
+
errors.push('Device model is required for mobile devices');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Validate app version if required
|
|
97
|
+
if (requireAppVersion && (!metadata?.app_version || metadata.app_version.trim().length === 0)) {
|
|
98
|
+
errors.push('App version is required for mobile devices');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Validate OS if allowedOS is specified
|
|
102
|
+
if (allowedOS && metadata?.os_name) {
|
|
103
|
+
if (!allowedOS.includes(metadata.os_name)) {
|
|
104
|
+
errors.push(`OS '${metadata.os_name}' is not supported. Supported: ${allowedOS.join(', ')}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Validate minimum app version
|
|
109
|
+
if (minAppVersion && metadata?.app_version) {
|
|
110
|
+
if (compareSemver(metadata.app_version, minAppVersion) < 0) {
|
|
111
|
+
errors.push(`App version ${metadata.app_version} is below minimum required version ${minAppVersion}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Validate screen dimensions if provided
|
|
116
|
+
if (metadata?.screen_width !== undefined && metadata.screen_width <= 0) {
|
|
117
|
+
errors.push('Screen width must be a positive number');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (metadata?.screen_height !== undefined && metadata.screen_height <= 0) {
|
|
121
|
+
errors.push('Screen height must be a positive number');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
valid: errors.length === 0,
|
|
126
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
transformForStorage(input: CreateDeviceInput): Record<string, unknown> {
|
|
131
|
+
const metadata = (input.metadata || {}) as MobileDeviceMetadata;
|
|
132
|
+
|
|
133
|
+
// Ensure mobile-specific defaults
|
|
134
|
+
return {
|
|
135
|
+
device_model: metadata.device_model || null,
|
|
136
|
+
os_name: metadata.os_name || null,
|
|
137
|
+
os_version: metadata.os_version || null,
|
|
138
|
+
app_version: metadata.app_version || null,
|
|
139
|
+
push_token: metadata.push_token || null,
|
|
140
|
+
screen_width: metadata.screen_width || null,
|
|
141
|
+
screen_height: metadata.screen_height || null,
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
transformFromStorage(row: Record<string, unknown>): Record<string, unknown> {
|
|
146
|
+
const metadata = (row.metadata || {}) as Record<string, unknown>;
|
|
147
|
+
|
|
148
|
+
// Extract mobile-specific fields from metadata
|
|
149
|
+
return {
|
|
150
|
+
device_model: metadata.device_model,
|
|
151
|
+
os_name: metadata.os_name,
|
|
152
|
+
os_version: metadata.os_version,
|
|
153
|
+
app_version: metadata.app_version,
|
|
154
|
+
push_token: metadata.push_token,
|
|
155
|
+
screen_width: metadata.screen_width,
|
|
156
|
+
screen_height: metadata.screen_height,
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
async onDeviceCreated(device: Device): Promise<void> {
|
|
161
|
+
// Optional: Log device creation, track in analytics, etc.
|
|
162
|
+
console.log(`[MobileAdapter] Device registered: ${device.name} (${device.id})`);
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
async onDeviceDeleted(device: Device): Promise<void> {
|
|
166
|
+
// Optional: Unregister push token, cleanup, etc.
|
|
167
|
+
const metadata = device.metadata as MobileDeviceMetadata;
|
|
168
|
+
if (metadata?.push_token) {
|
|
169
|
+
console.log(`[MobileAdapter] Should unregister push token for device: ${device.id}`);
|
|
170
|
+
}
|
|
171
|
+
console.log(`[MobileAdapter] Device deleted: ${device.name} (${device.id})`);
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
async onDeviceVerified(device: Device, ip?: string): Promise<void> {
|
|
175
|
+
// Optional: Log device verification, track activity
|
|
176
|
+
console.log(`[MobileAdapter] Device verified: ${device.name} from ${ip || 'unknown'}`);
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|