@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.
- package/README.md +311 -0
- package/dist/core/control-panel.d.ts.map +1 -1
- package/dist/core/control-panel.js +144 -2
- package/dist/core/control-panel.js.map +1 -1
- package/dist/core/plugin-registry.d.ts +36 -0
- package/dist/core/plugin-registry.d.ts.map +1 -1
- package/dist/core/plugin-registry.js +26 -0
- package/dist/core/plugin-registry.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 +4 -2
- 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/adapters/index.d.ts +1 -0
- package/dist/plugins/auth/adapters/index.d.ts.map +1 -1
- package/dist/plugins/auth/adapters/index.js +1 -0
- package/dist/plugins/auth/adapters/index.js.map +1 -1
- package/dist/plugins/auth/adapters/supabase-adapter.d.ts.map +1 -1
- package/dist/plugins/auth/adapters/supabase-adapter.js.map +1 -1
- package/dist/plugins/auth/adapters/supertokens-adapter.d.ts +18 -0
- package/dist/plugins/auth/adapters/supertokens-adapter.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/supertokens-adapter.js +267 -0
- package/dist/plugins/auth/adapters/supertokens-adapter.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 +138 -0
- package/dist/plugins/auth/env-config.d.ts.map +1 -0
- package/dist/plugins/auth/env-config.js +1122 -0
- package/dist/plugins/auth/env-config.js.map +1 -0
- package/dist/plugins/auth/index.d.ts +7 -1
- package/dist/plugins/auth/index.d.ts.map +1 -1
- package/dist/plugins/auth/index.js +7 -0
- package/dist/plugins/auth/index.js.map +1 -1
- package/dist/plugins/auth/supertokens-adapter.test.d.ts +10 -0
- package/dist/plugins/auth/supertokens-adapter.test.d.ts.map +1 -0
- package/dist/plugins/auth/supertokens-adapter.test.js +486 -0
- package/dist/plugins/auth/supertokens-adapter.test.js.map +1 -0
- package/dist/plugins/auth/types.d.ts +176 -0
- package/dist/plugins/auth/types.d.ts.map +1 -1
- package/dist/plugins/auth/types.js.map +1 -1
- package/dist/plugins/cache-plugin.test.js +3 -0
- package/dist/plugins/cache-plugin.test.js.map +1 -1
- package/dist/plugins/index.d.ts +6 -2
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +5 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/postgres-plugin.test.js +3 -0
- package/dist/plugins/postgres-plugin.test.js.map +1 -1
- package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts +7 -0
- package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts.map +1 -0
- package/dist/plugins/preferences/__tests__/deep-merge.test.js +215 -0
- package/dist/plugins/preferences/__tests__/deep-merge.test.js.map +1 -0
- package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts +7 -0
- package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts.map +1 -0
- package/dist/plugins/preferences/__tests__/preferences-plugin.test.js +265 -0
- package/dist/plugins/preferences/__tests__/preferences-plugin.test.js.map +1 -0
- package/dist/plugins/preferences/index.d.ts +12 -0
- package/dist/plugins/preferences/index.d.ts.map +1 -0
- package/dist/plugins/preferences/index.js +13 -0
- package/dist/plugins/preferences/index.js.map +1 -0
- package/dist/plugins/preferences/preferences-plugin.d.ts +39 -0
- package/dist/plugins/preferences/preferences-plugin.d.ts.map +1 -0
- package/dist/plugins/preferences/preferences-plugin.js +226 -0
- package/dist/plugins/preferences/preferences-plugin.js.map +1 -0
- package/dist/plugins/preferences/stores/index.d.ts +9 -0
- package/dist/plugins/preferences/stores/index.d.ts.map +1 -0
- package/dist/plugins/preferences/stores/index.js +9 -0
- package/dist/plugins/preferences/stores/index.js.map +1 -0
- package/dist/plugins/preferences/stores/postgres-store.d.ts +41 -0
- package/dist/plugins/preferences/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/preferences/stores/postgres-store.js +181 -0
- package/dist/plugins/preferences/stores/postgres-store.js.map +1 -0
- package/dist/plugins/preferences/types.d.ts +91 -0
- package/dist/plugins/preferences/types.d.ts.map +1 -0
- package/dist/plugins/preferences/types.js +10 -0
- package/dist/plugins/preferences/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/users/__tests__/users-plugin.test.d.ts +9 -0
- package/dist/plugins/users/__tests__/users-plugin.test.d.ts.map +1 -0
- package/dist/plugins/users/__tests__/users-plugin.test.js +546 -0
- package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -0
- 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/types.d.ts +36 -0
- package/dist/plugins/users/types.d.ts.map +1 -1
- package/dist/plugins/users/users-plugin.d.ts +8 -2
- package/dist/plugins/users/users-plugin.d.ts.map +1 -1
- package/dist/plugins/users/users-plugin.js +122 -5
- package/dist/plugins/users/users-plugin.js.map +1 -1
- package/dist-ui/assets/index-D7DoZ9rL.js +478 -0
- package/dist-ui/assets/index-D7DoZ9rL.js.map +1 -0
- package/dist-ui/index.html +1 -1
- package/dist-ui-lib/api/controlPanelApi.d.ts +194 -7
- package/dist-ui-lib/dashboard/WidgetComponentRegistry.d.ts +9 -5
- package/dist-ui-lib/dashboard/builtInWidgets.d.ts +7 -1
- 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/index.d.ts +2 -0
- package/dist-ui-lib/index.js +3665 -3945
- package/dist-ui-lib/index.js.map +1 -1
- package/dist-ui-lib/pages/AuthPage.d.ts +1 -0
- package/dist-ui-lib/pages/IntegrationsPage.d.ts +1 -0
- package/dist-ui-lib/pages/PluginsPage.d.ts +1 -0
- package/dist-ui-lib/pages/RateLimitPage.d.ts +1 -0
- package/package.json +7 -2
- package/src/core/control-panel.ts +161 -2
- package/src/core/plugin-registry.ts +63 -0
- package/src/core/types.ts +17 -0
- package/src/index.ts +45 -0
- package/src/plugins/auth/adapter-wrapper.test.ts +395 -0
- package/src/plugins/auth/adapter-wrapper.ts +205 -0
- package/src/plugins/auth/adapters/index.ts +1 -0
- package/src/plugins/auth/adapters/supabase-adapter.ts +22 -14
- package/src/plugins/auth/adapters/supertokens-adapter.ts +326 -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 +1279 -0
- package/src/plugins/auth/index.ts +30 -0
- package/src/plugins/auth/supertokens-adapter.test.ts +621 -0
- package/src/plugins/auth/types.ts +218 -0
- package/src/plugins/cache-plugin.test.ts +3 -0
- package/src/plugins/index.ts +75 -0
- package/src/plugins/postgres-plugin.test.ts +3 -0
- package/src/plugins/preferences/__tests__/deep-merge.test.ts +242 -0
- package/src/plugins/preferences/__tests__/preferences-plugin.test.ts +350 -0
- package/src/plugins/preferences/index.ts +30 -0
- package/src/plugins/preferences/preferences-plugin.ts +270 -0
- package/src/plugins/preferences/stores/index.ts +9 -0
- package/src/plugins/preferences/stores/postgres-store.ts +252 -0
- package/src/plugins/preferences/types.ts +100 -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/users/__tests__/users-plugin.test.ts +690 -0
- package/src/plugins/users/index.ts +3 -0
- package/src/plugins/users/types.ts +38 -0
- package/src/plugins/users/users-plugin.ts +142 -5
- package/ui/src/App.tsx +35 -14
- package/ui/src/api/controlPanelApi.ts +326 -1
- package/ui/src/components/ControlPanelApp.tsx +3 -0
- package/ui/src/dashboard/PluginWidgetRenderer.tsx +13 -10
- package/ui/src/dashboard/WidgetComponentRegistry.tsx +13 -9
- package/ui/src/dashboard/builtInWidgets.tsx +13 -3
- package/ui/src/dashboard/widgets/AuthStatusWidget.tsx +143 -0
- package/ui/src/dashboard/widgets/IntegrationStatusWidget.tsx +135 -0
- package/ui/src/dashboard/widgets/index.ts +2 -0
- package/ui/src/pages/AuthPage.tsx +1103 -0
- package/ui/src/pages/IntegrationsPage.tsx +288 -0
- package/ui/src/pages/PluginsPage.tsx +394 -0
- package/ui/src/pages/RateLimitPage.tsx +292 -0
- package/ui/vite.lib.config.ts +5 -0
- package/dist-ui/assets/index-Bsp2ntcw.js +0 -465
- package/dist-ui/assets/index-Bsp2ntcw.js.map +0 -1
|
@@ -127,6 +127,47 @@ export interface BasicAdapterConfig {
|
|
|
127
127
|
realm?: string;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Supertokens adapter configuration
|
|
132
|
+
*/
|
|
133
|
+
export interface SupertokensAdapterConfig {
|
|
134
|
+
/** Supertokens connection URI (e.g., 'http://localhost:3567') */
|
|
135
|
+
connectionUri: string;
|
|
136
|
+
|
|
137
|
+
/** Supertokens API key (for managed service) */
|
|
138
|
+
apiKey?: string;
|
|
139
|
+
|
|
140
|
+
/** App name for branding */
|
|
141
|
+
appName: string;
|
|
142
|
+
|
|
143
|
+
/** API domain (e.g., 'http://localhost:3000') */
|
|
144
|
+
apiDomain: string;
|
|
145
|
+
|
|
146
|
+
/** Website domain (e.g., 'http://localhost:3000') */
|
|
147
|
+
websiteDomain: string;
|
|
148
|
+
|
|
149
|
+
/** API base path (default: '/auth') */
|
|
150
|
+
apiBasePath?: string;
|
|
151
|
+
|
|
152
|
+
/** Website base path (default: '/auth') */
|
|
153
|
+
websiteBasePath?: string;
|
|
154
|
+
|
|
155
|
+
/** Enable email/password auth (default: true) */
|
|
156
|
+
enableEmailPassword?: boolean;
|
|
157
|
+
|
|
158
|
+
/** Social login providers */
|
|
159
|
+
socialProviders?: {
|
|
160
|
+
google?: { clientId: string; clientSecret: string };
|
|
161
|
+
apple?: {
|
|
162
|
+
clientId: string;
|
|
163
|
+
clientSecret: string;
|
|
164
|
+
keyId: string;
|
|
165
|
+
teamId: string;
|
|
166
|
+
};
|
|
167
|
+
github?: { clientId: string; clientSecret: string };
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
130
171
|
/**
|
|
131
172
|
* Auth plugin configuration
|
|
132
173
|
*/
|
|
@@ -163,3 +204,180 @@ export interface AuthenticatedRequest extends Request {
|
|
|
163
204
|
export function isAuthenticatedRequest(req: Request): req is AuthenticatedRequest {
|
|
164
205
|
return 'auth' in req && (req as AuthenticatedRequest).auth?.isAuthenticated === true;
|
|
165
206
|
}
|
|
207
|
+
|
|
208
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
209
|
+
// Environment Configuration Types
|
|
210
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Auth plugin state
|
|
214
|
+
*/
|
|
215
|
+
export type AuthPluginState = 'disabled' | 'enabled' | 'error';
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Options for createAuthPluginFromEnv (overrides only)
|
|
219
|
+
*/
|
|
220
|
+
export interface AuthEnvPluginOptions {
|
|
221
|
+
/** Paths to exclude from authentication (can also use AUTH_EXCLUDE_PATHS env var) */
|
|
222
|
+
excludePaths?: string[];
|
|
223
|
+
/** Whether auth is required (can also use AUTH_REQUIRED env var, default: true) */
|
|
224
|
+
authRequired?: boolean;
|
|
225
|
+
/** Enable debug logging (can also use AUTH_DEBUG env var) */
|
|
226
|
+
debug?: boolean;
|
|
227
|
+
/** Custom unauthorized handler */
|
|
228
|
+
onUnauthorized?: (req: Request, res: Response) => void;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Auth configuration status returned by getAuthStatus()
|
|
233
|
+
*/
|
|
234
|
+
export interface AuthConfigStatus {
|
|
235
|
+
/** Current plugin state */
|
|
236
|
+
state: AuthPluginState;
|
|
237
|
+
/** Active adapter name (null if disabled or error) */
|
|
238
|
+
adapter: string | null;
|
|
239
|
+
/** Error message if state is 'error' */
|
|
240
|
+
error?: string;
|
|
241
|
+
/** List of missing environment variables if state is 'error' */
|
|
242
|
+
missingVars?: string[];
|
|
243
|
+
/** Current configuration with secrets masked */
|
|
244
|
+
config?: Record<string, string>;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
248
|
+
// Runtime Configuration Types
|
|
249
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Supported adapter types for runtime configuration
|
|
253
|
+
*/
|
|
254
|
+
export type AuthAdapterType = 'auth0' | 'supabase' | 'supertokens' | 'basic';
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Runtime auth configuration (persisted to database)
|
|
258
|
+
*/
|
|
259
|
+
export interface RuntimeAuthConfig {
|
|
260
|
+
/** Which adapter to use */
|
|
261
|
+
adapter: AuthAdapterType | null;
|
|
262
|
+
|
|
263
|
+
/** Adapter-specific configuration */
|
|
264
|
+
config: {
|
|
265
|
+
auth0?: Auth0AdapterConfig;
|
|
266
|
+
supabase?: SupabaseAdapterConfig;
|
|
267
|
+
supertokens?: SupertokensAdapterConfig;
|
|
268
|
+
basic?: BasicAdapterConfig;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/** General auth settings */
|
|
272
|
+
settings: {
|
|
273
|
+
authRequired?: boolean;
|
|
274
|
+
excludePaths?: string[];
|
|
275
|
+
debug?: boolean;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/** When the config was last updated */
|
|
279
|
+
updatedAt: string;
|
|
280
|
+
|
|
281
|
+
/** Who updated the config (optional) */
|
|
282
|
+
updatedBy?: string;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Request body for PUT /api/auth/config
|
|
287
|
+
*/
|
|
288
|
+
export interface UpdateAuthConfigRequest {
|
|
289
|
+
/** Which adapter to use */
|
|
290
|
+
adapter: AuthAdapterType;
|
|
291
|
+
|
|
292
|
+
/** Adapter-specific configuration */
|
|
293
|
+
config: Record<string, unknown>;
|
|
294
|
+
|
|
295
|
+
/** General settings (optional) */
|
|
296
|
+
settings?: {
|
|
297
|
+
authRequired?: boolean;
|
|
298
|
+
excludePaths?: string[];
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Request body for POST /api/auth/test-provider
|
|
304
|
+
*/
|
|
305
|
+
export interface TestProviderRequest {
|
|
306
|
+
/** Which adapter to test */
|
|
307
|
+
adapter: AuthAdapterType;
|
|
308
|
+
|
|
309
|
+
/** Adapter configuration to test */
|
|
310
|
+
config: Record<string, unknown>;
|
|
311
|
+
|
|
312
|
+
/** For social provider test (optional) */
|
|
313
|
+
provider?: 'google' | 'github' | 'apple';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Response for POST /api/auth/test-provider
|
|
318
|
+
*/
|
|
319
|
+
export interface TestProviderResponse {
|
|
320
|
+
/** Whether the test was successful */
|
|
321
|
+
success: boolean;
|
|
322
|
+
|
|
323
|
+
/** Human-readable message */
|
|
324
|
+
message: string;
|
|
325
|
+
|
|
326
|
+
/** Additional details */
|
|
327
|
+
details?: {
|
|
328
|
+
latency?: number;
|
|
329
|
+
version?: string;
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Auth configuration store interface
|
|
335
|
+
*/
|
|
336
|
+
export interface AuthConfigStore {
|
|
337
|
+
/** Store name for identification */
|
|
338
|
+
name: string;
|
|
339
|
+
|
|
340
|
+
/** Initialize the store (create tables if needed) */
|
|
341
|
+
initialize(): Promise<void>;
|
|
342
|
+
|
|
343
|
+
/** Load configuration from store */
|
|
344
|
+
load(): Promise<RuntimeAuthConfig | null>;
|
|
345
|
+
|
|
346
|
+
/** Save configuration to store */
|
|
347
|
+
save(config: RuntimeAuthConfig): Promise<void>;
|
|
348
|
+
|
|
349
|
+
/** Delete configuration (revert to env vars) */
|
|
350
|
+
delete(): Promise<boolean>;
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Subscribe to configuration changes
|
|
354
|
+
* Returns unsubscribe function
|
|
355
|
+
*/
|
|
356
|
+
onChange(callback: (config: RuntimeAuthConfig | null) => void): () => void;
|
|
357
|
+
|
|
358
|
+
/** Shutdown and cleanup */
|
|
359
|
+
shutdown(): Promise<void>;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* PostgreSQL auth config store configuration
|
|
364
|
+
*/
|
|
365
|
+
export interface PostgresAuthConfigStoreConfig {
|
|
366
|
+
/** PostgreSQL pool instance or factory function for lazy initialization */
|
|
367
|
+
pool: unknown | (() => unknown);
|
|
368
|
+
|
|
369
|
+
/** Table name (default: 'auth_config') */
|
|
370
|
+
tableName?: string;
|
|
371
|
+
|
|
372
|
+
/** Schema name (default: 'public') */
|
|
373
|
+
schema?: string;
|
|
374
|
+
|
|
375
|
+
/** Auto-create table on initialization (default: true) */
|
|
376
|
+
autoCreateTable?: boolean;
|
|
377
|
+
|
|
378
|
+
/** Enable pg_notify for cross-instance config updates (default: true) */
|
|
379
|
+
enableNotify?: boolean;
|
|
380
|
+
|
|
381
|
+
/** Channel name for pg_notify (default: 'auth_config_changed') */
|
|
382
|
+
notifyChannel?: string;
|
|
383
|
+
}
|
|
@@ -79,10 +79,13 @@ describe('Cache Plugin', () => {
|
|
|
79
79
|
addMenuItem: vi.fn(),
|
|
80
80
|
addPage: vi.fn(),
|
|
81
81
|
addWidget: vi.fn(),
|
|
82
|
+
addConfigComponent: vi.fn(),
|
|
82
83
|
getRoutes: vi.fn().mockReturnValue([]),
|
|
83
84
|
getMenuItems: vi.fn().mockReturnValue([]),
|
|
84
85
|
getPages: vi.fn().mockReturnValue([]),
|
|
85
86
|
getWidgets: vi.fn().mockReturnValue([]),
|
|
87
|
+
getConfigComponents: vi.fn().mockReturnValue([]),
|
|
88
|
+
getPluginContributions: vi.fn().mockReturnValue({ routes: [], menuItems: [], pages: [], widgets: [], config: undefined }),
|
|
86
89
|
getConfig: vi.fn().mockReturnValue({}),
|
|
87
90
|
setConfig: vi.fn().mockResolvedValue(undefined),
|
|
88
91
|
subscribe: vi.fn().mockReturnValue(() => {}),
|
package/src/plugins/index.ts
CHANGED
|
@@ -28,6 +28,10 @@ export type { CachePluginConfig, CacheInstance } from './cache-plugin.js';
|
|
|
28
28
|
// Auth plugin
|
|
29
29
|
export {
|
|
30
30
|
createAuthPlugin,
|
|
31
|
+
createAuthPluginFromEnv,
|
|
32
|
+
getAuthStatus,
|
|
33
|
+
setAuthConfigStore,
|
|
34
|
+
postgresAuthConfigStore,
|
|
31
35
|
isAuthenticated,
|
|
32
36
|
getAuthenticatedUser,
|
|
33
37
|
getAccessToken,
|
|
@@ -37,6 +41,7 @@ export {
|
|
|
37
41
|
auth0Adapter,
|
|
38
42
|
basicAdapter,
|
|
39
43
|
supabaseAdapter,
|
|
44
|
+
supertokensAdapter,
|
|
40
45
|
isAuthenticatedRequest,
|
|
41
46
|
} from './auth/index.js';
|
|
42
47
|
export type {
|
|
@@ -47,6 +52,12 @@ export type {
|
|
|
47
52
|
Auth0AdapterConfig,
|
|
48
53
|
SupabaseAdapterConfig,
|
|
49
54
|
BasicAdapterConfig,
|
|
55
|
+
SupertokensAdapterConfig,
|
|
56
|
+
AuthPluginState,
|
|
57
|
+
AuthEnvPluginOptions,
|
|
58
|
+
AuthConfigStatus,
|
|
59
|
+
AuthConfigStore,
|
|
60
|
+
PostgresAuthConfigStoreConfig,
|
|
50
61
|
} from './auth/index.js';
|
|
51
62
|
|
|
52
63
|
// Users plugin
|
|
@@ -130,3 +141,67 @@ export type {
|
|
|
130
141
|
CachedEntitlements,
|
|
131
142
|
EntitlementStats,
|
|
132
143
|
} from './entitlements/index.js';
|
|
144
|
+
|
|
145
|
+
// Preferences plugin (depends on Users)
|
|
146
|
+
export {
|
|
147
|
+
createPreferencesPlugin,
|
|
148
|
+
getPreferencesStore,
|
|
149
|
+
getPreferences,
|
|
150
|
+
updatePreferences,
|
|
151
|
+
deletePreferences,
|
|
152
|
+
getDefaultPreferences,
|
|
153
|
+
postgresPreferencesStore,
|
|
154
|
+
deepMerge,
|
|
155
|
+
} from './preferences/index.js';
|
|
156
|
+
export type {
|
|
157
|
+
PreferencesPluginConfig,
|
|
158
|
+
PreferencesStore,
|
|
159
|
+
UserPreferences,
|
|
160
|
+
PostgresPreferencesStoreConfig,
|
|
161
|
+
PreferencesApiConfig,
|
|
162
|
+
} from './preferences/index.js';
|
|
163
|
+
|
|
164
|
+
// Rate Limit plugin
|
|
165
|
+
export {
|
|
166
|
+
createRateLimitPlugin,
|
|
167
|
+
createRateLimitPluginFromEnv,
|
|
168
|
+
getRateLimitConfigStatus,
|
|
169
|
+
postgresRateLimitStore,
|
|
170
|
+
createRateLimitCache,
|
|
171
|
+
createNoOpCache,
|
|
172
|
+
createSlidingWindowStrategy,
|
|
173
|
+
createFixedWindowStrategy,
|
|
174
|
+
createTokenBucketStrategy,
|
|
175
|
+
getStrategy,
|
|
176
|
+
rateLimitMiddleware,
|
|
177
|
+
rateLimitStatusMiddleware,
|
|
178
|
+
RateLimitService,
|
|
179
|
+
getRateLimitService,
|
|
180
|
+
isLimited,
|
|
181
|
+
checkLimit,
|
|
182
|
+
incrementLimit,
|
|
183
|
+
getRemainingRequests,
|
|
184
|
+
getLimitStatus,
|
|
185
|
+
clearLimit,
|
|
186
|
+
createCleanupJob,
|
|
187
|
+
} from './rate-limit/index.js';
|
|
188
|
+
export type {
|
|
189
|
+
RateLimitPluginConfig,
|
|
190
|
+
RateLimitEnvPluginOptions,
|
|
191
|
+
RateLimitStrategy,
|
|
192
|
+
LimitStatus,
|
|
193
|
+
Strategy,
|
|
194
|
+
StrategyOptions,
|
|
195
|
+
StrategyContext,
|
|
196
|
+
StoredLimit,
|
|
197
|
+
IncrementOptions,
|
|
198
|
+
RateLimitStore,
|
|
199
|
+
PostgresRateLimitStoreConfig,
|
|
200
|
+
CachedLimit,
|
|
201
|
+
RateLimitCache,
|
|
202
|
+
RateLimitCacheConfig,
|
|
203
|
+
RateLimitMiddlewareOptions,
|
|
204
|
+
CheckLimitOptions,
|
|
205
|
+
CleanupJob,
|
|
206
|
+
CleanupJobConfig,
|
|
207
|
+
} from './rate-limit/index.js';
|
|
@@ -56,10 +56,13 @@ describe('PostgreSQL Plugin', () => {
|
|
|
56
56
|
addMenuItem: vi.fn(),
|
|
57
57
|
addPage: vi.fn(),
|
|
58
58
|
addWidget: vi.fn(),
|
|
59
|
+
addConfigComponent: vi.fn(),
|
|
59
60
|
getRoutes: vi.fn().mockReturnValue([]),
|
|
60
61
|
getMenuItems: vi.fn().mockReturnValue([]),
|
|
61
62
|
getPages: vi.fn().mockReturnValue([]),
|
|
62
63
|
getWidgets: vi.fn().mockReturnValue([]),
|
|
64
|
+
getConfigComponents: vi.fn().mockReturnValue([]),
|
|
65
|
+
getPluginContributions: vi.fn().mockReturnValue({ routes: [], menuItems: [], pages: [], widgets: [], config: undefined }),
|
|
63
66
|
getConfig: vi.fn().mockReturnValue({}),
|
|
64
67
|
setConfig: vi.fn().mockResolvedValue(undefined),
|
|
65
68
|
subscribe: vi.fn().mockReturnValue(() => {}),
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep Merge Utility Tests
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for the deep merge function used by the preferences plugin.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from 'vitest';
|
|
8
|
+
import { deepMerge } from '../stores/postgres-store.js';
|
|
9
|
+
|
|
10
|
+
describe('deepMerge', () => {
|
|
11
|
+
describe('basic merging', () => {
|
|
12
|
+
it('should merge flat objects', () => {
|
|
13
|
+
const target = { a: 1 };
|
|
14
|
+
const source = { b: 2 };
|
|
15
|
+
const result = deepMerge(target, source);
|
|
16
|
+
expect(result).toEqual({ a: 1, b: 2 });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should not mutate original objects', () => {
|
|
20
|
+
const target = { a: 1 };
|
|
21
|
+
const source = { b: 2 };
|
|
22
|
+
deepMerge(target, source);
|
|
23
|
+
expect(target).toEqual({ a: 1 });
|
|
24
|
+
expect(source).toEqual({ b: 2 });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should return a new object', () => {
|
|
28
|
+
const target = { a: 1 };
|
|
29
|
+
const source = { b: 2 };
|
|
30
|
+
const result = deepMerge(target, source);
|
|
31
|
+
expect(result).not.toBe(target);
|
|
32
|
+
expect(result).not.toBe(source);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('nested object merging', () => {
|
|
37
|
+
it('should merge nested objects recursively', () => {
|
|
38
|
+
const target = { a: { x: 1 } };
|
|
39
|
+
const source = { a: { y: 2 } };
|
|
40
|
+
const result = deepMerge(target, source);
|
|
41
|
+
expect(result).toEqual({ a: { x: 1, y: 2 } });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should handle deeply nested objects', () => {
|
|
45
|
+
const target = { a: { b: { c: { x: 1 } } } };
|
|
46
|
+
const source = { a: { b: { c: { y: 2 } } } };
|
|
47
|
+
const result = deepMerge(target, source);
|
|
48
|
+
expect(result).toEqual({ a: { b: { c: { x: 1, y: 2 } } } });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should merge multiple nested keys', () => {
|
|
52
|
+
const target = {
|
|
53
|
+
theme: 'light',
|
|
54
|
+
notifications: { email: true, push: true },
|
|
55
|
+
};
|
|
56
|
+
const source = {
|
|
57
|
+
notifications: { email: false },
|
|
58
|
+
};
|
|
59
|
+
const result = deepMerge(target, source);
|
|
60
|
+
expect(result).toEqual({
|
|
61
|
+
theme: 'light',
|
|
62
|
+
notifications: { email: false, push: true },
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('value overwriting', () => {
|
|
68
|
+
it('should let source override target for same keys', () => {
|
|
69
|
+
const target = { a: 1 };
|
|
70
|
+
const source = { a: 2 };
|
|
71
|
+
const result = deepMerge(target, source);
|
|
72
|
+
expect(result).toEqual({ a: 2 });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should let source override target for nested keys', () => {
|
|
76
|
+
const target = { a: { x: 1 } };
|
|
77
|
+
const source = { a: { x: 2 } };
|
|
78
|
+
const result = deepMerge(target, source);
|
|
79
|
+
expect(result).toEqual({ a: { x: 2 } });
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('array handling', () => {
|
|
84
|
+
it('should replace arrays (not merge)', () => {
|
|
85
|
+
const target = { a: [1, 2] };
|
|
86
|
+
const source = { a: [3, 4, 5] };
|
|
87
|
+
const result = deepMerge(target, source);
|
|
88
|
+
expect(result).toEqual({ a: [3, 4, 5] });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should replace array with empty array', () => {
|
|
92
|
+
const target = { a: [1, 2, 3] };
|
|
93
|
+
const source = { a: [] };
|
|
94
|
+
const result = deepMerge(target, source);
|
|
95
|
+
expect(result).toEqual({ a: [] });
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should replace non-array with array', () => {
|
|
99
|
+
const target = { a: 'string' };
|
|
100
|
+
const source = { a: [1, 2] };
|
|
101
|
+
const result = deepMerge(target, source);
|
|
102
|
+
expect(result).toEqual({ a: [1, 2] });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should replace array with non-array', () => {
|
|
106
|
+
const target = { a: [1, 2] };
|
|
107
|
+
const source = { a: 'string' };
|
|
108
|
+
const result = deepMerge(target, source);
|
|
109
|
+
expect(result).toEqual({ a: 'string' });
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('special values', () => {
|
|
114
|
+
it('should handle null values in source', () => {
|
|
115
|
+
const target = { a: 1 };
|
|
116
|
+
const source = { a: null };
|
|
117
|
+
const result = deepMerge(target, source);
|
|
118
|
+
expect(result).toEqual({ a: null });
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should skip undefined values in source', () => {
|
|
122
|
+
const target = { a: 1 };
|
|
123
|
+
const source = { a: undefined };
|
|
124
|
+
const result = deepMerge(target, source);
|
|
125
|
+
expect(result).toEqual({ a: 1 });
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should handle null in target', () => {
|
|
129
|
+
const target = { a: null };
|
|
130
|
+
const source = { a: { x: 1 } };
|
|
131
|
+
const result = deepMerge(target, source);
|
|
132
|
+
expect(result).toEqual({ a: { x: 1 } });
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should replace object with null', () => {
|
|
136
|
+
const target = { a: { x: 1 } };
|
|
137
|
+
const source = { a: null };
|
|
138
|
+
const result = deepMerge(target, source);
|
|
139
|
+
expect(result).toEqual({ a: null });
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('edge cases', () => {
|
|
144
|
+
it('should handle empty target', () => {
|
|
145
|
+
const target = {};
|
|
146
|
+
const source = { a: 1 };
|
|
147
|
+
const result = deepMerge(target, source);
|
|
148
|
+
expect(result).toEqual({ a: 1 });
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should handle empty source', () => {
|
|
152
|
+
const target = { a: 1 };
|
|
153
|
+
const source = {};
|
|
154
|
+
const result = deepMerge(target, source);
|
|
155
|
+
expect(result).toEqual({ a: 1 });
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should handle both empty', () => {
|
|
159
|
+
const target = {};
|
|
160
|
+
const source = {};
|
|
161
|
+
const result = deepMerge(target, source);
|
|
162
|
+
expect(result).toEqual({});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should handle primitive values becoming objects', () => {
|
|
166
|
+
const target = { a: 'string' };
|
|
167
|
+
const source = { a: { x: 1 } };
|
|
168
|
+
const result = deepMerge(target, source);
|
|
169
|
+
expect(result).toEqual({ a: { x: 1 } });
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should handle objects becoming primitive values', () => {
|
|
173
|
+
const target = { a: { x: 1 } };
|
|
174
|
+
const source = { a: 'string' };
|
|
175
|
+
const result = deepMerge(target, source);
|
|
176
|
+
expect(result).toEqual({ a: 'string' });
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('real-world preference scenarios', () => {
|
|
181
|
+
it('should merge default preferences with user preferences', () => {
|
|
182
|
+
const defaults = {
|
|
183
|
+
theme: 'system',
|
|
184
|
+
notifications: {
|
|
185
|
+
email: true,
|
|
186
|
+
push: true,
|
|
187
|
+
sms: false,
|
|
188
|
+
},
|
|
189
|
+
trading: {
|
|
190
|
+
defaultSymbol: 'SPY',
|
|
191
|
+
chartInterval: '5min',
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const userPrefs = {
|
|
196
|
+
theme: 'dark',
|
|
197
|
+
notifications: {
|
|
198
|
+
email: false,
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const result = deepMerge(defaults, userPrefs);
|
|
203
|
+
expect(result).toEqual({
|
|
204
|
+
theme: 'dark',
|
|
205
|
+
notifications: {
|
|
206
|
+
email: false,
|
|
207
|
+
push: true,
|
|
208
|
+
sms: false,
|
|
209
|
+
},
|
|
210
|
+
trading: {
|
|
211
|
+
defaultSymbol: 'SPY',
|
|
212
|
+
chartInterval: '5min',
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should handle partial updates to preferences', () => {
|
|
218
|
+
const existing = {
|
|
219
|
+
theme: 'dark',
|
|
220
|
+
notifications: {
|
|
221
|
+
email: false,
|
|
222
|
+
push: true,
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const update = {
|
|
227
|
+
notifications: {
|
|
228
|
+
push: false,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const result = deepMerge(existing, update);
|
|
233
|
+
expect(result).toEqual({
|
|
234
|
+
theme: 'dark',
|
|
235
|
+
notifications: {
|
|
236
|
+
email: false,
|
|
237
|
+
push: false,
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
});
|