@qwickapps/server 1.8.1 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/src/core/control-panel.d.ts.map +1 -1
  3. package/dist/src/core/control-panel.js +10 -7
  4. package/dist/src/core/control-panel.js.map +1 -1
  5. package/dist/src/core/gateway.d.ts.map +1 -1
  6. package/dist/src/core/gateway.js +46 -47
  7. package/dist/src/core/gateway.js.map +1 -1
  8. package/dist/src/plugins/api-keys/ApiKeysManagementPage.d.ts.map +1 -1
  9. package/dist/src/plugins/api-keys/ApiKeysManagementPage.js +1 -1
  10. package/dist/src/plugins/api-keys/ApiKeysManagementPage.js.map +1 -1
  11. package/dist/src/plugins/api-keys/ApiKeysStatusWidget.d.ts.map +1 -1
  12. package/dist/src/plugins/api-keys/ApiKeysStatusWidget.js +1 -1
  13. package/dist/src/plugins/api-keys/ApiKeysStatusWidget.js.map +1 -1
  14. package/dist/src/plugins/auth/AuthManagementPage.d.ts.map +1 -1
  15. package/dist/src/plugins/auth/AuthManagementPage.js +1 -1
  16. package/dist/src/plugins/auth/AuthManagementPage.js.map +1 -1
  17. package/dist/src/plugins/auth/AuthStatusWidget.d.ts.map +1 -1
  18. package/dist/src/plugins/auth/AuthStatusWidget.js +1 -1
  19. package/dist/src/plugins/auth/AuthStatusWidget.js.map +1 -1
  20. package/dist/src/plugins/auth/auth-plugin.d.ts.map +1 -1
  21. package/dist/src/plugins/auth/auth-plugin.js +9 -0
  22. package/dist/src/plugins/auth/auth-plugin.js.map +1 -1
  23. package/dist/src/plugins/bans/BansManagementPage.d.ts.map +1 -1
  24. package/dist/src/plugins/bans/BansManagementPage.js +1 -1
  25. package/dist/src/plugins/bans/BansManagementPage.js.map +1 -1
  26. package/dist/src/plugins/bans/BansStatusWidget.d.ts.map +1 -1
  27. package/dist/src/plugins/bans/BansStatusWidget.js +1 -1
  28. package/dist/src/plugins/bans/BansStatusWidget.js.map +1 -1
  29. package/dist/src/plugins/cache/CacheManagementPage.js +1 -1
  30. package/dist/src/plugins/cache/CacheManagementPage.js.map +1 -1
  31. package/dist/src/plugins/cache/CacheStatusWidget.js +1 -1
  32. package/dist/src/plugins/cache/CacheStatusWidget.js.map +1 -1
  33. package/dist/src/plugins/devices/DevicesManagementPage.d.ts.map +1 -1
  34. package/dist/src/plugins/devices/DevicesManagementPage.js +1 -1
  35. package/dist/src/plugins/devices/DevicesManagementPage.js.map +1 -1
  36. package/dist/src/plugins/devices/DevicesStatusWidget.d.ts.map +1 -1
  37. package/dist/src/plugins/devices/DevicesStatusWidget.js +1 -1
  38. package/dist/src/plugins/devices/DevicesStatusWidget.js.map +1 -1
  39. package/dist/src/plugins/diagnostics/DiagnosticsManagementPage.js +1 -1
  40. package/dist/src/plugins/diagnostics/DiagnosticsManagementPage.js.map +1 -1
  41. package/dist/src/plugins/diagnostics/DiagnosticsStatusWidget.js +1 -1
  42. package/dist/src/plugins/diagnostics/DiagnosticsStatusWidget.js.map +1 -1
  43. package/dist/src/plugins/entitlements/EntitlementsManagementPage.d.ts.map +1 -1
  44. package/dist/src/plugins/entitlements/EntitlementsManagementPage.js +1 -1
  45. package/dist/src/plugins/entitlements/EntitlementsManagementPage.js.map +1 -1
  46. package/dist/src/plugins/entitlements/EntitlementsStatusWidget.d.ts.map +1 -1
  47. package/dist/src/plugins/entitlements/EntitlementsStatusWidget.js +1 -1
  48. package/dist/src/plugins/entitlements/EntitlementsStatusWidget.js.map +1 -1
  49. package/dist/src/plugins/health/HealthManagementPage.js +1 -1
  50. package/dist/src/plugins/health/HealthManagementPage.js.map +1 -1
  51. package/dist/src/plugins/health/HealthStatusWidget.js +1 -1
  52. package/dist/src/plugins/health/HealthStatusWidget.js.map +1 -1
  53. package/dist/src/plugins/logs/LogsManagementPage.js +1 -1
  54. package/dist/src/plugins/logs/LogsManagementPage.js.map +1 -1
  55. package/dist/src/plugins/logs/LogsStatusWidget.js +1 -1
  56. package/dist/src/plugins/logs/LogsStatusWidget.js.map +1 -1
  57. package/dist/src/plugins/maintenance/MaintenanceManagementPage.js +1 -1
  58. package/dist/src/plugins/maintenance/MaintenanceManagementPage.js.map +1 -1
  59. package/dist/src/plugins/maintenance/MaintenanceStatusWidget.js +1 -1
  60. package/dist/src/plugins/maintenance/MaintenanceStatusWidget.js.map +1 -1
  61. package/dist/src/plugins/maintenance/SeedManagementPage.js +1 -1
  62. package/dist/src/plugins/maintenance/SeedManagementPage.js.map +1 -1
  63. package/dist/src/plugins/maintenance/seed-executor.js +2 -2
  64. package/dist/src/plugins/maintenance/seed-executor.js.map +1 -1
  65. package/dist/src/plugins/maintenance-plugin.d.ts +2 -0
  66. package/dist/src/plugins/maintenance-plugin.d.ts.map +1 -1
  67. package/dist/src/plugins/maintenance-plugin.js +402 -2
  68. package/dist/src/plugins/maintenance-plugin.js.map +1 -1
  69. package/dist/src/plugins/notifications/NotificationsManagementPage.js +1 -1
  70. package/dist/src/plugins/notifications/NotificationsManagementPage.js.map +1 -1
  71. package/dist/src/plugins/notifications/NotificationsStatusWidget.d.ts.map +1 -1
  72. package/dist/src/plugins/notifications/NotificationsStatusWidget.js +1 -1
  73. package/dist/src/plugins/notifications/NotificationsStatusWidget.js.map +1 -1
  74. package/dist/src/plugins/parental/ParentalManagementPage.d.ts.map +1 -1
  75. package/dist/src/plugins/parental/ParentalManagementPage.js +1 -1
  76. package/dist/src/plugins/parental/ParentalManagementPage.js.map +1 -1
  77. package/dist/src/plugins/parental/ParentalStatusWidget.d.ts.map +1 -1
  78. package/dist/src/plugins/parental/ParentalStatusWidget.js +1 -1
  79. package/dist/src/plugins/parental/ParentalStatusWidget.js.map +1 -1
  80. package/dist/src/plugins/postgres/PostgresManagementPage.js +1 -1
  81. package/dist/src/plugins/postgres/PostgresManagementPage.js.map +1 -1
  82. package/dist/src/plugins/postgres/PostgresStatusWidget.js +1 -1
  83. package/dist/src/plugins/postgres/PostgresStatusWidget.js.map +1 -1
  84. package/dist/src/plugins/preferences/PreferencesManagementPage.d.ts.map +1 -1
  85. package/dist/src/plugins/preferences/PreferencesManagementPage.js +1 -1
  86. package/dist/src/plugins/preferences/PreferencesManagementPage.js.map +1 -1
  87. package/dist/src/plugins/preferences/PreferencesStatusWidget.d.ts.map +1 -1
  88. package/dist/src/plugins/preferences/PreferencesStatusWidget.js +1 -1
  89. package/dist/src/plugins/preferences/PreferencesStatusWidget.js.map +1 -1
  90. package/dist/src/plugins/profiles/ProfilesManagementPage.d.ts.map +1 -1
  91. package/dist/src/plugins/profiles/ProfilesManagementPage.js +1 -1
  92. package/dist/src/plugins/profiles/ProfilesManagementPage.js.map +1 -1
  93. package/dist/src/plugins/profiles/ProfilesStatusWidget.d.ts.map +1 -1
  94. package/dist/src/plugins/profiles/ProfilesStatusWidget.js +1 -1
  95. package/dist/src/plugins/profiles/ProfilesStatusWidget.js.map +1 -1
  96. package/dist/src/plugins/qwickbrain/QwickbrainManagementPage.js +1 -1
  97. package/dist/src/plugins/qwickbrain/QwickbrainManagementPage.js.map +1 -1
  98. package/dist/src/plugins/qwickbrain/QwickbrainStatusWidget.d.ts.map +1 -1
  99. package/dist/src/plugins/qwickbrain/QwickbrainStatusWidget.js +1 -1
  100. package/dist/src/plugins/qwickbrain/QwickbrainStatusWidget.js.map +1 -1
  101. package/dist/src/plugins/rate-limit/RateLimitManagementPage.js +1 -1
  102. package/dist/src/plugins/rate-limit/RateLimitManagementPage.js.map +1 -1
  103. package/dist/src/plugins/rate-limit/RateLimitStatusWidget.d.ts.map +1 -1
  104. package/dist/src/plugins/rate-limit/RateLimitStatusWidget.js +1 -1
  105. package/dist/src/plugins/rate-limit/RateLimitStatusWidget.js.map +1 -1
  106. package/dist/src/plugins/subscriptions/SubscriptionsManagementPage.d.ts.map +1 -1
  107. package/dist/src/plugins/subscriptions/SubscriptionsManagementPage.js +1 -1
  108. package/dist/src/plugins/subscriptions/SubscriptionsManagementPage.js.map +1 -1
  109. package/dist/src/plugins/subscriptions/SubscriptionsStatusWidget.d.ts.map +1 -1
  110. package/dist/src/plugins/subscriptions/SubscriptionsStatusWidget.js +1 -1
  111. package/dist/src/plugins/subscriptions/SubscriptionsStatusWidget.js.map +1 -1
  112. package/dist/src/plugins/usage/UsageManagementPage.d.ts.map +1 -1
  113. package/dist/src/plugins/usage/UsageManagementPage.js +1 -1
  114. package/dist/src/plugins/usage/UsageManagementPage.js.map +1 -1
  115. package/dist/src/plugins/usage/UsageStatusWidget.d.ts.map +1 -1
  116. package/dist/src/plugins/usage/UsageStatusWidget.js +1 -1
  117. package/dist/src/plugins/usage/UsageStatusWidget.js.map +1 -1
  118. package/dist/src/plugins/users/UsersManagementPage.js +1 -1
  119. package/dist/src/plugins/users/UsersManagementPage.js.map +1 -1
  120. package/dist/src/plugins/users/UsersStatusWidget.js +1 -1
  121. package/dist/src/plugins/users/UsersStatusWidget.js.map +1 -1
  122. package/dist/ui/src/api/clientBuilder.d.ts +3 -3
  123. package/dist/ui/src/api/clientBuilder.js +5 -5
  124. package/dist/ui/src/api/clientBuilder.js.map +1 -1
  125. package/dist/ui/src/api/controlPanelApi.js +19 -19
  126. package/dist/ui/src/api/controlPanelApi.js.map +1 -1
  127. package/dist/ui/src/components/ControlPanelApp.d.ts.map +1 -1
  128. package/dist/ui/src/components/ControlPanelApp.js +5 -4
  129. package/dist/ui/src/components/ControlPanelApp.js.map +1 -1
  130. package/dist/ui/src/dashboard/builtInWidgets.d.ts.map +1 -1
  131. package/dist/ui/src/dashboard/builtInWidgets.js +3 -1
  132. package/dist/ui/src/dashboard/builtInWidgets.js.map +1 -1
  133. package/dist/ui/src/dashboard/widgets/CMSMaintenanceWidget.js +8 -8
  134. package/dist/ui/src/dashboard/widgets/CMSMaintenanceWidget.js.map +1 -1
  135. package/dist/ui/src/dashboard/widgets/CMSStatusWidget.js +2 -2
  136. package/dist/ui/src/dashboard/widgets/CMSStatusWidget.js.map +1 -1
  137. package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js +4 -4
  138. package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js.map +1 -1
  139. package/dist/ui/src/dashboard/widgets/DatabaseOperationsWidget.d.ts.map +1 -1
  140. package/dist/ui/src/dashboard/widgets/DatabaseOperationsWidget.js +2 -1
  141. package/dist/ui/src/dashboard/widgets/DatabaseOperationsWidget.js.map +1 -1
  142. package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js +6 -6
  143. package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js.map +1 -1
  144. package/dist/ui/src/dashboard/widgets/MigrationManagementWidget.d.ts +8 -0
  145. package/dist/ui/src/dashboard/widgets/MigrationManagementWidget.d.ts.map +1 -0
  146. package/dist/ui/src/dashboard/widgets/MigrationManagementWidget.js +132 -0
  147. package/dist/ui/src/dashboard/widgets/MigrationManagementWidget.js.map +1 -0
  148. package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js +6 -6
  149. package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js.map +1 -1
  150. package/dist/ui/src/dashboard/widgets/index.d.ts +1 -0
  151. package/dist/ui/src/dashboard/widgets/index.d.ts.map +1 -1
  152. package/dist/ui/src/dashboard/widgets/index.js +1 -0
  153. package/dist/ui/src/dashboard/widgets/index.js.map +1 -1
  154. package/dist-ui/assets/{index-D-4HKPkw.js → index-Cez_jyhl.js} +111 -108
  155. package/dist-ui/assets/{index-D-4HKPkw.js.map → index-Cez_jyhl.js.map} +1 -1
  156. package/dist-ui/assets/{index-DRG9n0cx.css → index-De-dCl_t.css} +1 -1
  157. package/dist-ui/index.html +2 -2
  158. package/dist-ui-lib/index.js +2623 -2441
  159. package/dist-ui-lib/index.js.map +1 -1
  160. package/dist-ui-lib/src/api/clientBuilder.d.ts +3 -3
  161. package/dist-ui-lib/src/dashboard/widgets/MigrationManagementWidget.d.ts +7 -0
  162. package/dist-ui-lib/src/dashboard/widgets/index.d.ts +1 -0
  163. package/package.json +27 -26
  164. package/src/core/control-panel.ts +10 -7
  165. package/src/core/gateway.ts +48 -51
  166. package/src/plugins/api-keys/ApiKeysManagementPage.tsx +1 -1
  167. package/src/plugins/api-keys/ApiKeysStatusWidget.tsx +1 -1
  168. package/src/plugins/auth/AuthManagementPage.tsx +1 -1
  169. package/src/plugins/auth/AuthStatusWidget.tsx +1 -1
  170. package/src/plugins/auth/auth-plugin.ts +9 -0
  171. package/src/plugins/bans/BansManagementPage.tsx +1 -1
  172. package/src/plugins/bans/BansStatusWidget.tsx +1 -1
  173. package/src/plugins/cache/CacheManagementPage.tsx +1 -1
  174. package/src/plugins/cache/CacheStatusWidget.tsx +1 -1
  175. package/src/plugins/devices/DevicesManagementPage.tsx +1 -1
  176. package/src/plugins/devices/DevicesStatusWidget.tsx +1 -1
  177. package/src/plugins/diagnostics/DiagnosticsManagementPage.tsx +1 -1
  178. package/src/plugins/diagnostics/DiagnosticsStatusWidget.tsx +1 -1
  179. package/src/plugins/entitlements/EntitlementsManagementPage.tsx +1 -1
  180. package/src/plugins/entitlements/EntitlementsStatusWidget.tsx +1 -1
  181. package/src/plugins/health/HealthManagementPage.tsx +1 -1
  182. package/src/plugins/health/HealthStatusWidget.tsx +1 -1
  183. package/src/plugins/logs/LogsManagementPage.tsx +1 -1
  184. package/src/plugins/logs/LogsStatusWidget.tsx +1 -1
  185. package/src/plugins/maintenance/MaintenanceManagementPage.tsx +1 -1
  186. package/src/plugins/maintenance/MaintenanceStatusWidget.tsx +1 -1
  187. package/src/plugins/maintenance/SeedManagementPage.tsx +1 -1
  188. package/src/plugins/maintenance/seed-executor.ts +2 -2
  189. package/src/plugins/maintenance-plugin.ts +474 -2
  190. package/src/plugins/notifications/NotificationsManagementPage.tsx +1 -1
  191. package/src/plugins/notifications/NotificationsStatusWidget.tsx +1 -1
  192. package/src/plugins/parental/ParentalManagementPage.tsx +1 -1
  193. package/src/plugins/parental/ParentalStatusWidget.tsx +1 -1
  194. package/src/plugins/postgres/PostgresManagementPage.tsx +1 -1
  195. package/src/plugins/postgres/PostgresStatusWidget.tsx +1 -1
  196. package/src/plugins/preferences/PreferencesManagementPage.tsx +1 -1
  197. package/src/plugins/preferences/PreferencesStatusWidget.tsx +1 -1
  198. package/src/plugins/profiles/ProfilesManagementPage.tsx +1 -1
  199. package/src/plugins/profiles/ProfilesStatusWidget.tsx +1 -1
  200. package/src/plugins/qwickbrain/QwickbrainManagementPage.tsx +1 -1
  201. package/src/plugins/qwickbrain/QwickbrainStatusWidget.tsx +1 -1
  202. package/src/plugins/rate-limit/RateLimitManagementPage.tsx +1 -1
  203. package/src/plugins/rate-limit/RateLimitStatusWidget.tsx +1 -1
  204. package/src/plugins/subscriptions/SubscriptionsManagementPage.tsx +1 -1
  205. package/src/plugins/subscriptions/SubscriptionsStatusWidget.tsx +1 -1
  206. package/src/plugins/usage/UsageManagementPage.tsx +1 -1
  207. package/src/plugins/usage/UsageStatusWidget.tsx +1 -1
  208. package/src/plugins/users/UsersManagementPage.tsx +1 -1
  209. package/src/plugins/users/UsersStatusWidget.tsx +1 -1
  210. package/ui/src/App.tsx +4 -3
  211. package/ui/src/api/clientBuilder.ts +5 -5
  212. package/ui/src/api/controlPanelApi.ts +19 -19
  213. package/ui/src/components/ControlPanelApp.tsx +5 -4
  214. package/ui/src/dashboard/builtInWidgets.tsx +3 -0
  215. package/ui/src/dashboard/widgets/CMSMaintenanceWidget.tsx +8 -8
  216. package/ui/src/dashboard/widgets/CMSStatusWidget.tsx +2 -2
  217. package/ui/src/dashboard/widgets/CacheMaintenanceWidget.tsx +4 -4
  218. package/ui/src/dashboard/widgets/DatabaseOperationsWidget.tsx +2 -1
  219. package/ui/src/dashboard/widgets/LogsMaintenanceWidget.tsx +6 -6
  220. package/ui/src/dashboard/widgets/MigrationManagementWidget.tsx +319 -0
  221. package/ui/src/dashboard/widgets/SeedManagementWidget.tsx +6 -6
  222. package/ui/src/dashboard/widgets/index.ts +1 -0
  223. package/ui/src/hooks/useJobStream.ts +2 -2
  224. package/ui/src/pages/ContentOpsJobsPage.tsx +3 -3
  225. package/ui/src/pages/PluginPage.tsx +1 -1
  226. package/ui/src/pages/TenantsManagementPage.tsx +1 -1
