@baasix/types 1.0.1

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/src/plugin.ts ADDED
@@ -0,0 +1,711 @@
1
+ /**
2
+ * Plugin System Types
3
+ * Shared types for Baasix plugin development
4
+ */
5
+
6
+ import type { SchemaDefinition } from "./schema";
7
+ import type { Accountability } from "./auth";
8
+ import type { MailOptions, HttpMethod } from "./common";
9
+ import type { ReportConfig, ReportResult, StatsQuery, StatsResult } from "./query";
10
+ import type { FileMetadata } from "./files";
11
+ import type { Notification, NotificationOptions } from "./notification";
12
+
13
+ // ============================================================================
14
+ // Express Types (actual Express types from @types/express)
15
+ // Core packages should import Express types from here for consistency.
16
+ // ============================================================================
17
+
18
+ import type {
19
+ Request as ExpressRequestType,
20
+ Response as ExpressResponseType,
21
+ NextFunction as ExpressNextFunctionType,
22
+ Express as ExpressType,
23
+ Router as RouterType,
24
+ } from "express";
25
+
26
+ /** Express Request type */
27
+ export type Request = ExpressRequestType;
28
+ /** Express Response type */
29
+ export type Response = ExpressResponseType;
30
+ /** Express NextFunction type */
31
+ export type NextFunction = ExpressNextFunctionType;
32
+ /** Express Application type */
33
+ export type Express = ExpressType;
34
+ /** Express Router type */
35
+ export type Router = RouterType;
36
+
37
+ /** Type aliases for clarity */
38
+ export type ExpressRequest = ExpressRequestType;
39
+ export type ExpressResponse = ExpressResponseType;
40
+ export type ExpressNextFunction = ExpressNextFunctionType;
41
+ export type ExpressApp = ExpressType;
42
+ export type ExpressRouter = RouterType;
43
+
44
+ // ============================================================================
45
+ // Express-Compatible Types (for plugins that don't want express dependency)
46
+ // These types are compatible with Express but don't require express as a dependency.
47
+ // They can be used directly in plugins or overridden with actual Express types.
48
+ // ============================================================================
49
+
50
+ /**
51
+ * Generic request type (compatible with Express Request)
52
+ */
53
+ export interface PluginRequest {
54
+ params: Record<string, string>;
55
+ query: Record<string, any>;
56
+ body: any;
57
+ headers: Record<string, string | string[] | undefined>;
58
+ method: string;
59
+ path: string;
60
+ url: string;
61
+ originalUrl: string;
62
+ baseUrl: string;
63
+ cookies?: Record<string, string>;
64
+ signedCookies?: Record<string, string>;
65
+ ip?: string;
66
+ ips?: string[];
67
+ hostname?: string;
68
+ protocol?: string;
69
+ secure?: boolean;
70
+ xhr?: boolean;
71
+ accountability?: Accountability;
72
+ get(header: string): string | undefined;
73
+ header(header: string): string | undefined;
74
+ accepts(...types: string[]): string | false;
75
+ is(type: string): string | false | null;
76
+ [key: string]: any;
77
+ }
78
+
79
+ /**
80
+ * Generic response type (compatible with Express Response)
81
+ */
82
+ export interface PluginResponse {
83
+ status(code: number): PluginResponse;
84
+ sendStatus(code: number): PluginResponse;
85
+ json(data: any): PluginResponse;
86
+ send(data: any): PluginResponse;
87
+ end(data?: any): PluginResponse;
88
+ set(header: string, value: string | string[]): PluginResponse;
89
+ set(headers: Record<string, string | string[]>): PluginResponse;
90
+ header(header: string, value: string | string[]): PluginResponse;
91
+ get(header: string): string | undefined;
92
+ type(type: string): PluginResponse;
93
+ contentType(type: string): PluginResponse;
94
+ redirect(url: string): void;
95
+ redirect(status: number, url: string): void;
96
+ cookie(name: string, value: string, options?: Record<string, any>): PluginResponse;
97
+ clearCookie(name: string, options?: Record<string, any>): PluginResponse;
98
+ attachment(filename?: string): PluginResponse;
99
+ download(path: string, filename?: string): void;
100
+ locals: Record<string, any>;
101
+ headersSent: boolean;
102
+ statusCode: number;
103
+ [key: string]: any;
104
+ }
105
+
106
+ /**
107
+ * Generic next function type (compatible with Express NextFunction)
108
+ */
109
+ export type PluginNextFunction = (error?: any) => void;
110
+
111
+ /**
112
+ * Generic Express application type
113
+ */
114
+ export interface PluginApp {
115
+ use(...handlers: any[]): PluginApp;
116
+ get(path: string, ...handlers: any[]): PluginApp;
117
+ post(path: string, ...handlers: any[]): PluginApp;
118
+ put(path: string, ...handlers: any[]): PluginApp;
119
+ patch(path: string, ...handlers: any[]): PluginApp;
120
+ delete(path: string, ...handlers: any[]): PluginApp;
121
+ options(path: string, ...handlers: any[]): PluginApp;
122
+ all(path: string, ...handlers: any[]): PluginApp;
123
+ listen(port: number, callback?: () => void): any;
124
+ set(setting: string, value: any): PluginApp;
125
+ get(setting: string): any;
126
+ locals: Record<string, any>;
127
+ [key: string]: any;
128
+ }
129
+
130
+ /**
131
+ * Generic Router type (compatible with Express Router)
132
+ */
133
+ export interface PluginRouter {
134
+ use(...handlers: any[]): PluginRouter;
135
+ get(path: string, ...handlers: any[]): PluginRouter;
136
+ post(path: string, ...handlers: any[]): PluginRouter;
137
+ put(path: string, ...handlers: any[]): PluginRouter;
138
+ patch(path: string, ...handlers: any[]): PluginRouter;
139
+ delete(path: string, ...handlers: any[]): PluginRouter;
140
+ options(path: string, ...handlers: any[]): PluginRouter;
141
+ all(path: string, ...handlers: any[]): PluginRouter;
142
+ [key: string]: any;
143
+ }
144
+
145
+ // ============================================================================
146
+ // Service Interfaces
147
+ // ============================================================================
148
+
149
+ /**
150
+ * Base service options with accountability
151
+ */
152
+ export interface ServiceOptions {
153
+ accountability?: Accountability;
154
+ [key: string]: any;
155
+ }
156
+
157
+ /**
158
+ * Items service interface for CRUD operations
159
+ * Note: Actual implementations may have additional methods and different signatures.
160
+ * The index signature provides flexibility for all implementations.
161
+ */
162
+ export interface IItemsService {
163
+ [key: string]: any;
164
+ }
165
+
166
+ /**
167
+ * Permission service interface
168
+ */
169
+ export interface IPermissionService {
170
+ [key: string]: any;
171
+ }
172
+
173
+ /**
174
+ * Mail service interface
175
+ */
176
+ export interface IMailService {
177
+ [key: string]: any;
178
+ }
179
+
180
+ /**
181
+ * Storage service interface
182
+ */
183
+ export interface IStorageService {
184
+ [key: string]: any;
185
+ }
186
+
187
+ /**
188
+ * Settings service interface
189
+ */
190
+ export interface ISettingsService {
191
+ [key: string]: any;
192
+ }
193
+
194
+ /**
195
+ * Socket service interface
196
+ */
197
+ export interface ISocketService {
198
+ [key: string]: any;
199
+ }
200
+
201
+ /**
202
+ * Realtime service interface
203
+ */
204
+ export interface IRealtimeService {
205
+ [key: string]: any;
206
+ }
207
+
208
+ /**
209
+ * Tasks service interface
210
+ */
211
+ export interface ITasksService {
212
+ [key: string]: any;
213
+ }
214
+
215
+ /**
216
+ * Workflow service interface
217
+ */
218
+ export interface IWorkflowService {
219
+ [key: string]: any;
220
+ }
221
+
222
+ /**
223
+ * Migration service interface
224
+ */
225
+ export interface IMigrationService {
226
+ [key: string]: any;
227
+ }
228
+
229
+ /**
230
+ * Hook function type - called during lifecycle events
231
+ */
232
+ export type HookFunction = (context: PluginHookContext) => Promise<PluginHookContext> | PluginHookContext;
233
+
234
+ /**
235
+ * Hooks manager interface - manages lifecycle hooks for collections
236
+ */
237
+ export interface IHooksManager {
238
+ /**
239
+ * Register a hook for a collection and event
240
+ * @param collection - Collection name (use '*' for all collections)
241
+ * @param event - Event name (e.g., 'items.create', 'items.update')
242
+ * @param hookFunction - Function to execute
243
+ */
244
+ registerHook(collection: string, event: string, hookFunction: HookFunction): void;
245
+
246
+ /**
247
+ * Get hooks for a collection and event
248
+ * @param collection - Collection name
249
+ * @param event - Event name
250
+ * @returns Array of registered hook functions
251
+ */
252
+ getHooks(collection: string, event: string): HookFunction[];
253
+
254
+ /**
255
+ * Execute hooks for a collection and event
256
+ * @param collection - Collection name
257
+ * @param event - Event name
258
+ * @param accountability - User/role accountability info
259
+ * @param context - Hook context with data
260
+ * @returns Modified context after all hooks execute
261
+ */
262
+ executeHooks(
263
+ collection: string,
264
+ event: string,
265
+ accountability: Accountability | undefined,
266
+ context: PluginHookContext
267
+ ): Promise<PluginHookContext>;
268
+
269
+ /**
270
+ * Load hooks from extensions directory
271
+ * @param context - Plugin context
272
+ * @param directory - Optional directory path
273
+ */
274
+ loadHooksFromDirectory?(context: any, directory?: string): Promise<void>;
275
+
276
+ /**
277
+ * Load schedules from extensions directory
278
+ * @param context - Plugin context
279
+ * @param schedule - Schedule manager
280
+ * @param directory - Optional directory path
281
+ */
282
+ loadSchedulesFromDirectory?(context: any, schedule: any, directory?: string): Promise<void>;
283
+
284
+ /** Allow additional methods/properties */
285
+ [key: string]: any;
286
+ }
287
+
288
+ /**
289
+ * Cache service interface
290
+ */
291
+ export interface ICacheService {
292
+ [key: string]: any;
293
+ }
294
+
295
+ /**
296
+ * Files service interface
297
+ */
298
+ export interface IFilesService {
299
+ [key: string]: any;
300
+ }
301
+
302
+ /**
303
+ * Assets service interface
304
+ */
305
+ export interface IAssetsService {
306
+ [key: string]: any;
307
+ }
308
+
309
+ /**
310
+ * Notification service interface
311
+ */
312
+ export interface INotificationService {
313
+ [key: string]: any;
314
+ }
315
+
316
+ /**
317
+ * Report service interface
318
+ */
319
+ export interface IReportService {
320
+ [key: string]: any;
321
+ }
322
+
323
+ /**
324
+ * Stats service interface
325
+ */
326
+ export interface IStatsService {
327
+ [key: string]: any;
328
+ }
329
+
330
+ // ============================================================================
331
+ // Plugin Types
332
+ // ============================================================================
333
+
334
+ /**
335
+ * Plugin types categorize plugins by their primary function
336
+ */
337
+ export type PluginType =
338
+ | "feature" // E-commerce, CMS, Blog, etc.
339
+ | "auth" // OAuth providers, OTP, Passkey, etc.
340
+ | "payment" // Stripe, PayPal, Razorpay, etc.
341
+ | "storage" // S3, GCS, Cloudinary, etc.
342
+ | "ai" // RAG, Embeddings, LLM providers, etc.
343
+ | "notification" // Email, SMS, Push, etc.
344
+ | "integration"; // Third-party integrations
345
+
346
+ /**
347
+ * Plugin metadata - information about the plugin
348
+ */
349
+ export interface PluginMeta {
350
+ /** Unique plugin name (used as identifier) */
351
+ name: string;
352
+ /** Plugin version (semver) */
353
+ version: string;
354
+ /** Plugin type/category */
355
+ type: PluginType;
356
+ /** Human-readable description */
357
+ description?: string;
358
+ /** Plugin author */
359
+ author?: string;
360
+ /** Plugin dependencies (names of other plugins that must be loaded first) */
361
+ dependencies?: string[];
362
+ }
363
+
364
+ /**
365
+ * Schema definition for plugin collections
366
+ */
367
+ export interface PluginSchemaDefinition {
368
+ collectionName: string;
369
+ schema: SchemaDefinition;
370
+ }
371
+
372
+ /**
373
+ * Plugin route handler context - available in route handlers
374
+ */
375
+ export interface PluginRouteContext {
376
+ /** Database connection */
377
+ db: any;
378
+ /** ItemsService class for CRUD operations */
379
+ ItemsService: new (...args: any[]) => IItemsService;
380
+ /** Registered plugin services */
381
+ services: Record<string, any>;
382
+ /** Permission service (singleton) */
383
+ permissionService?: IPermissionService;
384
+ /** Mail service (singleton) */
385
+ mailService?: IMailService;
386
+ /** Storage service (singleton) */
387
+ storageService?: IStorageService;
388
+ /** Settings service (singleton) */
389
+ settingsService?: ISettingsService;
390
+ /** Socket service (singleton) */
391
+ socketService?: ISocketService;
392
+ /** Realtime service (singleton) */
393
+ realtimeService?: IRealtimeService;
394
+ /** Tasks service (singleton) */
395
+ tasksService?: ITasksService;
396
+ /** Workflow service (singleton) */
397
+ workflowService?: IWorkflowService;
398
+ /** Migration service (singleton) */
399
+ migrationService?: IMigrationService;
400
+ /** Get cache service instance */
401
+ getCacheService?: () => ICacheService;
402
+ /** FilesService class */
403
+ FilesService?: new (...args: any[]) => IFilesService;
404
+ /** AssetsService class */
405
+ AssetsService?: new (...args: any[]) => IAssetsService;
406
+ /** NotificationService class */
407
+ NotificationService?: new (...args: any[]) => INotificationService;
408
+ /** ReportService class */
409
+ ReportService?: new (...args: any[]) => IReportService;
410
+ /** StatsService class */
411
+ StatsService?: new (...args: any[]) => IStatsService;
412
+ /** Plugin configuration */
413
+ config: Record<string, any>;
414
+ }
415
+
416
+ /**
417
+ * Plugin route handler function
418
+ */
419
+ export type PluginRouteHandler<TReq = PluginRequest, TRes = PluginResponse> = (
420
+ req: TReq,
421
+ res: TRes,
422
+ context: PluginRouteContext
423
+ ) => Promise<any> | any;
424
+
425
+ /**
426
+ * Plugin route definition
427
+ */
428
+ export interface PluginRoute<TReq = PluginRequest, TRes = PluginResponse> {
429
+ /** Route path (e.g., '/payments/stripe/checkout') */
430
+ path: string;
431
+ /** HTTP method */
432
+ method: HttpMethod;
433
+ /** Route handler */
434
+ handler: PluginRouteHandler<TReq, TRes>;
435
+ /** Whether authentication is required */
436
+ requireAuth?: boolean;
437
+ /** Whether to parse raw body (for webhooks) */
438
+ rawBody?: boolean;
439
+ /** Custom middleware for this route */
440
+ middleware?: Array<(req: TReq, res: TRes, next: PluginNextFunction) => void>;
441
+ /** Route description for documentation */
442
+ description?: string;
443
+ }
444
+
445
+ /**
446
+ * Plugin hook event types
447
+ */
448
+ export type PluginHookEvent =
449
+ | "items.create"
450
+ | "items.read"
451
+ | "items.update"
452
+ | "items.delete"
453
+ | "items.create.after"
454
+ | "items.read.after"
455
+ | "items.update.after"
456
+ | "items.delete.after";
457
+
458
+ /**
459
+ * Plugin hook context - passed to hook handlers
460
+ * All properties are optional to allow flexibility in different contexts
461
+ */
462
+ export interface PluginHookContext {
463
+ collection?: string;
464
+ accountability?: Accountability;
465
+ db?: any;
466
+ data?: any;
467
+ id?: string | number;
468
+ query?: any;
469
+ schema?: any;
470
+ transaction?: any;
471
+ [key: string]: any;
472
+ }
473
+
474
+ /**
475
+ * Plugin hook handler function
476
+ */
477
+ export type PluginHookHandler = (
478
+ context: PluginHookContext
479
+ ) => Promise<PluginHookContext> | PluginHookContext;
480
+
481
+ /**
482
+ * Plugin hook definition
483
+ */
484
+ export interface PluginHook {
485
+ /** Collection name (use '*' for all collections) */
486
+ collection: string;
487
+ /** Hook event */
488
+ event: PluginHookEvent;
489
+ /** Hook handler */
490
+ handler: PluginHookHandler;
491
+ /** Hook priority (lower runs first) */
492
+ priority?: number;
493
+ }
494
+
495
+ /**
496
+ * Plugin context - passed to lifecycle hooks and service factories
497
+ */
498
+ export interface PluginContext extends PluginRouteContext {
499
+ /** Hooks manager (singleton) */
500
+ hooksManager?: IHooksManager;
501
+ /** Invalidate cache for a collection */
502
+ invalidateCache?: (collection?: string) => Promise<void>;
503
+ /** Express app instance (when available) */
504
+ app?: PluginApp;
505
+ /** Get another plugin's service */
506
+ getPluginService: (pluginName: string, serviceName: string) => any;
507
+ }
508
+
509
+ /**
510
+ * Plugin service factory function
511
+ */
512
+ export type PluginServiceFactory = (context: PluginContext) => any;
513
+
514
+ /**
515
+ * Plugin service definition
516
+ */
517
+ export interface PluginService {
518
+ /** Service name (used to access via context.services.name) */
519
+ name: string;
520
+ /** Service factory function */
521
+ factory: PluginServiceFactory;
522
+ }
523
+
524
+ /**
525
+ * Plugin auth provider type
526
+ */
527
+ export type AuthProviderType = "oauth2" | "otp" | "passkey" | "custom";
528
+
529
+ /**
530
+ * OAuth2 configuration
531
+ */
532
+ export interface OAuth2Config {
533
+ authorizationUrl: string;
534
+ tokenUrl: string;
535
+ userInfoUrl: string;
536
+ clientId: string;
537
+ clientSecret: string;
538
+ scope?: string[];
539
+ }
540
+
541
+ /**
542
+ * Plugin auth provider definition
543
+ */
544
+ export interface PluginAuthProvider {
545
+ /** Provider identifier (e.g., 'github', 'otp') */
546
+ id: string;
547
+ /** Display name */
548
+ name: string;
549
+ /** Provider type */
550
+ type: AuthProviderType;
551
+ /** OAuth2 configuration (for oauth2 type) */
552
+ oauth2Config?: OAuth2Config;
553
+ /** Custom authentication handler */
554
+ authenticate?: (
555
+ credentials: Record<string, any>,
556
+ context: PluginContext
557
+ ) => Promise<{ user: any; account?: any } | null>;
558
+ /** Custom routes for this provider */
559
+ routes?: PluginRoute[];
560
+ }
561
+
562
+ /**
563
+ * Plugin middleware definition
564
+ */
565
+ export interface PluginMiddleware<TReq = PluginRequest, TRes = PluginResponse> {
566
+ /** Middleware name (for debugging) */
567
+ name: string;
568
+ /** Path pattern (optional, defaults to all routes) */
569
+ path?: string;
570
+ /** Middleware handler */
571
+ handler: (req: TReq, res: TRes, next: PluginNextFunction) => void;
572
+ /** Priority (lower runs first) */
573
+ priority?: number;
574
+ }
575
+
576
+ /**
577
+ * Plugin schedule definition
578
+ */
579
+ export interface PluginSchedule {
580
+ /** Schedule name */
581
+ name: string;
582
+ /** Cron expression */
583
+ cron: string;
584
+ /** Schedule handler */
585
+ handler: (context: PluginContext) => Promise<void> | void;
586
+ /** Whether to run immediately on startup */
587
+ runOnStart?: boolean;
588
+ }
589
+
590
+ /**
591
+ * Plugin definition - what a plugin provides
592
+ */
593
+ export interface PluginDefinition {
594
+ /** Plugin metadata */
595
+ meta: PluginMeta;
596
+ /** Schema extensions - new collections/tables */
597
+ schemas?: PluginSchemaDefinition[];
598
+ /** Route extensions - new API endpoints */
599
+ routes?: PluginRoute[];
600
+ /** Hook extensions - lifecycle hooks */
601
+ hooks?: PluginHook[];
602
+ /** Service extensions - new services */
603
+ services?: PluginService[];
604
+ /** Auth provider extensions */
605
+ authProviders?: PluginAuthProvider[];
606
+ /** Middleware extensions */
607
+ middleware?: PluginMiddleware[];
608
+ /** Scheduled tasks */
609
+ schedules?: PluginSchedule[];
610
+ /** Called when the plugin is initialized */
611
+ onInit?: (context: PluginContext) => Promise<void>;
612
+ /** Called when all plugins are loaded and server is ready */
613
+ onReady?: (context: PluginContext) => Promise<void>;
614
+ /** Called when the server is shutting down */
615
+ onShutdown?: (context: PluginContext) => Promise<void>;
616
+ }
617
+
618
+ /**
619
+ * Plugin factory function - creates a plugin with configuration
620
+ */
621
+ export type PluginFactory<TConfig = Record<string, any>> = (
622
+ config: TConfig
623
+ ) => PluginDefinition;
624
+
625
+ /**
626
+ * Baasix plugin type
627
+ */
628
+ export type BaasixPlugin = PluginDefinition;
629
+
630
+ /**
631
+ * Loaded plugin - plugin with runtime state
632
+ */
633
+ export interface LoadedPlugin {
634
+ /** Plugin definition */
635
+ definition: PluginDefinition;
636
+ /** Plugin configuration */
637
+ config: Record<string, any>;
638
+ /** Plugin services (instantiated) */
639
+ services: Record<string, any>;
640
+ /** Whether the plugin has been initialized */
641
+ initialized: boolean;
642
+ /** Whether the plugin is ready */
643
+ ready: boolean;
644
+ }
645
+
646
+ /**
647
+ * Plugin manager options
648
+ */
649
+ export interface PluginManagerOptions {
650
+ /** Whether to log plugin loading */
651
+ verbose?: boolean;
652
+ }
653
+
654
+ /**
655
+ * Start server options with plugin support
656
+ */
657
+ export interface StartServerOptions {
658
+ /** Server port */
659
+ port?: number;
660
+ /** Plugins to load */
661
+ plugins?: BaasixPlugin[];
662
+ /** Plugin manager options */
663
+ pluginOptions?: PluginManagerOptions;
664
+ }
665
+
666
+ // ============================================================================
667
+ // Express-Typed Plugin Types
668
+ // These types use actual Express types for core package usage.
669
+ // Plugins that don't want express dependency should use the generic versions above.
670
+ // ============================================================================
671
+
672
+ /**
673
+ * Plugin route handler function with Express types
674
+ */
675
+ export type ExpressPluginRouteHandler = (
676
+ req: Request,
677
+ res: Response,
678
+ context: PluginRouteContext
679
+ ) => Promise<any> | any;
680
+
681
+ /**
682
+ * Plugin route definition with Express types
683
+ */
684
+ export interface ExpressPluginRoute extends Omit<PluginRoute, 'handler' | 'middleware'> {
685
+ /** Route handler */
686
+ handler: ExpressPluginRouteHandler;
687
+ /** Custom middleware for this route */
688
+ middleware?: Array<(req: Request, res: Response, next: NextFunction) => void>;
689
+ }
690
+
691
+ /**
692
+ * Plugin middleware definition with Express types
693
+ */
694
+ export interface ExpressPluginMiddleware extends Omit<PluginMiddleware, 'handler'> {
695
+ /** Middleware handler */
696
+ handler: (req: Request, res: Response, next: NextFunction) => void;
697
+ }
698
+
699
+ /**
700
+ * Plugin context with Express types
701
+ */
702
+ export interface ExpressPluginContext extends PluginRouteContext {
703
+ /** Hooks manager (singleton) - lifecycle hooks for collections */
704
+ hooksManager?: IHooksManager;
705
+ /** Invalidate cache for a collection */
706
+ invalidateCache?: (collection?: string) => Promise<void>;
707
+ /** Express app instance */
708
+ app?: Express;
709
+ /** Get another plugin's service */
710
+ getPluginService: (pluginName: string, serviceName: string) => any;
711
+ }