@qwickapps/server 1.3.0 → 1.4.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.
Files changed (241) hide show
  1. package/README.md +311 -0
  2. package/dist/core/control-panel.d.ts.map +1 -1
  3. package/dist/core/control-panel.js +144 -2
  4. package/dist/core/control-panel.js.map +1 -1
  5. package/dist/core/plugin-registry.d.ts +36 -0
  6. package/dist/core/plugin-registry.d.ts.map +1 -1
  7. package/dist/core/plugin-registry.js +26 -0
  8. package/dist/core/plugin-registry.js.map +1 -1
  9. package/dist/core/types.d.ts +19 -0
  10. package/dist/core/types.d.ts.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +4 -2
  14. package/dist/index.js.map +1 -1
  15. package/dist/plugins/auth/adapter-wrapper.d.ts +47 -0
  16. package/dist/plugins/auth/adapter-wrapper.d.ts.map +1 -0
  17. package/dist/plugins/auth/adapter-wrapper.js +166 -0
  18. package/dist/plugins/auth/adapter-wrapper.js.map +1 -0
  19. package/dist/plugins/auth/adapter-wrapper.test.d.ts +7 -0
  20. package/dist/plugins/auth/adapter-wrapper.test.d.ts.map +1 -0
  21. package/dist/plugins/auth/adapter-wrapper.test.js +303 -0
  22. package/dist/plugins/auth/adapter-wrapper.test.js.map +1 -0
  23. package/dist/plugins/auth/adapters/index.d.ts +1 -0
  24. package/dist/plugins/auth/adapters/index.d.ts.map +1 -1
  25. package/dist/plugins/auth/adapters/index.js +1 -0
  26. package/dist/plugins/auth/adapters/index.js.map +1 -1
  27. package/dist/plugins/auth/adapters/supabase-adapter.d.ts.map +1 -1
  28. package/dist/plugins/auth/adapters/supabase-adapter.js.map +1 -1
  29. package/dist/plugins/auth/adapters/supertokens-adapter.d.ts +18 -0
  30. package/dist/plugins/auth/adapters/supertokens-adapter.d.ts.map +1 -0
  31. package/dist/plugins/auth/adapters/supertokens-adapter.js +267 -0
  32. package/dist/plugins/auth/adapters/supertokens-adapter.js.map +1 -0
  33. package/dist/plugins/auth/config-store.d.ts +11 -0
  34. package/dist/plugins/auth/config-store.d.ts.map +1 -0
  35. package/dist/plugins/auth/config-store.js +232 -0
  36. package/dist/plugins/auth/config-store.js.map +1 -0
  37. package/dist/plugins/auth/config-store.test.d.ts +7 -0
  38. package/dist/plugins/auth/config-store.test.d.ts.map +1 -0
  39. package/dist/plugins/auth/config-store.test.js +299 -0
  40. package/dist/plugins/auth/config-store.test.js.map +1 -0
  41. package/dist/plugins/auth/env-config.d.ts +138 -0
  42. package/dist/plugins/auth/env-config.d.ts.map +1 -0
  43. package/dist/plugins/auth/env-config.js +1122 -0
  44. package/dist/plugins/auth/env-config.js.map +1 -0
  45. package/dist/plugins/auth/index.d.ts +7 -1
  46. package/dist/plugins/auth/index.d.ts.map +1 -1
  47. package/dist/plugins/auth/index.js +7 -0
  48. package/dist/plugins/auth/index.js.map +1 -1
  49. package/dist/plugins/auth/supertokens-adapter.test.d.ts +10 -0
  50. package/dist/plugins/auth/supertokens-adapter.test.d.ts.map +1 -0
  51. package/dist/plugins/auth/supertokens-adapter.test.js +486 -0
  52. package/dist/plugins/auth/supertokens-adapter.test.js.map +1 -0
  53. package/dist/plugins/auth/types.d.ts +176 -0
  54. package/dist/plugins/auth/types.d.ts.map +1 -1
  55. package/dist/plugins/auth/types.js.map +1 -1
  56. package/dist/plugins/cache-plugin.test.js +3 -0
  57. package/dist/plugins/cache-plugin.test.js.map +1 -1
  58. package/dist/plugins/index.d.ts +6 -2
  59. package/dist/plugins/index.d.ts.map +1 -1
  60. package/dist/plugins/index.js +5 -1
  61. package/dist/plugins/index.js.map +1 -1
  62. package/dist/plugins/postgres-plugin.test.js +3 -0
  63. package/dist/plugins/postgres-plugin.test.js.map +1 -1
  64. package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts +7 -0
  65. package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts.map +1 -0
  66. package/dist/plugins/preferences/__tests__/deep-merge.test.js +215 -0
  67. package/dist/plugins/preferences/__tests__/deep-merge.test.js.map +1 -0
  68. package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts +7 -0
  69. package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts.map +1 -0
  70. package/dist/plugins/preferences/__tests__/preferences-plugin.test.js +265 -0
  71. package/dist/plugins/preferences/__tests__/preferences-plugin.test.js.map +1 -0
  72. package/dist/plugins/preferences/index.d.ts +12 -0
  73. package/dist/plugins/preferences/index.d.ts.map +1 -0
  74. package/dist/plugins/preferences/index.js +13 -0
  75. package/dist/plugins/preferences/index.js.map +1 -0
  76. package/dist/plugins/preferences/preferences-plugin.d.ts +39 -0
  77. package/dist/plugins/preferences/preferences-plugin.d.ts.map +1 -0
  78. package/dist/plugins/preferences/preferences-plugin.js +226 -0
  79. package/dist/plugins/preferences/preferences-plugin.js.map +1 -0
  80. package/dist/plugins/preferences/stores/index.d.ts +9 -0
  81. package/dist/plugins/preferences/stores/index.d.ts.map +1 -0
  82. package/dist/plugins/preferences/stores/index.js +9 -0
  83. package/dist/plugins/preferences/stores/index.js.map +1 -0
  84. package/dist/plugins/preferences/stores/postgres-store.d.ts +41 -0
  85. package/dist/plugins/preferences/stores/postgres-store.d.ts.map +1 -0
  86. package/dist/plugins/preferences/stores/postgres-store.js +181 -0
  87. package/dist/plugins/preferences/stores/postgres-store.js.map +1 -0
  88. package/dist/plugins/preferences/types.d.ts +91 -0
  89. package/dist/plugins/preferences/types.d.ts.map +1 -0
  90. package/dist/plugins/preferences/types.js +10 -0
  91. package/dist/plugins/preferences/types.js.map +1 -0
  92. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts +7 -0
  93. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts.map +1 -0
  94. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js +220 -0
  95. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js.map +1 -0
  96. package/dist/plugins/rate-limit/cleanup.d.ts +40 -0
  97. package/dist/plugins/rate-limit/cleanup.d.ts.map +1 -0
  98. package/dist/plugins/rate-limit/cleanup.js +72 -0
  99. package/dist/plugins/rate-limit/cleanup.js.map +1 -0
  100. package/dist/plugins/rate-limit/env-config.d.ts +91 -0
  101. package/dist/plugins/rate-limit/env-config.d.ts.map +1 -0
  102. package/dist/plugins/rate-limit/env-config.js +318 -0
  103. package/dist/plugins/rate-limit/env-config.js.map +1 -0
  104. package/dist/plugins/rate-limit/index.d.ts +76 -0
  105. package/dist/plugins/rate-limit/index.d.ts.map +1 -0
  106. package/dist/plugins/rate-limit/index.js +79 -0
  107. package/dist/plugins/rate-limit/index.js.map +1 -0
  108. package/dist/plugins/rate-limit/middleware.d.ts +40 -0
  109. package/dist/plugins/rate-limit/middleware.d.ts.map +1 -0
  110. package/dist/plugins/rate-limit/middleware.js +169 -0
  111. package/dist/plugins/rate-limit/middleware.js.map +1 -0
  112. package/dist/plugins/rate-limit/rate-limit-plugin.d.ts +44 -0
  113. package/dist/plugins/rate-limit/rate-limit-plugin.d.ts.map +1 -0
  114. package/dist/plugins/rate-limit/rate-limit-plugin.js +354 -0
  115. package/dist/plugins/rate-limit/rate-limit-plugin.js.map +1 -0
  116. package/dist/plugins/rate-limit/rate-limit-service.d.ts +110 -0
  117. package/dist/plugins/rate-limit/rate-limit-service.d.ts.map +1 -0
  118. package/dist/plugins/rate-limit/rate-limit-service.js +172 -0
  119. package/dist/plugins/rate-limit/rate-limit-service.js.map +1 -0
  120. package/dist/plugins/rate-limit/stores/cache-store.d.ts +33 -0
  121. package/dist/plugins/rate-limit/stores/cache-store.d.ts.map +1 -0
  122. package/dist/plugins/rate-limit/stores/cache-store.js +225 -0
  123. package/dist/plugins/rate-limit/stores/cache-store.js.map +1 -0
  124. package/dist/plugins/rate-limit/stores/index.d.ts +8 -0
  125. package/dist/plugins/rate-limit/stores/index.d.ts.map +1 -0
  126. package/dist/plugins/rate-limit/stores/index.js +8 -0
  127. package/dist/plugins/rate-limit/stores/index.js.map +1 -0
  128. package/dist/plugins/rate-limit/stores/postgres-store.d.ts +34 -0
  129. package/dist/plugins/rate-limit/stores/postgres-store.d.ts.map +1 -0
  130. package/dist/plugins/rate-limit/stores/postgres-store.js +320 -0
  131. package/dist/plugins/rate-limit/stores/postgres-store.js.map +1 -0
  132. package/dist/plugins/rate-limit/strategies/fixed-window.d.ts +21 -0
  133. package/dist/plugins/rate-limit/strategies/fixed-window.d.ts.map +1 -0
  134. package/dist/plugins/rate-limit/strategies/fixed-window.js +97 -0
  135. package/dist/plugins/rate-limit/strategies/fixed-window.js.map +1 -0
  136. package/dist/plugins/rate-limit/strategies/index.d.ts +14 -0
  137. package/dist/plugins/rate-limit/strategies/index.d.ts.map +1 -0
  138. package/dist/plugins/rate-limit/strategies/index.js +27 -0
  139. package/dist/plugins/rate-limit/strategies/index.js.map +1 -0
  140. package/dist/plugins/rate-limit/strategies/sliding-window.d.ts +22 -0
  141. package/dist/plugins/rate-limit/strategies/sliding-window.d.ts.map +1 -0
  142. package/dist/plugins/rate-limit/strategies/sliding-window.js +122 -0
  143. package/dist/plugins/rate-limit/strategies/sliding-window.js.map +1 -0
  144. package/dist/plugins/rate-limit/strategies/token-bucket.d.ts +28 -0
  145. package/dist/plugins/rate-limit/strategies/token-bucket.d.ts.map +1 -0
  146. package/dist/plugins/rate-limit/strategies/token-bucket.js +121 -0
  147. package/dist/plugins/rate-limit/strategies/token-bucket.js.map +1 -0
  148. package/dist/plugins/rate-limit/types.d.ts +265 -0
  149. package/dist/plugins/rate-limit/types.d.ts.map +1 -0
  150. package/dist/plugins/rate-limit/types.js +9 -0
  151. package/dist/plugins/rate-limit/types.js.map +1 -0
  152. package/dist/plugins/users/__tests__/users-plugin.test.d.ts +9 -0
  153. package/dist/plugins/users/__tests__/users-plugin.test.d.ts.map +1 -0
  154. package/dist/plugins/users/__tests__/users-plugin.test.js +546 -0
  155. package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -0
  156. package/dist/plugins/users/index.d.ts +2 -2
  157. package/dist/plugins/users/index.d.ts.map +1 -1
  158. package/dist/plugins/users/index.js +1 -1
  159. package/dist/plugins/users/index.js.map +1 -1
  160. package/dist/plugins/users/types.d.ts +36 -0
  161. package/dist/plugins/users/types.d.ts.map +1 -1
  162. package/dist/plugins/users/users-plugin.d.ts +8 -2
  163. package/dist/plugins/users/users-plugin.d.ts.map +1 -1
  164. package/dist/plugins/users/users-plugin.js +122 -5
  165. package/dist/plugins/users/users-plugin.js.map +1 -1
  166. package/dist-ui/assets/index-D7DoZ9rL.js +478 -0
  167. package/dist-ui/assets/index-D7DoZ9rL.js.map +1 -0
  168. package/dist-ui/index.html +1 -1
  169. package/dist-ui-lib/api/controlPanelApi.d.ts +194 -7
  170. package/dist-ui-lib/dashboard/WidgetComponentRegistry.d.ts +9 -5
  171. package/dist-ui-lib/dashboard/builtInWidgets.d.ts +7 -1
  172. package/dist-ui-lib/dashboard/widgets/AuthStatusWidget.d.ts +9 -0
  173. package/dist-ui-lib/dashboard/widgets/IntegrationStatusWidget.d.ts +9 -0
  174. package/dist-ui-lib/dashboard/widgets/index.d.ts +2 -0
  175. package/dist-ui-lib/index.js +3665 -3945
  176. package/dist-ui-lib/index.js.map +1 -1
  177. package/dist-ui-lib/pages/AuthPage.d.ts +1 -0
  178. package/dist-ui-lib/pages/IntegrationsPage.d.ts +1 -0
  179. package/dist-ui-lib/pages/PluginsPage.d.ts +1 -0
  180. package/dist-ui-lib/pages/RateLimitPage.d.ts +1 -0
  181. package/package.json +7 -2
  182. package/src/core/control-panel.ts +161 -2
  183. package/src/core/plugin-registry.ts +63 -0
  184. package/src/core/types.ts +17 -0
  185. package/src/index.ts +45 -0
  186. package/src/plugins/auth/adapter-wrapper.test.ts +395 -0
  187. package/src/plugins/auth/adapter-wrapper.ts +205 -0
  188. package/src/plugins/auth/adapters/index.ts +1 -0
  189. package/src/plugins/auth/adapters/supabase-adapter.ts +22 -14
  190. package/src/plugins/auth/adapters/supertokens-adapter.ts +326 -0
  191. package/src/plugins/auth/config-store.test.ts +417 -0
  192. package/src/plugins/auth/config-store.ts +305 -0
  193. package/src/plugins/auth/env-config.ts +1279 -0
  194. package/src/plugins/auth/index.ts +30 -0
  195. package/src/plugins/auth/supertokens-adapter.test.ts +621 -0
  196. package/src/plugins/auth/types.ts +218 -0
  197. package/src/plugins/cache-plugin.test.ts +3 -0
  198. package/src/plugins/index.ts +75 -0
  199. package/src/plugins/postgres-plugin.test.ts +3 -0
  200. package/src/plugins/preferences/__tests__/deep-merge.test.ts +242 -0
  201. package/src/plugins/preferences/__tests__/preferences-plugin.test.ts +350 -0
  202. package/src/plugins/preferences/index.ts +30 -0
  203. package/src/plugins/preferences/preferences-plugin.ts +270 -0
  204. package/src/plugins/preferences/stores/index.ts +9 -0
  205. package/src/plugins/preferences/stores/postgres-store.ts +252 -0
  206. package/src/plugins/preferences/types.ts +100 -0
  207. package/src/plugins/rate-limit/__tests__/rate-limit-plugin.test.ts +259 -0
  208. package/src/plugins/rate-limit/cleanup.ts +117 -0
  209. package/src/plugins/rate-limit/env-config.ts +400 -0
  210. package/src/plugins/rate-limit/index.ts +128 -0
  211. package/src/plugins/rate-limit/middleware.ts +212 -0
  212. package/src/plugins/rate-limit/rate-limit-plugin.ts +400 -0
  213. package/src/plugins/rate-limit/rate-limit-service.ts +228 -0
  214. package/src/plugins/rate-limit/stores/cache-store.ts +261 -0
  215. package/src/plugins/rate-limit/stores/index.ts +8 -0
  216. package/src/plugins/rate-limit/stores/postgres-store.ts +402 -0
  217. package/src/plugins/rate-limit/strategies/fixed-window.ts +116 -0
  218. package/src/plugins/rate-limit/strategies/index.ts +30 -0
  219. package/src/plugins/rate-limit/strategies/sliding-window.ts +157 -0
  220. package/src/plugins/rate-limit/strategies/token-bucket.ts +154 -0
  221. package/src/plugins/rate-limit/types.ts +338 -0
  222. package/src/plugins/users/__tests__/users-plugin.test.ts +690 -0
  223. package/src/plugins/users/index.ts +3 -0
  224. package/src/plugins/users/types.ts +38 -0
  225. package/src/plugins/users/users-plugin.ts +142 -5
  226. package/ui/src/App.tsx +35 -14
  227. package/ui/src/api/controlPanelApi.ts +326 -1
  228. package/ui/src/components/ControlPanelApp.tsx +3 -0
  229. package/ui/src/dashboard/PluginWidgetRenderer.tsx +13 -10
  230. package/ui/src/dashboard/WidgetComponentRegistry.tsx +13 -9
  231. package/ui/src/dashboard/builtInWidgets.tsx +13 -3
  232. package/ui/src/dashboard/widgets/AuthStatusWidget.tsx +143 -0
  233. package/ui/src/dashboard/widgets/IntegrationStatusWidget.tsx +135 -0
  234. package/ui/src/dashboard/widgets/index.ts +2 -0
  235. package/ui/src/pages/AuthPage.tsx +1103 -0
  236. package/ui/src/pages/IntegrationsPage.tsx +288 -0
  237. package/ui/src/pages/PluginsPage.tsx +394 -0
  238. package/ui/src/pages/RateLimitPage.tsx +292 -0
  239. package/ui/vite.lib.config.ts +5 -0
  240. package/dist-ui/assets/index-Bsp2ntcw.js +0 -465
  241. package/dist-ui/assets/index-Bsp2ntcw.js.map +0 -1
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Supertokens Auth Adapter
3
+ *
4
+ * Provides Supertokens authentication using EmailPassword and ThirdParty recipes.
5
+ * Supports email/password and social logins (Google, Apple, GitHub).
6
+ *
7
+ * Note: Requires supertokens-node v20+
8
+ *
9
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
10
+ */
11
+ // Keys for storing data on the request object
12
+ const REQUEST_USER_KEY = '_supertokensUser';
13
+ const REQUEST_RES_KEY = '_supertokensRes';
14
+ const REQUEST_SESSION_KEY = '_supertokensSession';
15
+ /**
16
+ * Create a Supertokens authentication adapter
17
+ *
18
+ * Uses EmailPassword and ThirdParty recipes (Supertokens v20+)
19
+ */
20
+ export function supertokensAdapter(config) {
21
+ // Track initialization state
22
+ let initialized = false;
23
+ let initializationError = null;
24
+ return {
25
+ name: 'supertokens',
26
+ initialize() {
27
+ // Return middleware that lazily initializes Supertokens
28
+ const initMiddleware = async (req, res, next) => {
29
+ // Store response on request for later use in getUser()
30
+ req[REQUEST_RES_KEY] = res;
31
+ // Skip if already initialized with error
32
+ if (initializationError) {
33
+ return res.status(500).json({
34
+ error: 'Auth Configuration Error',
35
+ message: 'Supertokens is not properly configured. Install supertokens-node package: npm install supertokens-node',
36
+ details: initializationError.message,
37
+ });
38
+ }
39
+ // Lazy initialize Supertokens
40
+ if (!initialized) {
41
+ try {
42
+ const supertokens = await import('supertokens-node');
43
+ const Session = await import('supertokens-node/recipe/session');
44
+ const EmailPassword = await import('supertokens-node/recipe/emailpassword');
45
+ const ThirdParty = await import('supertokens-node/recipe/thirdparty');
46
+ // Build recipe list - using any[] for Supertokens internal types
47
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
+ const recipeList = [];
49
+ // Add EmailPassword recipe if enabled (default: true)
50
+ if (config.enableEmailPassword !== false) {
51
+ recipeList.push(EmailPassword.default.init());
52
+ }
53
+ // Add ThirdParty recipe if any social providers configured
54
+ if (config.socialProviders) {
55
+ // Build provider configurations using Supertokens ProviderInput type
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+ const providers = [];
58
+ if (config.socialProviders.google) {
59
+ providers.push({
60
+ config: {
61
+ thirdPartyId: 'google',
62
+ clients: [
63
+ {
64
+ clientId: config.socialProviders.google.clientId,
65
+ clientSecret: config.socialProviders.google.clientSecret,
66
+ },
67
+ ],
68
+ },
69
+ });
70
+ }
71
+ if (config.socialProviders.apple) {
72
+ // Apple requires keyId, teamId, and privateKey in additionalConfig
73
+ providers.push({
74
+ config: {
75
+ thirdPartyId: 'apple',
76
+ clients: [
77
+ {
78
+ clientId: config.socialProviders.apple.clientId,
79
+ clientSecret: config.socialProviders.apple.clientSecret,
80
+ additionalConfig: {
81
+ keyId: config.socialProviders.apple.keyId,
82
+ teamId: config.socialProviders.apple.teamId,
83
+ },
84
+ },
85
+ ],
86
+ },
87
+ });
88
+ }
89
+ if (config.socialProviders.github) {
90
+ providers.push({
91
+ config: {
92
+ thirdPartyId: 'github',
93
+ clients: [
94
+ {
95
+ clientId: config.socialProviders.github.clientId,
96
+ clientSecret: config.socialProviders.github.clientSecret,
97
+ },
98
+ ],
99
+ },
100
+ });
101
+ }
102
+ if (providers.length > 0) {
103
+ recipeList.push(ThirdParty.default.init({
104
+ signInAndUpFeature: {
105
+ providers,
106
+ },
107
+ }));
108
+ }
109
+ }
110
+ // Always add Session recipe
111
+ recipeList.push(Session.default.init());
112
+ // Initialize Supertokens
113
+ supertokens.default.init({
114
+ framework: 'express',
115
+ supertokens: {
116
+ connectionURI: config.connectionUri,
117
+ apiKey: config.apiKey,
118
+ },
119
+ appInfo: {
120
+ appName: config.appName,
121
+ apiDomain: config.apiDomain,
122
+ websiteDomain: config.websiteDomain,
123
+ apiBasePath: config.apiBasePath ?? '/auth',
124
+ websiteBasePath: config.websiteBasePath ?? '/auth',
125
+ },
126
+ recipeList,
127
+ });
128
+ initialized = true;
129
+ }
130
+ catch (error) {
131
+ initializationError =
132
+ error instanceof Error ? error : new Error('Failed to initialize Supertokens');
133
+ console.error('[SupertokensAdapter] Initialization error:', error);
134
+ return res.status(500).json({
135
+ error: 'Auth Configuration Error',
136
+ message: 'Supertokens is not properly configured. Install supertokens-node package: npm install supertokens-node',
137
+ details: initializationError.message,
138
+ });
139
+ }
140
+ }
141
+ next();
142
+ };
143
+ // Supertokens middleware for handling auth routes
144
+ const supertokensMiddleware = async (req, res, next) => {
145
+ if (!initialized) {
146
+ return next();
147
+ }
148
+ try {
149
+ const { middleware } = await import('supertokens-node/framework/express');
150
+ middleware()(req, res, next);
151
+ }
152
+ catch {
153
+ next();
154
+ }
155
+ };
156
+ return [initMiddleware, supertokensMiddleware];
157
+ },
158
+ isAuthenticated(req) {
159
+ const extReq = req;
160
+ // Check if we already validated this request
161
+ if (extReq[REQUEST_USER_KEY]) {
162
+ return true;
163
+ }
164
+ // Check if session was already retrieved
165
+ if (extReq[REQUEST_SESSION_KEY]) {
166
+ return true;
167
+ }
168
+ // For synchronous check, we can only check if session cookies exist
169
+ // Full validation happens in getUser()
170
+ // Supertokens uses cookies, so we check for session tokens
171
+ const cookies = req.cookies || {};
172
+ const accessToken = cookies.sAccessToken;
173
+ const refreshToken = cookies.sRefreshToken;
174
+ // Also check for Authorization header (for API clients)
175
+ const authHeader = req.headers.authorization;
176
+ const hasBearerToken = authHeader?.startsWith('Bearer ');
177
+ return !!(accessToken || refreshToken || hasBearerToken);
178
+ },
179
+ async getUser(req) {
180
+ const extReq = req;
181
+ // Return cached user if available
182
+ const cachedUser = extReq[REQUEST_USER_KEY];
183
+ if (cachedUser) {
184
+ return cachedUser;
185
+ }
186
+ if (!initialized) {
187
+ return null;
188
+ }
189
+ // Get response object stored during middleware
190
+ const res = extReq[REQUEST_RES_KEY];
191
+ if (!res) {
192
+ console.error('[SupertokensAdapter] Response object not found on request');
193
+ return null;
194
+ }
195
+ try {
196
+ const Session = await import('supertokens-node/recipe/session');
197
+ const supertokens = await import('supertokens-node');
198
+ // Get session - sessionRequired: false means it won't throw if no session
199
+ const session = await Session.default.getSession(req, res, {
200
+ sessionRequired: false,
201
+ });
202
+ if (!session) {
203
+ return null;
204
+ }
205
+ // Cache session for isAuthenticated check
206
+ extReq[REQUEST_SESSION_KEY] = session;
207
+ const userId = session.getUserId();
208
+ // Get user info from Supertokens
209
+ const userInfo = await supertokens.default.getUser(userId);
210
+ if (!userInfo) {
211
+ return null;
212
+ }
213
+ // Get roles from session access token payload if available
214
+ const accessTokenPayload = session.getAccessTokenPayload();
215
+ const roles = accessTokenPayload?.roles || [];
216
+ // Map Supertokens user to AuthenticatedUser
217
+ const user = {
218
+ id: userId,
219
+ email: userInfo.emails?.[0] ?? '',
220
+ name: accessTokenPayload?.name ||
221
+ userInfo.thirdParty?.[0]?.userId ||
222
+ userInfo.emails?.[0]?.split('@')[0],
223
+ picture: accessTokenPayload?.picture,
224
+ emailVerified: userInfo.emails?.[0] ? true : false,
225
+ roles,
226
+ raw: {
227
+ ...userInfo,
228
+ sessionHandle: session.getHandle(),
229
+ accessTokenPayload,
230
+ },
231
+ };
232
+ // Cache on request object
233
+ extReq[REQUEST_USER_KEY] = user;
234
+ return user;
235
+ }
236
+ catch (error) {
237
+ console.error('[SupertokensAdapter] Error getting user:', error);
238
+ return null;
239
+ }
240
+ },
241
+ hasRoles(req, roles) {
242
+ const extReq = req;
243
+ const user = extReq[REQUEST_USER_KEY];
244
+ if (!user?.roles)
245
+ return false;
246
+ return roles.every((role) => user.roles?.includes(role));
247
+ },
248
+ getAccessToken(_req) {
249
+ // Supertokens uses session cookies, not access tokens
250
+ // Return null as per the design decision
251
+ return null;
252
+ },
253
+ onUnauthorized(_req, res) {
254
+ res.status(401).json({
255
+ error: 'Unauthorized',
256
+ message: 'Authentication required. Please sign in.',
257
+ hint: 'Use the /auth endpoints to authenticate',
258
+ });
259
+ },
260
+ async shutdown() {
261
+ // Supertokens doesn't require explicit cleanup
262
+ initialized = false;
263
+ initializationError = null;
264
+ },
265
+ };
266
+ }
267
+ //# sourceMappingURL=supertokens-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supertokens-adapter.js","sourceRoot":"","sources":["../../../../src/plugins/auth/adapters/supertokens-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Auth Configuration Store
3
+ *
4
+ * PostgreSQL-based storage for runtime auth configuration.
5
+ * Supports pg_notify for cross-instance hot-reload in scaled deployments.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+ import type { AuthConfigStore, PostgresAuthConfigStoreConfig } from './types.js';
10
+ export declare function postgresAuthConfigStore(config: PostgresAuthConfigStoreConfig): AuthConfigStore;
11
+ //# sourceMappingURL=config-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../../src/plugins/auth/config-store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,eAAe,EAEf,6BAA6B,EAC9B,MAAM,YAAY,CAAC;AAgDpB,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,6BAA6B,GAAG,eAAe,CAmP9F"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Auth Configuration Store
3
+ *
4
+ * PostgreSQL-based storage for runtime auth configuration.
5
+ * Supports pg_notify for cross-instance hot-reload in scaled deployments.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+ /**
10
+ * Create a PostgreSQL-backed auth configuration store
11
+ *
12
+ * @param config Configuration including a pg Pool instance
13
+ * @returns AuthConfigStore implementation
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Pool } from 'pg';
18
+ * import { postgresAuthConfigStore } from '@qwickapps/server';
19
+ *
20
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
21
+ * const store = postgresAuthConfigStore({ pool });
22
+ *
23
+ * // Or with lazy initialization:
24
+ * const store = postgresAuthConfigStore({ pool: () => getPostgres().getPool() });
25
+ * ```
26
+ */
27
+ // Valid identifier pattern (alphanumeric + underscore, starting with letter or underscore)
28
+ const VALID_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
29
+ /**
30
+ * Validate SQL identifier to prevent SQL injection
31
+ */
32
+ function validateIdentifier(name, type) {
33
+ if (!VALID_IDENTIFIER.test(name)) {
34
+ throw new Error(`Invalid ${type}: must be alphanumeric with underscores, starting with letter or underscore`);
35
+ }
36
+ if (name.length > 63) {
37
+ throw new Error(`Invalid ${type}: must be 63 characters or less`);
38
+ }
39
+ }
40
+ export function postgresAuthConfigStore(config) {
41
+ const { pool: poolOrFn, tableName = 'auth_config', schema = 'public', autoCreateTable = true, enableNotify = true, notifyChannel = 'auth_config_changed', } = config;
42
+ // Validate identifiers to prevent SQL injection
43
+ validateIdentifier(tableName, 'table name');
44
+ validateIdentifier(schema, 'schema name');
45
+ validateIdentifier(notifyChannel, 'notify channel');
46
+ // Helper to get pool (supports lazy initialization via function)
47
+ const getPool = () => {
48
+ const pool = typeof poolOrFn === 'function' ? poolOrFn() : poolOrFn;
49
+ if (!pool || typeof pool.query !== 'function') {
50
+ throw new Error('Invalid pool: must have query method');
51
+ }
52
+ return pool;
53
+ };
54
+ const tableFullName = `"${schema}"."${tableName}"`;
55
+ // Listeners for config changes
56
+ const listeners = new Set();
57
+ // Client dedicated to listening for notifications
58
+ let listenerClient = null;
59
+ // Reconnection state for exponential backoff
60
+ let reconnectAttempt = 0;
61
+ const maxReconnectDelay = 60000; // Max 60 seconds
62
+ const baseReconnectDelay = 1000; // Start at 1 second
63
+ /**
64
+ * Calculate reconnect delay with exponential backoff
65
+ */
66
+ function getReconnectDelay() {
67
+ // Exponential backoff: 1s, 2s, 4s, 8s, 16s, 32s, 60s (capped)
68
+ const delay = Math.min(baseReconnectDelay * Math.pow(2, reconnectAttempt), maxReconnectDelay);
69
+ reconnectAttempt++;
70
+ return delay;
71
+ }
72
+ /**
73
+ * Reset reconnection state after successful connection
74
+ */
75
+ function resetReconnectState() {
76
+ reconnectAttempt = 0;
77
+ }
78
+ /**
79
+ * Start listening for pg_notify events
80
+ */
81
+ async function startListening() {
82
+ if (!enableNotify || listenerClient)
83
+ return;
84
+ try {
85
+ const pool = getPool();
86
+ listenerClient = await pool.connect();
87
+ // Subscribe to the notification channel
88
+ await listenerClient.query(`LISTEN ${notifyChannel}`);
89
+ // Reset backoff on successful connection
90
+ resetReconnectState();
91
+ // Handle notifications
92
+ listenerClient.on('notification', async (msg) => {
93
+ if (msg.channel === notifyChannel) {
94
+ // Reload config from database and notify listeners
95
+ const newConfig = await loadFromDb();
96
+ for (const listener of listeners) {
97
+ try {
98
+ listener(newConfig);
99
+ }
100
+ catch (err) {
101
+ console.error('[AuthConfigStore] Listener error:', err);
102
+ }
103
+ }
104
+ }
105
+ });
106
+ // Handle errors - try to reconnect with exponential backoff
107
+ // Note: pg client emits 'error' events with Error objects, but our interface
108
+ // only defines 'notification'. We cast to any to handle this.
109
+ listenerClient.on('error', (err) => {
110
+ console.error('[AuthConfigStore] Listener connection error:', err);
111
+ listenerClient?.release(true);
112
+ listenerClient = null;
113
+ // Try to reconnect with exponential backoff
114
+ const delay = getReconnectDelay();
115
+ console.log(`[AuthConfigStore] Reconnecting in ${delay}ms (attempt ${reconnectAttempt})`);
116
+ setTimeout(() => startListening(), delay);
117
+ });
118
+ }
119
+ catch (err) {
120
+ console.error('[AuthConfigStore] Failed to start listener:', err);
121
+ listenerClient = null;
122
+ // Also apply backoff on initial connection failure
123
+ const delay = getReconnectDelay();
124
+ console.log(`[AuthConfigStore] Retrying connection in ${delay}ms (attempt ${reconnectAttempt})`);
125
+ setTimeout(() => startListening(), delay);
126
+ }
127
+ }
128
+ /**
129
+ * Load config from database
130
+ */
131
+ async function loadFromDb() {
132
+ const pool = getPool();
133
+ const result = await pool.query(`SELECT adapter, config, settings, updated_at, updated_by
134
+ FROM ${tableFullName}
135
+ LIMIT 1`);
136
+ if (result.rows.length === 0) {
137
+ return null;
138
+ }
139
+ const row = result.rows[0];
140
+ return {
141
+ adapter: row.adapter,
142
+ config: row.config,
143
+ settings: row.settings,
144
+ updatedAt: row.updated_at.toISOString(),
145
+ updatedBy: row.updated_by || undefined,
146
+ };
147
+ }
148
+ return {
149
+ name: 'postgres',
150
+ async initialize() {
151
+ if (!autoCreateTable) {
152
+ await startListening();
153
+ return;
154
+ }
155
+ const pool = getPool();
156
+ // Create table with singleton pattern (only one row allowed)
157
+ await pool.query(`
158
+ CREATE TABLE IF NOT EXISTS ${tableFullName} (
159
+ id SERIAL PRIMARY KEY,
160
+ adapter VARCHAR(50),
161
+ config JSONB NOT NULL DEFAULT '{}',
162
+ settings JSONB NOT NULL DEFAULT '{}',
163
+ created_at TIMESTAMPTZ DEFAULT NOW(),
164
+ updated_at TIMESTAMPTZ DEFAULT NOW(),
165
+ updated_by VARCHAR(255)
166
+ );
167
+
168
+ -- Ensure only one config row (singleton pattern)
169
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_${tableName}_singleton
170
+ ON ${tableFullName} ((true));
171
+ `);
172
+ // Start listening for notifications
173
+ await startListening();
174
+ },
175
+ async load() {
176
+ return loadFromDb();
177
+ },
178
+ async save(runtimeConfig) {
179
+ const pool = getPool();
180
+ // Upsert the configuration
181
+ await pool.query(`INSERT INTO ${tableFullName} (adapter, config, settings, updated_at, updated_by)
182
+ VALUES ($1, $2, $3, NOW(), $4)
183
+ ON CONFLICT ((true)) DO UPDATE SET
184
+ adapter = $1,
185
+ config = $2,
186
+ settings = $3,
187
+ updated_at = NOW(),
188
+ updated_by = $4`, [
189
+ runtimeConfig.adapter,
190
+ JSON.stringify(runtimeConfig.config),
191
+ JSON.stringify(runtimeConfig.settings),
192
+ runtimeConfig.updatedBy || null,
193
+ ]);
194
+ // Notify other instances
195
+ if (enableNotify) {
196
+ await pool.query(`NOTIFY ${notifyChannel}`);
197
+ }
198
+ },
199
+ async delete() {
200
+ const pool = getPool();
201
+ const result = await pool.query(`DELETE FROM ${tableFullName}`);
202
+ // Notify other instances
203
+ if (enableNotify) {
204
+ await pool.query(`NOTIFY ${notifyChannel}`);
205
+ }
206
+ return (result.rowCount ?? 0) > 0;
207
+ },
208
+ onChange(callback) {
209
+ listeners.add(callback);
210
+ // Return unsubscribe function
211
+ return () => {
212
+ listeners.delete(callback);
213
+ };
214
+ },
215
+ async shutdown() {
216
+ // Release the listener client
217
+ if (listenerClient) {
218
+ try {
219
+ await listenerClient.query(`UNLISTEN ${notifyChannel}`);
220
+ }
221
+ catch {
222
+ // Ignore errors during shutdown
223
+ }
224
+ listenerClient.release(true);
225
+ listenerClient = null;
226
+ }
227
+ // Clear listeners
228
+ listeners.clear();
229
+ },
230
+ };
231
+ }
232
+ //# sourceMappingURL=config-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../../src/plugins/auth/config-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Auth Config Store Tests
3
+ *
4
+ * Unit tests for PostgreSQL-backed auth configuration store.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=config-store.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.test.d.ts","sourceRoot":"","sources":["../../../src/plugins/auth/config-store.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}