@@ -18,15 +18,15 @@ export interface RouteManifestEntry {
18
18
  /**
19
19
  * Build typed API client from server manifest
20
20
  *
21
- * Fetches the manifest from /api/client-manifest and generates a nested
21
+ * Fetches the manifest from /client-manifest (baseUrl already includes /qapi) and generates a nested
22
22
  * client object with methods for each route.
23
23
  *
24
- * @param baseUrl - Base URL of the server (e.g., 'http://localhost:3000')
24
+ * @param baseUrl - Base URL for QwickApps Server APIs (e.g., '/qapi' or 'http://localhost:3000/qapi')
25
25
  * @returns Promise resolving to the generated client
26
26
  *
27
27
  * @example
28
28
  * ```typescript
29
- * const client = await buildClientFromManifest<APIClient>('http://localhost:3000');
29
+ * const client = await buildClientFromManifest<APIClient>('/qapi');
30
30
  * const logs = await client.logs.query({ limit: 10 });
31
31
  * ```
32
32
  */
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Migration Management Widget
3
+ *
4
+ * Allows executing Payload CMS database migrations from the control panel.
5
+ * Part of the maintenance plugin.
6
+ */
7
+ export declare function MigrationManagementWidget(): import("react/jsx-runtime").JSX.Element;
@@ -10,6 +10,7 @@ export { NotificationsStatsWidget } from './NotificationsStatsWidget';
10
10
  export { CMSStatusWidget } from './CMSStatusWidget';
11
11
  export { CMSMaintenanceWidget } from './CMSMaintenanceWidget';
12
12
  export { SeedManagementWidget } from './SeedManagementWidget';
13
+ export { MigrationManagementWidget } from './MigrationManagementWidget';
13
14
  export { ServiceControlWidget } from './ServiceControlWidget';
14
15
  export { EnvironmentConfigWidget } from './EnvironmentConfigWidget';
15
16
  export { DatabaseOpsWidget } from './DatabaseOpsWidget';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qwickapps/server",
3
- "version": "1.8.1",
3
+ "version": "1.8.2",
4
4
  "description": "Plugin-based application server framework for building websites, APIs, admin dashboards, and full-stack products",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -29,29 +29,6 @@
29
29
  "ui",
30
30
  "CHANGELOG.md"
31
31
  ],
32
- "scripts": {
33
- "build": "npm run build:ui-lib && npm run build:server && npm run build:ui",
34
- "build:server": "tsc",
35
- "build:ui": "cd ui && vite build",
36
- "build:ui-lib": "cd ui && vite build --config vite.lib.config.ts && tsc -p tsconfig.lib.json",
37
- "build:clean": "rm -rf dist dist-ui dist-ui-lib && npm run build",
38
- "dev": "tsc --watch",
39
- "dev:ui": "cd ui && vite",
40
- "clean": "rm -rf dist dist-ui dist-ui-lib node_modules",
41
- "test": "vitest run",
42
- "test:watch": "vitest",
43
- "test:coverage": "vitest run --coverage",
44
- "test:e2e": "playwright test",
45
- "test:e2e:ui": "playwright test --ui",
46
- "test:e2e:headed": "playwright test --headed",
47
- "demo": "npm run build:server && pnpm tsx examples/demo-server.ts",
48
- "demo:gateway": "npm run build:server && pnpm tsx examples/demo-gateway.ts",
49
- "demo:all": "npm run build:server && pnpm tsx examples/demo-all.ts",
50
- "type-check": "tsc --noEmit",
51
- "type-check:ui": "cd ui && tsc --noEmit",
52
- "validate:clean-install": "./qa/clean-install/validate.sh",
53
- "prepublishOnly": "npm run test && npm run build && npm run validate:clean-install"
54
- },
55
32
  "dependencies": {
56
33
  "@qwickapps/logging": "^1.0.2",
57
34
  "compression": "^1.7.4",
@@ -59,6 +36,8 @@
59
36
  "express": "^4.18.2",
60
37
  "helmet": "^7.1.0",
61
38
  "http-proxy-middleware": "^3.0.3",
39
+ "prop-types": "^15.8.1",
40
+ "react-is": "^18.2.0",
62
41
  "zod": "^3.22.4"
63
42
  },
64
43
  "devDependencies": {
@@ -90,7 +69,7 @@
90
69
  "react": "^18.2.0",
91
70
  "react-dom": "^18.2.0",
92
71
  "react-router-dom": "^6.30.1",
93
- "supertokens-node": "^20.1.7",
72
+ "supertokens-node": "^18.0.0",
94
73
  "tsx": "^4.20.6",
95
74
  "typescript": "^5.3.3",
96
75
  "vite": "^6.0.0",
@@ -141,5 +120,27 @@
141
120
  "homepage": "https://github.com/qwickapps/server#readme",
142
121
  "publishConfig": {
143
122
  "access": "public"
123
+ },
124
+ "scripts": {
125
+ "build": "npm run build:ui-lib && npm run build:server && npm run build:ui",
126
+ "build:server": "tsc",
127
+ "build:ui": "cd ui && vite build",
128
+ "build:ui-lib": "cd ui && vite build --config vite.lib.config.ts && tsc -p tsconfig.lib.json",
129
+ "build:clean": "rm -rf dist dist-ui dist-ui-lib && npm run build",
130
+ "dev": "tsc --watch",
131
+ "dev:ui": "cd ui && vite",
132
+ "clean": "rm -rf dist dist-ui dist-ui-lib node_modules",
133
+ "test": "vitest run",
134
+ "test:watch": "vitest",
135
+ "test:coverage": "vitest run --coverage",
136
+ "test:e2e": "playwright test",
137
+ "test:e2e:ui": "playwright test --ui",
138
+ "test:e2e:headed": "playwright test --headed",
139
+ "demo": "npm run build:server && pnpm tsx examples/demo-server.ts",
140
+ "demo:gateway": "npm run build:server && pnpm tsx examples/demo-gateway.ts",
141
+ "demo:all": "npm run build:server && pnpm tsx examples/demo-all.ts",
142
+ "type-check": "tsc --noEmit",
143
+ "type-check:ui": "cd ui && tsc --noEmit",
144
+ "validate:clean-install": "./qa/clean-install/validate.sh"
144
145
  }
145
- }
146
+ }
@@ -200,10 +200,11 @@ export function createControlPanel(options: CreateControlPanelOptions): ControlP
200
200
  next();
201
201
  });
202
202
 
203
- // CRITICAL: System APIs always mount at /api regardless of mountPath
204
- // This ensures consistent API paths across all products
205
- // See: ADR-012-QwickApps-Server-Routing-Architecture
206
- app.use('/api', router);
203
+ // CRITICAL: QwickApps Server APIs always mount at /qapi regardless of mountPath
204
+ // This avoids conflicts with application-level APIs (e.g., Payload CMS uses /api)
205
+ // /qapi = QwickApps framework APIs (SuperTokens, health, postgres, cache, etc.)
206
+ // /api = Application/CMS APIs (Payload, custom app routes)
207
+ app.use('/qapi', router);
207
208
 
208
209
  // Built-in routes
209
210
 
@@ -238,7 +239,7 @@ export function createControlPanel(options: CreateControlPanelOptions): ControlP
238
239
 
239
240
  manifest[key] = {
240
241
  method: route.method.toUpperCase(),
241
- path: `/api${route.path}`,
242
+ path: route.path,
242
243
  auth: route.auth?.required || false,
243
244
  };
244
245
  }
@@ -284,8 +285,10 @@ export function createControlPanel(options: CreateControlPanelOptions): ControlP
284
285
  const effectivePath = forwardedPrefix || mountPath;
285
286
  const normalizedPath = effectivePath === '/' ? '' : effectivePath;
286
287
 
287
- // Inject base path as global variable before other scripts
288
- const basePathScript = `<script>window.__APP_BASE_PATH__="${normalizedPath}";</script>`;
288
+ // Inject base paths as global variables before other scripts
289
+ // __APP_BASE_PATH__: UI mount path for routing (e.g., '/cpanel')
290
+ // __API_BASE_PATH__: Base URL for QwickApps Server APIs (always '/qapi')
291
+ const basePathScript = `<script>window.__APP_BASE_PATH__="${normalizedPath}";window.__API_BASE_PATH__="/qapi";</script>`;
289
292
  let html = indexHtmlTemplate.replace('<head>', `<head>\n ${basePathScript}`);
290
293
 
291
294
  // Rewrite asset paths if mounted at a subpath
@@ -1311,54 +1311,37 @@ export function createGateway(config: GatewayConfig): GatewayInstance {
1311
1311
  );
1312
1312
  }
1313
1313
 
1314
- // 2. Setup control panel proxies (BEFORE server.listen)
1315
- // Control panel runs at / internally with APIs at /api and UI at /
1316
- // We proxy both /api and /cpanel to the control panel
1317
-
1318
- // Proxy control panel APIs at {cpPath}/api
1319
- // IMPORTANT: Express strips the API path prefix before passing to middleware,
1320
- // so we need pathRewrite to reconstruct the full path for the control panel
1321
- const cpApiPath = `${cpPath}/api`;
1322
- const apiProxy = createProxyMiddleware({
1314
+ // 2. Create HTTP server (but don't listen yet - need server object for WS)
1315
+ server = createServer(app);
1316
+
1317
+ // 3. Setup mounted apps WITH QwickApps Server API proxy injected at the right position
1318
+ // QwickApps Server APIs (/qapi/*) need to be registered BEFORE root path proxy
1319
+ // to prevent being caught by frontend catch-all routing
1320
+ const qwickAppsApiProxy = createProxyMiddleware({
1323
1321
  target: `http://localhost:${cpPort}`,
1324
1322
  changeOrigin: true,
1325
- pathRewrite: (path) => `/api${path}`, // Express removed {cpPath}/api, add back just /api (control panel APIs are at /api/*)
1326
1323
  on: {
1327
1324
  proxyReq: (proxyReq, req) => {
1328
- // Set X-Forwarded-Prefix so control panel knows its public mount path
1329
- proxyReq.setHeader('X-Forwarded-Prefix', cpPath);
1330
- logger.debug(`[API Proxy] Forwarding ${req.method} ${req.url} to control panel`);
1325
+ logger.debug(`[QwickApps API] Forwarding ${req.method} ${req.url} to QwickApps Server`);
1331
1326
  },
1332
1327
  proxyRes: (proxyRes, req) => {
1333
- logger.debug(`[API Proxy] Response for ${req.url}: ${proxyRes.statusCode} ${proxyRes.headers['content-type']}`);
1328
+ logger.debug(`[QwickApps API] Response for ${req.url}: ${proxyRes.statusCode}`);
1334
1329
  },
1335
1330
  error: (err: Error, req: IncomingMessage, res: ServerResponse | Socket) => {
1336
- logger.error(`[API Proxy] Error for ${req.url}`, { error: err.message });
1331
+ logger.error(`[QwickApps API] Error for ${req.url}`, { error: err.message });
1337
1332
  if (res && 'writeHead' in res && !res.headersSent) {
1338
1333
  res.writeHead(503, { 'Content-Type': 'application/json' });
1339
1334
  res.end(JSON.stringify({
1340
1335
  error: 'Service Unavailable',
1341
- message: 'The control panel API is currently unavailable.',
1336
+ message: 'QwickApps Server APIs are currently unavailable.',
1342
1337
  details: nodeEnv === 'development' ? err.message : undefined,
1343
1338
  }));
1344
1339
  }
1345
1340
  },
1346
1341
  },
1347
1342
  });
1348
- app.use(cpApiPath, apiProxy);
1349
- logger.debug(`Setting up proxy: ${cpApiPath} -> http://localhost:${cpPort}/api`);
1350
- mountedApps.push({ path: cpApiPath, type: 'proxy', target: `http://localhost:${cpPort}` });
1351
- }
1352
-
1353
- // 3. Create HTTP server (but don't listen yet - need server object for WS)
1354
- server = createServer(app);
1355
1343
 
1356
- // 4. Setup control panel UI proxy (needs server for WebSocket handling)
1357
- if (cpEnabled) {
1358
- const cpPort = parseInt(process.env.CPANEL_PORT || String(gatewayPort + 1), 10);
1359
-
1360
- // Proxy /cpanel to control panel UI
1361
- // Express strips cpPath prefix, so we need custom proxy to add it back
1344
+ // Create control panel UI proxy (will be registered before root proxy)
1362
1345
  const cpUiProxy = createProxyMiddleware({
1363
1346
  target: `http://localhost:${cpPort}`,
1364
1347
  changeOrigin: true,
@@ -1378,23 +1361,46 @@ export function createGateway(config: GatewayConfig): GatewayInstance {
1378
1361
  },
1379
1362
  },
1380
1363
  });
1381
- app.use(cpPath, cpUiProxy);
1382
1364
 
1383
- // WebSocket upgrade handling for control panel
1384
- server!.on('upgrade', (req: IncomingMessage, socket: Duplex, head: Buffer) => {
1385
- if (req.url?.startsWith(cpPath)) {
1386
- cpUiProxy.upgrade?.(req, socket as Socket, head);
1365
+ const apps = config.apps || [];
1366
+ for (const appConfig of apps) {
1367
+ // IMPORTANT: Insert QwickApps Server and Control Panel proxies BEFORE root path proxy
1368
+ // This ensures /qapi/* and /cpanel requests don't get caught by frontend catch-all routing
1369
+ if (appConfig.path === '/') {
1370
+ // 1. Register QwickApps Server API proxy at /qapi/* BEFORE the root proxy
1371
+ // These are framework APIs: SuperTokens auth, health checks, postgres, cache, etc.
1372
+ // Payload CMS uses natural Next.js /api/* path
1373
+ app.use((req, res, next) => {
1374
+ if (req.path.startsWith('/qapi/')) {
1375
+ return qwickAppsApiProxy(req, res, next);
1376
+ }
1377
+ next();
1378
+ });
1379
+ logger.debug(`Setting up proxy: /qapi/* -> http://localhost:${cpPort} (QwickApps Server APIs)`);
1380
+ mountedApps.push({ path: '/qapi', type: 'proxy', target: `http://localhost:${cpPort}` });
1381
+
1382
+ // 2. Register Control Panel UI proxy BEFORE the root proxy
1383
+ app.use(cpPath, cpUiProxy);
1384
+ mountedApps.push({ path: cpPath, type: 'proxy', target: `http://localhost:${cpPort}` });
1385
+
1386
+ // 3. Setup WebSocket upgrade handling for control panel UI
1387
+ server!.on('upgrade', (req: IncomingMessage, socket: Duplex, head: Buffer) => {
1388
+ if (req.url?.startsWith(cpPath)) {
1389
+ cpUiProxy.upgrade?.(req, socket as Socket, head);
1390
+ }
1391
+ });
1387
1392
  }
1388
- });
1389
1393
 
1390
- mountedApps.push({ path: cpPath, type: 'proxy', target: `http://localhost:${cpPort}` });
1394
+ // Now register the app itself
1395
+ if (appConfig.source.type === 'proxy') {
1396
+ setupProxyApp(appConfig, server);
1397
+ } else {
1398
+ setupStaticApp(appConfig);
1399
+ }
1400
+ }
1391
1401
  }
1392
1402
 
1393
- // 5. Setup mounted apps (proxy and static)
1394
- const apps = config.apps || [];
1395
-
1396
- // If plugins need maintenance, add root-level maintenance page
1397
- // but keep /cpanel and /diagnostics accessible
1403
+ // 6. Add maintenance page if needed (after all proxies are set up)
1398
1404
  if (cpEnabled) {
1399
1405
  const pluginsNeedingMaintenance = controlPanelInstance!.getPluginRegistry().getPluginsNeedingMaintenance();
1400
1406
  if (pluginsNeedingMaintenance.length > 0) {
@@ -1429,16 +1435,7 @@ export function createGateway(config: GatewayConfig): GatewayInstance {
1429
1435
  }
1430
1436
  }
1431
1437
 
1432
- // Setup additional apps
1433
- for (const appConfig of apps) {
1434
- if (appConfig.source.type === 'proxy') {
1435
- setupProxyApp(appConfig, server);
1436
- } else {
1437
- setupStaticApp(appConfig);
1438
- }
1439
- }
1440
-
1441
- // 6. Setup frontend app at root
1438
+ // 7. Setup frontend app at root
1442
1439
  setupFrontendApp();
1443
1440
 
1444
1441
  // 7. Start listening (LAST STEP - after all middleware is registered)
@@ -24,7 +24,7 @@ interface ApiKey {
24
24
  usageCount: number;
25
25
  }
26
26
 
27
- export function ApiKeysManagementPage({ apiPrefix = '/api/api-keys' }: ApiKeysManagementPageProps) {
27
+ export function ApiKeysManagementPage({ apiPrefix = '/qapi/api-keys' }: ApiKeysManagementPageProps) {
28
28
  const [activeTab, setActiveTab] = useState<'all' | 'active' | 'expired' | 'config'>('all');
29
29
  const [keys, setKeys] = useState<ApiKey[]>([]);
30
30
  const [loading, setLoading] = useState(true);
@@ -10,7 +10,7 @@ export interface ApiKeysStatusWidgetProps {
10
10
  apiPrefix?: string;
11
11
  }
12
12
 
13
- export function ApiKeysStatusWidget({ apiPrefix = '/api/api-keys' }: ApiKeysStatusWidgetProps) {
13
+ export function ApiKeysStatusWidget({ apiPrefix = '/qapi/api-keys' }: ApiKeysStatusWidgetProps) {
14
14
  const [stats, setStats] = useState<{
15
15
  totalKeys: number;
16
16
  activeKeys: number;
@@ -30,7 +30,7 @@ interface AuthSession {
30
30
  ipAddress?: string;
31
31
  }
32
32
 
33
- export function AuthManagementPage({ apiPrefix = '/api/auth' }: AuthManagementPageProps) {
33
+ export function AuthManagementPage({ apiPrefix = '/qapi/auth' }: AuthManagementPageProps) {
34
34
  const [activeTab, setActiveTab] = useState<'overview' | 'providers' | 'sessions' | 'config'>('overview');
35
35
  const [providers, setProviders] = useState<AuthProvider[]>([]);
36
36
  const [sessions, setSessions] = useState<AuthSession[]>([]);
@@ -10,7 +10,7 @@ export interface AuthStatusWidgetProps {
10
10
  apiPrefix?: string;
11
11
  }
12
12
 
13
- export function AuthStatusWidget({ apiPrefix = '/api/auth' }: AuthStatusWidgetProps) {
13
+ export function AuthStatusWidget({ apiPrefix = '/qapi/auth' }: AuthStatusWidgetProps) {
14
14
  const [stats, setStats] = useState<{
15
15
  totalProviders: number;
16
16
  activeProviders: number;
@@ -73,6 +73,15 @@ export function createAuthPlugin(config: AuthPluginConfig): Plugin {
73
73
  }
74
74
  }
75
75
 
76
+ // Register SuperTokens middleware on router for /auth/* paths
77
+ // This ensures Gateway forwards ALL /api/auth/* requests to control panel
78
+ // where SuperTokens can handle them dynamically
79
+ if (Array.isArray(primaryMiddleware)) {
80
+ router.use('/auth', ...primaryMiddleware);
81
+ } else {
82
+ router.use('/auth', primaryMiddleware);
83
+ }
84
+
76
85
  // Add the auth checking middleware to router (not app)
77
86
  // This ensures it processes requests to /api/* routes
78
87
  router.use(createAuthMiddleware());
@@ -23,7 +23,7 @@ interface Ban {
23
23
  createdBy?: string;
24
24
  }
25
25
 
26
- export function BansManagementPage({ apiPrefix = '/api/bans' }: BansManagementPageProps) {
26
+ export function BansManagementPage({ apiPrefix = '/qapi/bans' }: BansManagementPageProps) {
27
27
  const [activeTab, setActiveTab] = useState<'all' | 'active' | 'expired' | 'config'>('all');
28
28
  const [bans, setBans] = useState<Ban[]>([]);
29
29
  const [loading, setLoading] = useState(true);
@@ -10,7 +10,7 @@ export interface BansStatusWidgetProps {
10
10
  apiPrefix?: string;
11
11
  }
12
12
 
13
- export function BansStatusWidget({ apiPrefix = '/api/bans' }: BansStatusWidgetProps) {
13
+ export function BansStatusWidget({ apiPrefix = '/qapi/bans' }: BansStatusWidgetProps) {
14
14
  const [stats, setStats] = useState<{
15
15
  totalBans: number;
16
16
  activeBans: number;
@@ -32,7 +32,7 @@ interface CacheInfo {
32
32
  }
33
33
 
34
34
  export const CacheManagementPage: React.FC<CacheManagementPageProps> = ({
35
- apiPrefix = '/api/plugins/cache',
35
+ apiPrefix = '/qapi/plugins/cache',
36
36
  }) => {
37
37
  const [keys, setKeys] = useState<CacheKey[]>([]);
38
38
  const [info, setInfo] = useState<CacheInfo | null>(null);
@@ -26,7 +26,7 @@ interface CacheStats {
26
26
  }
27
27
 
28
28
  export const CacheStatusWidget: React.FC<CacheStatusWidgetProps> = ({
29
- apiPrefix = '/api/plugins/cache',
29
+ apiPrefix = '/qapi/plugins/cache',
30
30
  }) => {
31
31
  const [stats, setStats] = useState<CacheStats | null>(null);
32
32
  const [loading, setLoading] = useState(true);
@@ -23,7 +23,7 @@ interface Device {
23
23
  lastActiveAt?: string;
24
24
  }
25
25
 
26
- export function DevicesManagementPage({ apiPrefix = '/api/devices' }: DevicesManagementPageProps) {
26
+ export function DevicesManagementPage({ apiPrefix = '/qapi/devices' }: DevicesManagementPageProps) {
27
27
  const [activeTab, setActiveTab] = useState<'all' | 'active' | 'pending' | 'config'>('all');
28
28
  const [devices, setDevices] = useState<Device[]>([]);
29
29
  const [loading, setLoading] = useState(true);
@@ -10,7 +10,7 @@ export interface DevicesStatusWidgetProps {
10
10
  apiPrefix?: string;
11
11
  }
12
12
 
13
- export function DevicesStatusWidget({ apiPrefix = '/api/devices' }: DevicesStatusWidgetProps) {
13
+ export function DevicesStatusWidget({ apiPrefix = '/qapi/devices' }: DevicesStatusWidgetProps) {
14
14
  const [stats, setStats] = useState<{
15
15
  totalDevices: number;
16
16
  activeDevices: number;
@@ -38,7 +38,7 @@ interface DiagnosticsReport {
38
38
  }
39
39
 
40
40
  export const DiagnosticsManagementPage: React.FC<DiagnosticsManagementPageProps> = ({
41
- apiPrefix = '/api/plugins/diagnostics',
41
+ apiPrefix = '/qapi/plugins/diagnostics',
42
42
  }) => {
43
43
  const [report, setReport] = useState<DiagnosticsReport | null>(null);
44
44
  const [loading, setLoading] = useState(true);
@@ -26,7 +26,7 @@ interface DiagnosticsStats {
26
26
  }
27
27
 
28
28
  export const DiagnosticsStatusWidget: React.FC<DiagnosticsStatusWidgetProps> = ({
29
- apiPrefix = '/api/plugins/diagnostics',
29
+ apiPrefix = '/qapi/plugins/diagnostics',
30
30
  }) => {
31
31
  const [stats, setStats] = useState<DiagnosticsStats | null>(null);
32
32
  const [loading, setLoading] = useState(true);
@@ -22,7 +22,7 @@ interface Entitlement {
22
22
  grantedBy?: string;
23
23
  }
24
24
 
25
- export function EntitlementsManagementPage({ apiPrefix = '/api/entitlements' }: EntitlementsManagementPageProps) {
25
+ export function EntitlementsManagementPage({ apiPrefix = '/qapi/entitlements' }: EntitlementsManagementPageProps) {
26
26
  const [activeTab, setActiveTab] = useState<'all' | 'active' | 'expired' | 'config'>('all');
27
27
  const [entitlements, setEntitlements] = useState<Entitlement[]>([]);
28
28
  const [loading, setLoading] = useState(true);
@@ -10,7 +10,7 @@ export interface EntitlementsStatusWidgetProps {
10
10
  apiPrefix?: string;
11
11
  }
12
12
 
13
- export function EntitlementsStatusWidget({ apiPrefix = '/api/entitlements' }: EntitlementsStatusWidgetProps) {
13
+ export function EntitlementsStatusWidget({ apiPrefix = '/qapi/entitlements' }: EntitlementsStatusWidgetProps) {
14
14
  const [stats, setStats] = useState<{
15
15
  totalEntitlements: number;
16
16
  activeEntitlements: number;
@@ -33,7 +33,7 @@ interface HealthSummary {
33
33
  }
34
34
 
35
35
  export const HealthManagementPage: React.FC<HealthManagementPageProps> = ({
36
- apiPrefix = '/api/plugins/health',
36
+ apiPrefix = '/qapi/plugins/health',
37
37
  }) => {
38
38
  const [summary, setSummary] = useState<HealthSummary | null>(null);
39
39
  const [selectedCheck, setSelectedCheck] = useState<HealthCheckResult | null>(null);
@@ -33,7 +33,7 @@ interface HealthSummary {
33
33
  }
34
34
 
35
35
  export const HealthStatusWidget: React.FC<HealthStatusWidgetProps> = ({
36
- apiPrefix = '/api/plugins/health',
36
+ apiPrefix = '/qapi/plugins/health',
37
37
  }) => {
38
38
  const [summary, setSummary] = useState<HealthSummary | null>(null);
39
39
  const [loading, setLoading] = useState(true);
@@ -42,7 +42,7 @@ interface LogStats {
42
42
  }
43
43
 
44
44
  export const LogsManagementPage: React.FC<LogsManagementPageProps> = ({
45
- apiPrefix = '/api/plugins/logs',
45
+ apiPrefix = '/qapi/plugins/logs',
46
46
  }) => {
47
47
  const [logs, setLogs] = useState<LogEntry[]>([]);
48
48
  const [sources, setSources] = useState<LogSource[]>([]);
@@ -28,7 +28,7 @@ interface LogStats {
28
28
  }
29
29
 
30
30
  export const LogsStatusWidget: React.FC<LogsStatusWidgetProps> = ({
31
- apiPrefix = '/api/plugins/logs',
31
+ apiPrefix = '/qapi/plugins/logs',
32
32
  }) => {
33
33
  const [stats, setStats] = useState<LogStats | null>(null);
34
34
  const [loading, setLoading] = useState(true);
@@ -30,7 +30,7 @@ interface MaintenanceStatus {
30
30
  }
31
31
 
32
32
  export const MaintenanceManagementPage: React.FC<MaintenanceManagementPageProps> = ({
33
- apiPrefix = '/api/plugins/maintenance',
33
+ apiPrefix = '/qapi/plugins/maintenance',
34
34
  }) => {
35
35
  const [status, setStatus] = useState<MaintenanceStatus | null>(null);
36
36
  const [loading, setLoading] = useState(true);
@@ -26,7 +26,7 @@ interface MaintenanceStatus {
26
26
  }
27
27
 
28
28
  export const MaintenanceStatusWidget: React.FC<MaintenanceStatusWidgetProps> = ({
29
- apiPrefix = '/api/plugins/maintenance',
29
+ apiPrefix = '/qapi/plugins/maintenance',
30
30
  }) => {
31
31
  const [status, setStatus] = useState<MaintenanceStatus | null>(null);
32
32
  const [loading, setLoading] = useState(true);
@@ -19,7 +19,7 @@ export interface SeedManagementPageProps {
19
19
  type Tab = 'list' | 'execute' | 'history';
20
20
 
21
21
  export const SeedManagementPage: React.FC<SeedManagementPageProps> = ({
22
- apiPrefix = '/api/plugins/maintenance',
22
+ apiPrefix = '/qapi/plugins/maintenance',
23
23
  }) => {
24
24
  const [activeTab, setActiveTab] = useState<Tab>('list');
25
25
  const [selectedSeed, setSelectedSeed] = useState<string | null>(null);
@@ -45,8 +45,8 @@ const MAX_OUTPUT_SIZE = 100 * 1024;
45
45
  * @returns Resolved absolute path if valid, null if invalid
46
46
  */
47
47
  export function validateScriptPath(scriptPath: string, scriptsPath: string): string | null {
48
- // Only allow .mjs files
49
- if (!scriptPath.endsWith('.mjs')) {
48
+ // Only allow .mjs and .ts files
49
+ if (!scriptPath.endsWith('.mjs') && !scriptPath.endsWith('.ts')) {
50
50
  return null;
51
51
  }
52
52