webspresso 0.0.98 → 0.0.100

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 (88) hide show
  1. package/.agents/ADMIN.md +11 -1
  2. package/.agents/AGENTS.md +2 -2
  3. package/.agents/AUTH.md +415 -0
  4. package/.agents/CLI.md +47 -0
  5. package/.agents/ERRORS.md +59 -0
  6. package/.agents/ORM.md +178 -4
  7. package/.agents/PLUGINS.md +113 -8
  8. package/.agents/QUEUE.md +92 -0
  9. package/.agents/ROUTING.md +160 -7
  10. package/.agents/STREAMING.md +35 -0
  11. package/AGENTS.md +2 -0
  12. package/README.md +145 -93
  13. package/bin/commands/add-docker.js +467 -0
  14. package/bin/commands/deploy-check.js +339 -0
  15. package/bin/webspresso.js +4 -0
  16. package/core/auth/index.js +123 -1
  17. package/core/auth/magic-link.js +170 -0
  18. package/core/auth/manager.js +477 -3
  19. package/core/auth/middleware.js +118 -5
  20. package/core/auth/oauth.js +517 -0
  21. package/core/auth/qrcode.js +499 -0
  22. package/core/auth/session-manager.js +255 -0
  23. package/core/auth/sessions.js +351 -0
  24. package/core/auth/tokens.js +1 -0
  25. package/core/auth/totp.js +507 -0
  26. package/core/auth/user-agent.js +161 -0
  27. package/core/orm/eager-loader.js +144 -10
  28. package/core/orm/index.js +10 -1
  29. package/core/orm/model.js +55 -1
  30. package/core/orm/query-builder.js +90 -4
  31. package/core/orm/repository.js +327 -16
  32. package/core/orm/scopes.js +3 -2
  33. package/core/orm/search.js +213 -0
  34. package/core/orm/types.js +6 -1
  35. package/core/queue/cron.js +544 -0
  36. package/core/queue/index.js +8 -1
  37. package/core/queue/manager.js +100 -1
  38. package/core/queue/scheduler.js +415 -0
  39. package/core/sse/index.js +19 -0
  40. package/core/sse/stream.js +430 -0
  41. package/core/ssr/stream.js +62 -2
  42. package/index.d.ts +794 -6
  43. package/index.js +48 -0
  44. package/package.json +7 -5
  45. package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +323 -31
  46. package/plugins/admin-panel/client/parts/08-record-list.js +5 -0
  47. package/plugins/admin-panel/client/verify-spa-parts.js +2 -0
  48. package/plugins/admin-panel/field-renderers/file-upload.js +187 -104
  49. package/plugins/admin-panel/field-renderers/index.js +2 -0
  50. package/plugins/admin-panel/modules/admin-users.js +1 -1
  51. package/plugins/api-key/crypto.js +101 -0
  52. package/plugins/api-key/index.js +288 -0
  53. package/plugins/api-key/middleware.js +461 -0
  54. package/plugins/api-key/migration-template.js +48 -0
  55. package/plugins/api-key/model.js +50 -0
  56. package/plugins/api-key/scopes.js +125 -0
  57. package/plugins/audit-log/admin-component.js +487 -70
  58. package/plugins/audit-log/api-handlers.js +114 -0
  59. package/plugins/audit-log/index.js +24 -0
  60. package/plugins/content/client/inline-edit.js +2 -46
  61. package/plugins/cors.js +13 -2
  62. package/plugins/email/auth-bridge.js +66 -0
  63. package/plugins/email/bundled-templates.js +15 -0
  64. package/plugins/email/templates/auth-magic-link.mjml +13 -0
  65. package/plugins/file-manager/admin-component.js +69 -53
  66. package/plugins/file-manager/index.js +25 -8
  67. package/plugins/index.js +8 -0
  68. package/plugins/oauth/index.js +338 -0
  69. package/plugins/queue/index.js +4 -0
  70. package/plugins/webhooks/admin-component.js +608 -0
  71. package/plugins/webhooks/api-handlers.js +237 -0
  72. package/plugins/webhooks/crypto.js +144 -0
  73. package/plugins/webhooks/dispatcher.js +708 -0
  74. package/plugins/webhooks/index.js +263 -0
  75. package/plugins/webhooks/matcher.js +113 -0
  76. package/plugins/webhooks/migration-template.js +75 -0
  77. package/plugins/webhooks/models.js +98 -0
  78. package/plugins/webhooks/sender.js +176 -0
  79. package/src/api/api-loader.js +1 -0
  80. package/src/bundle/index.js +2 -1
  81. package/src/discovery/file-route-parser.js +44 -1
  82. package/src/discovery/scan-routes.js +2 -2
  83. package/src/file-router.js +310 -104
  84. package/src/helpers.js +16 -1
  85. package/src/njk-frontmatter.js +3 -0
  86. package/src/routing/cascading.js +490 -0
  87. package/src/routing/middleware-resolver.js +92 -0
  88. package/src/server.js +6 -0
package/index.d.ts CHANGED
@@ -541,8 +541,70 @@ export function mountPages(
541
541
  registerDynamicFileRoutes: () => void;
542
542
  };
543
543
 
544
+ export interface CascadingLayoutInfo {
545
+ layoutRelPath: string;
546
+ fullPath: string;
547
+ configPath: string | null;
548
+ }
549
+
550
+ export interface CascadingErrorBoundaryInfo {
551
+ dirSegment: string;
552
+ errorRelPath: string;
553
+ fullPath: string;
554
+ configPath: string | null;
555
+ }
556
+
557
+ export interface CascadingLoadingInfo {
558
+ dirSegment: string;
559
+ loadingRelPath: string;
560
+ fullPath: string;
561
+ }
562
+
563
+ export namespace cascading {
564
+ export function getDirectoryChain(relativeFilePath: string): string[];
565
+ export function templateHasExtends(templateBody?: string | null, fullPath?: string): boolean;
566
+ export function findCascadingMiddlewareFiles(baseDir: string, relativeFilePath: string, isDev?: boolean): string[];
567
+ export function loadCascadingMiddlewares(
568
+ baseDir: string,
569
+ relativeFilePath: string,
570
+ middlewareRegistry?: Record<string, unknown>,
571
+ isDev?: boolean
572
+ ): Array<(req: any, res: any, next: (err?: any) => void) => void>;
573
+ export function runMiddleware(mw: Function, req: any, res: any): Promise<void>;
574
+ export function runMiddlewareChain(chain: Function[], req: any, res: any): Promise<void>;
575
+ export function findCascadingLayouts(baseDir: string, relativeFilePath: string, isDev?: boolean): CascadingLayoutInfo[];
576
+ export function executeCascadingLayoutLoads(layouts: CascadingLayoutInfo[], req: any, ctx: any, isDev?: boolean): Promise<void>;
577
+ export function applyCascadingLayouts(
578
+ nunjucksEnv: any,
579
+ layouts: CascadingLayoutInfo[],
580
+ pageHtml: string,
581
+ renderContext: Record<string, unknown>,
582
+ isDev?: boolean
583
+ ): string;
584
+ export function findNearestErrorBoundary(
585
+ baseDir: string,
586
+ relativeFilePath: string,
587
+ isDev?: boolean
588
+ ): CascadingErrorBoundaryInfo | null;
589
+ export function findNearestLoadingTemplate(
590
+ baseDir: string,
591
+ relativeFilePath: string,
592
+ isDev?: boolean
593
+ ): CascadingLoadingInfo | null;
594
+ export function clearCascadingCaches(): void;
595
+ }
596
+
597
+ export function resolveMiddlewares(
598
+ middlewareConfig: unknown[] | null | undefined,
599
+ middlewareRegistry?: Record<string, unknown>
600
+ ): Array<(req: any, res: any, next: (err?: any) => void) => void>;
601
+
544
602
  export function filePathToRoute(filePath: string, pagesDir: string): string;
545
603
 
604
+ export function isRouteGroupSegment(segment: string): boolean;
605
+
606
+ export function stripRouteGroups(route: string): string;
607
+
546
608
  export function extractMethodFromFilename(filename: string): {
547
609
  method: string;
548
610
  baseName: string;
@@ -706,11 +768,20 @@ export interface ScopeContext {
706
768
 
707
769
  export type RelationType = 'belongsTo' | 'hasMany' | 'hasOne';
708
770
 
771
+ export type RelationCascadeOption =
772
+ | boolean
773
+ | 'delete'
774
+ | 'restore'
775
+ | 'all'
776
+ | ('delete' | 'restore' | 'all')[]
777
+ | { delete?: boolean; restore?: boolean };
778
+
709
779
  export interface RelationDefinition {
710
780
  type: RelationType;
711
- model: () => ModelDefinition;
781
+ model: string | (() => ModelDefinition<any> | string);
712
782
  foreignKey: string;
713
783
  localKey?: string;
784
+ cascade?: RelationCascadeOption;
714
785
  }
715
786
 
716
787
  export interface AdminPermissions {
@@ -864,6 +935,7 @@ export interface ModelOptions<TSchema extends ZodObject<any> = ZodObject<Record<
864
935
  maxIncludes?: number;
865
936
  maxFilterConditions?: number;
866
937
  };
938
+ searchable?: string[];
867
939
  cache?: boolean | 'auto' | 'smart' | { strategy: 'auto' | 'smart' };
868
940
  }
869
941
 
@@ -898,6 +970,7 @@ export interface ModelDefinition<TModel = Record<string, any>> {
898
970
  maxIncludes?: number;
899
971
  maxFilterConditions?: number;
900
972
  };
973
+ searchable?: string[];
901
974
  hooks: Record<string, unknown>;
902
975
  cache?: boolean | 'auto' | 'smart' | { strategy: 'auto' | 'smart' };
903
976
  }
@@ -914,6 +987,8 @@ export function hasModel(name: string): boolean;
914
987
 
915
988
  export function clearRegistry(): void;
916
989
 
990
+ export function isCascadeEnabled(relation: RelationDefinition, operation: 'delete' | 'restore'): boolean;
991
+
917
992
  // --- ORM: schema & columns ---
918
993
 
919
994
  /** zdb column helpers (id, string, timestamp, …) + `schema()` */
@@ -934,7 +1009,10 @@ export function getColumnMeta(schema: ZodTypeAny): unknown;
934
1009
 
935
1010
  export interface FindOptions {
936
1011
  with?: string[];
1012
+ include?: string[];
937
1013
  select?: string[];
1014
+ limit?: number;
1015
+ offset?: number;
938
1016
  }
939
1017
 
940
1018
  export interface PaginatedResult<T = Record<string, any>> {
@@ -945,6 +1023,16 @@ export interface PaginatedResult<T = Record<string, any>> {
945
1023
  totalPages: number;
946
1024
  }
947
1025
 
1026
+ export interface SearchOptions {
1027
+ mode?: 'auto' | 'fts' | 'like';
1028
+ language?: string;
1029
+ matchAllWords?: boolean;
1030
+ exact?: boolean;
1031
+ rank?: boolean;
1032
+ ftsTable?: string;
1033
+ boolean?: 'and' | 'or';
1034
+ }
1035
+
948
1036
  export interface QueryBuilder<T = Record<string, any>> {
949
1037
  where(column: keyof T | string, value: unknown): this;
950
1038
  where(column: keyof T | string, operator: string, value: unknown): this;
@@ -954,14 +1042,19 @@ export interface QueryBuilder<T = Record<string, any>> {
954
1042
  whereBetween(column: keyof T | string, range: [unknown, unknown]): this;
955
1043
  select(...columns: (keyof T | string)[]): this;
956
1044
  orderBy(column: keyof T | string, direction?: 'asc' | 'desc'): this;
1045
+ orderByRaw(sql: string, bindings?: unknown[]): this;
1046
+ search(term: string, columns?: string | string[], options?: SearchOptions): this;
1047
+ orSearch(term: string, columns?: string | string[], options?: SearchOptions): this;
957
1048
  limit(n: number): this;
958
1049
  offset(n: number): this;
959
1050
  with(...relations: string[]): this;
1051
+ include(...relations: string[]): this;
960
1052
  withTrashed(): this;
961
1053
  onlyTrashed(): this;
962
1054
  first(): Promise<T | null>;
963
1055
  list(): Promise<T[]>;
964
1056
  get(): Promise<T[]>;
1057
+ find(): Promise<T[]>;
965
1058
  count(): Promise<number>;
966
1059
  paginate(page?: number, perPage?: number): Promise<PaginatedResult<T>>;
967
1060
  exists(): Promise<boolean>;
@@ -976,18 +1069,21 @@ export interface Repository<T = Record<string, any>> {
976
1069
  findById(id: string | number, options?: FindOptions): Promise<T | null>;
977
1070
  findOne(conditions: Partial<T> | Record<string, unknown>, options?: FindOptions): Promise<T | null>;
978
1071
  findAll(options?: FindOptions): Promise<T[]>;
1072
+ find(conditions?: Partial<T> | Record<string, unknown>, options?: FindOptions): Promise<T[]>;
979
1073
  create(data: Partial<T> | Record<string, unknown>): Promise<T>;
980
1074
  createMany(data: (Partial<T> | Record<string, unknown>)[]): Promise<T[]>;
981
1075
  update(id: string | number, data: Partial<T> | Record<string, unknown>): Promise<T | null>;
982
1076
  updateWhere(conditions: Partial<T> | Record<string, unknown>, data: Partial<T> | Record<string, unknown>): Promise<number>;
983
- delete(id: string | number): Promise<boolean>;
984
- forceDelete(id: string | number): Promise<boolean>;
985
- restore(id: string | number): Promise<T | null>;
1077
+ delete(id: string | number, options?: { cascade?: boolean; deletedAt?: Date }): Promise<boolean>;
1078
+ forceDelete(id: string | number, options?: { cascade?: boolean }): Promise<boolean>;
1079
+ restore(id: string | number, options?: { cascade?: boolean; allChildren?: boolean }): Promise<T | null>;
986
1080
  query(): QueryBuilder<T>;
987
1081
  raw(sql: string, bindings?: unknown[]): Promise<unknown>;
988
1082
  count(conditions?: Partial<T> | Record<string, unknown>): Promise<number>;
989
1083
  exists(conditions: Partial<T> | Record<string, unknown>): Promise<boolean>;
990
1084
  with(...relations: string[]): QueryBuilder<T>;
1085
+ include(...relations: string[]): QueryBuilder<T>;
1086
+ search(term: string, columns?: string | string[], options?: SearchOptions): QueryBuilder<T>;
991
1087
  model: ModelDefinition<T>;
992
1088
  }
993
1089
 
@@ -1208,6 +1304,24 @@ export function validateQueryComplexity(
1208
1304
  includes: string[];
1209
1305
  };
1210
1306
 
1307
+ export function buildSearchClause(params: {
1308
+ knex: any;
1309
+ model: any;
1310
+ term: string;
1311
+ columns?: string | string[];
1312
+ options?: SearchOptions;
1313
+ }): {
1314
+ raw: true;
1315
+ sql: string;
1316
+ bindings: any[];
1317
+ boolean: 'and' | 'or';
1318
+ rankClause: { sql: string; bindings: any[] } | null;
1319
+ } | null;
1320
+
1321
+ export function tokenizeSearchTerm(term: string): string[];
1322
+
1323
+ export function detectDialect(knex: any): 'sqlite' | 'postgres' | 'mysql' | 'generic';
1324
+
1211
1325
  export interface SchemaExplorerPluginOptions {
1212
1326
  /** Raw JSON API endpoint path (default: '/_schema') */
1213
1327
  path?: string;
@@ -1374,6 +1488,7 @@ export interface AuditLogPluginOptions {
1374
1488
  tableName?: string;
1375
1489
  includeDefaultPage?: boolean;
1376
1490
  apiPrefix?: string;
1491
+ registerRecordAction?: boolean;
1377
1492
  retentionDays?: number;
1378
1493
  cleanupIntervalMs?: number;
1379
1494
  autoCleanup?: boolean;
@@ -1391,6 +1506,8 @@ export function auditLogPlugin(options?: AuditLogPluginOptions): WebspressoPlugi
1391
1506
  stopCleanup(): void;
1392
1507
  getRetentionConfig(): AuditLogRetentionConfig;
1393
1508
  queryLogs(filters?: Record<string, unknown>): Promise<any[]>;
1509
+ queryTimeline(model: string, recordId: string | number): Promise<any[]>;
1510
+ getRecordTimeline(model: string, recordId: string | number): Promise<any[]>;
1394
1511
  getMigrationTemplate(tableName?: string): string;
1395
1512
  };
1396
1513
  dispose?(): void;
@@ -1632,6 +1749,162 @@ export interface BasicAuthPluginOptions {
1632
1749
 
1633
1750
  export function basicAuthPlugin(options?: BasicAuthPluginOptions): WebspressoPlugin;
1634
1751
 
1752
+ export interface ApiKeyRecord {
1753
+ id?: number | string;
1754
+ name: string;
1755
+ key_hash: string;
1756
+ key_hint: string;
1757
+ prefix?: string;
1758
+ user_id?: number | string | null;
1759
+ scopes?: string[] | string | null;
1760
+ rate_limit?: number | null;
1761
+ metadata?: any;
1762
+ expires_at?: Date | string | null;
1763
+ last_used_at?: Date | string | null;
1764
+ revoked_at?: Date | string | null;
1765
+ created_at?: Date | string;
1766
+ updated_at?: Date | string;
1767
+ user?: any;
1768
+ [key: string]: any;
1769
+ }
1770
+
1771
+ export interface ApiKeyPluginOptions {
1772
+ /** Database instance or Knex instance. */
1773
+ db?: any;
1774
+ /** Knex instance. */
1775
+ knex?: any;
1776
+ /** Table name for API keys. Default 'api_keys'. */
1777
+ tableName?: string;
1778
+ /** Default key prefix. Default 'wsp_live_'. */
1779
+ prefix?: string;
1780
+ /** Random byte length for key generation. Default 24. */
1781
+ byteLength?: number;
1782
+ /** Protect all matching routes globally. Default false. */
1783
+ global?: boolean;
1784
+ /** Route prefixes to protect when global: true. Default true (all routes). */
1785
+ routes?: string | string[] | boolean;
1786
+ /** Path prefixes to bypass authentication. */
1787
+ skipPaths?: string[];
1788
+ /** Custom predicate function to skip authentication. */
1789
+ skip?: (req: Request) => boolean;
1790
+ /** Static in-memory keys for testing, serverless, or microservices. */
1791
+ keys?: Array<{ key?: string; key_hash?: string; name?: string; scopes?: string[] | string; [key: string]: any }> | Record<string, any>;
1792
+ /** Automatically update last_used_at timestamp. Default true. */
1793
+ trackUsage?: boolean;
1794
+ /** Throttle interval in milliseconds for last_used_at updates. Default 60000. */
1795
+ updateLastUsedThrottleMs?: number;
1796
+ /** Allow query parameter extraction (?apiKey=...). Default false. */
1797
+ allowQueryParam?: boolean;
1798
+ /** Query parameter name. Default 'apiKey'. */
1799
+ queryParamName?: string;
1800
+ /** Custom key extraction function. */
1801
+ extractKey?: (req: Request) => string | null;
1802
+ /** Custom key lookup by SHA-256 hash. */
1803
+ findKeyByHash?: (hash: string, req?: Request) => Promise<ApiKeyRecord | null> | ApiKeyRecord | null;
1804
+ /** Custom verification hook. */
1805
+ verify?: (rawKey: string, req?: Request) => Promise<ApiKeyRecord | null> | ApiKeyRecord | null;
1806
+ /** Custom user loader for key. */
1807
+ getUser?: (record: ApiKeyRecord, req?: Request) => Promise<any> | any;
1808
+ /** Callback hook on successful authentication. */
1809
+ onAuthenticated?: (req: Request, record: ApiKeyRecord) => void | Promise<void>;
1810
+ /** Custom 401 Unauthorized response handler, string, or object. */
1811
+ unauthorizedResponse?: ((req: Request, res: Response, info?: any) => unknown) | string | Record<string, unknown>;
1812
+ /** Custom 403 Forbidden response handler, string, or object. */
1813
+ forbiddenResponse?: ((req: Request, res: Response, info?: any) => unknown) | string | Record<string, unknown>;
1814
+ }
1815
+
1816
+ export interface ApiKeyRouteOptions {
1817
+ /** Required scope(s) for this route. Supports wildcards ('*', 'reports:*'). */
1818
+ scopes?: string | string[];
1819
+ /** Whether all required scopes must be present (true) or any scope (false). Default true. */
1820
+ requireAllScopes?: boolean;
1821
+ /** If true, allows requests without API key to pass through without error. Default false. */
1822
+ optional?: boolean;
1823
+ /** Custom 401 Unauthorized response. */
1824
+ unauthorizedResponse?: ((req: Request, res: Response, info?: any) => unknown) | string | Record<string, unknown>;
1825
+ /** Custom 403 Forbidden response. */
1826
+ forbiddenResponse?: ((req: Request, res: Response, info?: any) => unknown) | string | Record<string, unknown>;
1827
+ }
1828
+
1829
+ export function apiKeyPlugin(options?: ApiKeyPluginOptions): WebspressoPlugin;
1830
+ export function createApiKeyMiddleware(options?: ApiKeyPluginOptions & ApiKeyRouteOptions): RequestHandler;
1831
+
1832
+ export interface WebhookEndpoint {
1833
+ id?: number | string;
1834
+ name: string;
1835
+ url: string;
1836
+ secret?: string;
1837
+ events?: string[] | string;
1838
+ is_active?: boolean;
1839
+ description?: string | null;
1840
+ headers?: Record<string, string> | string | null;
1841
+ metadata?: Record<string, any> | string | null;
1842
+ created_at?: Date | string;
1843
+ updated_at?: Date | string;
1844
+ [key: string]: any;
1845
+ }
1846
+
1847
+ export interface WebhookDelivery {
1848
+ id?: number | string;
1849
+ endpoint_id: number | string;
1850
+ event: string;
1851
+ payload: string;
1852
+ status_code?: number | null;
1853
+ success: boolean;
1854
+ duration_ms?: number | null;
1855
+ error?: string | null;
1856
+ response_body?: string | null;
1857
+ attempt?: number;
1858
+ max_attempts?: number;
1859
+ next_retry_at?: Date | string | null;
1860
+ created_at?: Date | string;
1861
+ updated_at?: Date | string;
1862
+ [key: string]: any;
1863
+ }
1864
+
1865
+ export interface WebhooksPluginOptions {
1866
+ db?: any;
1867
+ knex?: any;
1868
+ endpointsTable?: string;
1869
+ deliveriesTable?: string;
1870
+ maxAttempts?: number;
1871
+ backoffBaseMs?: number;
1872
+ timeoutMs?: number;
1873
+ wrapPayload?: boolean;
1874
+ queue?: any;
1875
+ endpoints?: WebhookEndpoint[];
1876
+ apiPrefix?: string;
1877
+ includeDefaultPage?: boolean;
1878
+ pageTitle?: string;
1879
+ menuOrder?: number;
1880
+ }
1881
+
1882
+ export interface WebhookDispatchResult {
1883
+ dispatched: number;
1884
+ deliveries: WebhookDelivery[];
1885
+ results?: Array<{ success?: boolean; statusCode?: number; error?: string; [key: string]: any }>;
1886
+ }
1887
+
1888
+ export interface WebhookDispatcherInstance {
1889
+ dispatch(event: string, payload: any, options?: { wait?: boolean; endpointId?: number | string }): Promise<WebhookDispatchResult>;
1890
+ pingEndpoint(endpointId: number | string): Promise<any>;
1891
+ retryDelivery(deliveryId: number | string): Promise<any>;
1892
+ createEndpoint(data: Partial<WebhookEndpoint>): Promise<WebhookEndpoint>;
1893
+ getEndpoint(id: number | string): Promise<WebhookEndpoint | null>;
1894
+ updateEndpoint(id: number | string, data: Partial<WebhookEndpoint>): Promise<WebhookEndpoint | null>;
1895
+ deleteEndpoint(id: number | string): Promise<boolean>;
1896
+ listEndpoints(filters?: { active?: boolean; search?: string; limit?: number; offset?: number }): Promise<WebhookEndpoint[]>;
1897
+ listDeliveries(filters?: { endpointId?: number | string; event?: string; success?: boolean | string; page?: number; limit?: number }): Promise<{ items: WebhookDelivery[]; total: number; page: number; limit: number; pages: number }>;
1898
+ getDelivery(id: number | string): Promise<WebhookDelivery | null>;
1899
+ purgeDeliveries(options?: { days?: number }): Promise<number>;
1900
+ dispose(): void;
1901
+ on(event: string, listener: (...args: any[]) => void): this;
1902
+ }
1903
+
1904
+ export function webhooksPlugin(options?: WebhooksPluginOptions): WebspressoPlugin & {
1905
+ dispatcher: WebhookDispatcherInstance;
1906
+ };
1907
+
1635
1908
  export interface ContentPluginOptions {
1636
1909
  db: import('./index').Database;
1637
1910
  adminPath?: string;
@@ -2117,6 +2390,82 @@ export interface QueueRetentionConfig {
2117
2390
  runOnStart?: boolean;
2118
2391
  }
2119
2392
 
2393
+ export interface ScheduleOptions {
2394
+ id?: string;
2395
+ overlap?: boolean;
2396
+ preventOverlap?: boolean;
2397
+ maxRuns?: number;
2398
+ utc?: boolean;
2399
+ timezone?: string;
2400
+ tz?: string;
2401
+ runImmediately?: boolean;
2402
+ delay?: number | Date;
2403
+ attempts?: number;
2404
+ priority?: number;
2405
+ timeout?: number;
2406
+ backoff?: number | { type?: 'exponential' | 'fixed'; delay?: number };
2407
+ [key: string]: unknown;
2408
+ }
2409
+
2410
+ export interface ScheduleInfo {
2411
+ id: string;
2412
+ name: string;
2413
+ cronExpression: string;
2414
+ cron?: CronExpression;
2415
+ data: unknown;
2416
+ options: ScheduleOptions;
2417
+ runsCount: number;
2418
+ lastRunAt: Date | null;
2419
+ nextRunAt: Date | null;
2420
+ isRunning: boolean;
2421
+ activeJobId: string | number | null;
2422
+ activeJobIds?: (string | number)[];
2423
+ registeredAt: Date;
2424
+ }
2425
+
2426
+ export class CronExpression {
2427
+ rawExpression: string;
2428
+ resolvedExpression: string;
2429
+ utc: boolean;
2430
+ timezone: string | null;
2431
+ minutes: Set<number>;
2432
+ hours: Set<number>;
2433
+ doms: Set<number>;
2434
+ months: Set<number>;
2435
+ dows: Set<number>;
2436
+ constructor(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string });
2437
+ match(date?: Date | string | number): boolean;
2438
+ getNextDate(fromDate?: Date | string | number): Date | null;
2439
+ getNextDates(count?: number, fromDate?: Date | string | number): Date[];
2440
+ static isValid(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string }): boolean;
2441
+ static parse(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string }): CronExpression;
2442
+ }
2443
+
2444
+ export function parseCron(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string }): CronExpression;
2445
+ export function isValidCron(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string }): boolean;
2446
+ export function resolveCronAlias(str: string): string;
2447
+ export const CRON_ALIASES: Record<string, string>;
2448
+
2449
+ export class TaskScheduler {
2450
+ queue: QueueManager;
2451
+ maxIntervalMs: number;
2452
+ isRunning: boolean;
2453
+ schedules: Map<string, any>;
2454
+ constructor(queue: QueueManager, options?: { autoStart?: boolean; maxIntervalMs?: number });
2455
+ schedule(cronExpression: string | CronExpression, jobName: string, data?: unknown, options?: ScheduleOptions): ScheduleInfo;
2456
+ cron(cronExpression: string | CronExpression, jobName: string, data?: unknown, options?: ScheduleOptions): ScheduleInfo;
2457
+ unschedule(idOrJobName: string): boolean;
2458
+ getSchedules(): ScheduleInfo[];
2459
+ getSchedule(idOrJobName: string): ScheduleInfo | null;
2460
+ trigger(idOrJobName: string): Promise<Job | null>;
2461
+ start(): this;
2462
+ stop(): this;
2463
+ pause(): this;
2464
+ resume(): this;
2465
+ clear(): void;
2466
+ destroy(): void;
2467
+ }
2468
+
2120
2469
  export class QueueManager extends EventEmitter {
2121
2470
  adapter: QueueAdapter;
2122
2471
  concurrency: number;
@@ -2125,6 +2474,7 @@ export class QueueManager extends EventEmitter {
2125
2474
  isPaused: boolean;
2126
2475
  isDraining: boolean;
2127
2476
  retentionConfig: QueueRetentionConfig;
2477
+ scheduler: TaskScheduler;
2128
2478
  constructor(options?: {
2129
2479
  adapter?: QueueAdapter;
2130
2480
  concurrency?: number;
@@ -2141,6 +2491,13 @@ export class QueueManager extends EventEmitter {
2141
2491
  define(name: string, handler: (job: Job, ctx: { queue: QueueManager }) => Promise<any> | any, options?: DispatchOptions): this;
2142
2492
  has(name: string): boolean;
2143
2493
  dispatch(name: string, data?: unknown, options?: DispatchOptions): Promise<Job>;
2494
+ schedule(cronExpression: string | CronExpression, name: string, data?: unknown, options?: ScheduleOptions): ScheduleInfo;
2495
+ cron(cronExpression: string | CronExpression, name: string, data?: unknown, options?: ScheduleOptions): ScheduleInfo;
2496
+ unschedule(idOrJobName: string): boolean;
2497
+ getSchedules(): ScheduleInfo[];
2498
+ getSchedule(idOrJobName: string): ScheduleInfo | null;
2499
+ triggerSchedule(idOrJobName: string): Promise<Job | null>;
2500
+ triggerCron(idOrJobName: string): Promise<Job | null>;
2144
2501
  start(): this;
2145
2502
  pause(): this;
2146
2503
  resume(): this;
@@ -2202,6 +2559,10 @@ export function queuePlugin(options?: {
2202
2559
  olderThan?: Date | string | number;
2203
2560
  limit?: number;
2204
2561
  }): Promise<number>;
2562
+ schedule(cronExpression: string | CronExpression, name: string, data?: unknown, options?: ScheduleOptions): ScheduleInfo | undefined;
2563
+ cron(cronExpression: string | CronExpression, name: string, data?: unknown, options?: ScheduleOptions): ScheduleInfo | undefined;
2564
+ unschedule(idOrJobName: string): boolean | undefined;
2565
+ getSchedules(): ScheduleInfo[];
2205
2566
  };
2206
2567
  };
2207
2568
 
@@ -2211,14 +2572,20 @@ export interface HtmlStreamOptions {
2211
2572
  env: import('nunjucks').Environment;
2212
2573
  templatePath: string;
2213
2574
  context?: Record<string, unknown>;
2214
- defer?: Record<string, Promise<unknown> | { promise: Promise<unknown>; template?: string }>;
2575
+ defer?: Record<string, Promise<unknown> | { promise: Promise<unknown>; template?: string; loadingTemplate?: string }>;
2576
+ nonce?: string;
2577
+ loadingTemplate?: string | null;
2578
+ layouts?: CascadingLayoutInfo[];
2215
2579
  }
2216
2580
 
2217
2581
  export interface RenderStreamOptions {
2218
2582
  env?: import('nunjucks').Environment;
2219
- defer?: Record<string, Promise<unknown> | { promise: Promise<unknown>; template?: string }>;
2583
+ defer?: Record<string, Promise<unknown> | { promise: Promise<unknown>; template?: string; loadingTemplate?: string }>;
2220
2584
  status?: number;
2221
2585
  flushImmediately?: boolean;
2586
+ nonce?: string;
2587
+ loadingTemplate?: string | null;
2588
+ layouts?: CascadingLayoutInfo[];
2222
2589
  }
2223
2590
 
2224
2591
  export function createHtmlStream(options: HtmlStreamOptions): import('stream').Readable;
@@ -2234,6 +2601,54 @@ export const ssr: {
2234
2601
  renderStream: typeof renderStream;
2235
2602
  };
2236
2603
 
2604
+ // --- Server-Sent Events (SSE) Streaming ---
2605
+
2606
+ export interface SseOptions {
2607
+ status?: number;
2608
+ headers?: Record<string, string>;
2609
+ heartbeat?: number | boolean;
2610
+ heartbeatComment?: string;
2611
+ retry?: number;
2612
+ map?: (chunk: any) => any;
2613
+ }
2614
+
2615
+ export interface SseEventObject {
2616
+ data?: any;
2617
+ event?: string;
2618
+ id?: string | number;
2619
+ retry?: number;
2620
+ }
2621
+
2622
+ export class ServerSentEventsStream extends EventEmitter {
2623
+ req: import('http').IncomingMessage;
2624
+ res: import('http').ServerResponse;
2625
+ options: SseOptions;
2626
+ isOpen: boolean;
2627
+ isClosed: boolean;
2628
+
2629
+ constructor(req: import('http').IncomingMessage, res: import('http').ServerResponse, options?: SseOptions);
2630
+ send(payloadOrData: any | SseEventObject, event?: string, id?: string | number): Promise<boolean>;
2631
+ comment(text: string): boolean;
2632
+ heartbeat(comment?: string): boolean;
2633
+ retry(ms: number): boolean;
2634
+ pipe(source: AsyncIterable<any> | Iterable<any> | import('stream').Readable, mapFn?: (chunk: any) => any): Promise<void>;
2635
+ stream(generatorFn: (stream: ServerSentEventsStream) => any): Promise<void>;
2636
+ close(): void;
2637
+ }
2638
+
2639
+ export function createSseStream(
2640
+ req: import('http').IncomingMessage,
2641
+ res: import('http').ServerResponse,
2642
+ sourceOrOptions?: SseOptions | AsyncIterable<any> | Iterable<any> | import('stream').Readable | ((stream: ServerSentEventsStream) => any),
2643
+ maybeOptions?: SseOptions
2644
+ ): ServerSentEventsStream | Promise<void>;
2645
+
2646
+ export const sseStream: {
2647
+ ServerSentEventsStream: typeof ServerSentEventsStream;
2648
+ createSseStream: typeof createSseStream;
2649
+ formatSseFrame: (data?: any, event?: string, id?: string | number, retry?: number) => string;
2650
+ };
2651
+
2237
2652
  // --- Model Context Protocol (MCP) Plugin ---
2238
2653
 
2239
2654
  export interface McpPluginOptions {
@@ -2629,8 +3044,381 @@ export interface GenerateTypesResult {
2629
3044
 
2630
3045
  export function generateTypes(options?: GenerateTypesOptions): GenerateTypesResult;
2631
3046
 
3047
+ // --- OAuth 2.0 & Social Login Plugin ---
2632
3048
 
3049
+ export class OAuthError extends Error {
3050
+ code: string;
3051
+ details?: any;
3052
+ constructor(message: string, code?: string, details?: any);
3053
+ }
2633
3054
 
3055
+ export interface OAuthUserProfile {
3056
+ provider: string;
3057
+ id: string;
3058
+ email?: string | null;
3059
+ emailVerified?: boolean;
3060
+ name?: string | null;
3061
+ firstName?: string | null;
3062
+ lastName?: string | null;
3063
+ username?: string | null;
3064
+ avatarUrl?: string | null;
3065
+ bio?: string | null;
3066
+ location?: string | null;
3067
+ locale?: string | null;
3068
+ raw: Record<string, any>;
3069
+ [key: string]: any;
3070
+ }
3071
+
3072
+ export interface OAuthProviderConfig {
3073
+ name?: string;
3074
+ clientId: string;
3075
+ clientSecret: string;
3076
+ redirectUri?: string;
3077
+ authorizationUrl?: string;
3078
+ tokenUrl?: string;
3079
+ userInfoUrl?: string;
3080
+ scopes?: string[] | string;
3081
+ defaultScopes?: string[];
3082
+ params?: Record<string, any>;
3083
+ normalizeProfile?: (raw: any, extra?: any) => OAuthUserProfile;
3084
+ fetchExtra?: (tokens: any) => Promise<any>;
3085
+ }
3086
+
3087
+ export interface OAuthClientConfig {
3088
+ secret?: string;
3089
+ stateTtlMs?: number;
3090
+ providers?: Record<string, OAuthProviderConfig>;
3091
+ }
3092
+
3093
+ export class OAuthClient {
3094
+ secret: string;
3095
+ stateTtlMs: number;
3096
+ providers: Record<string, OAuthProviderConfig>;
3097
+ constructor(config?: OAuthClientConfig);
3098
+ registerProvider(name: string, options?: OAuthProviderConfig): this;
3099
+ getProvider(name: string): OAuthProviderConfig;
3100
+ getProviderNames(): string[];
3101
+ getAuthorizationUrl(providerName: string, options?: {
3102
+ redirectUri?: string;
3103
+ scopes?: string[] | string;
3104
+ stateData?: Record<string, any>;
3105
+ pkce?: boolean;
3106
+ extraParams?: Record<string, any>;
3107
+ }): { url: string; state: string; codeVerifier?: string };
3108
+ exchangeCode(providerName: string, params: {
3109
+ code: string;
3110
+ redirectUri?: string;
3111
+ codeVerifier?: string;
3112
+ }): Promise<Record<string, any>>;
3113
+ fetchUserProfile(providerName: string, tokens: Record<string, any>): Promise<OAuthUserProfile>;
3114
+ handleCallback(providerName: string, params: {
3115
+ code: string;
3116
+ state: string;
3117
+ redirectUri?: string;
3118
+ }): Promise<{ provider: string; user: OAuthUserProfile; tokens: Record<string, any>; stateData: Record<string, any> }>;
3119
+ }
3120
+
3121
+ export function createOAuthClient(config?: OAuthClientConfig): OAuthClient;
3122
+ export function generatePKCE(): { codeVerifier: string; codeChallenge: string; codeChallengeMethod: 'S256' };
3123
+ export function createSignedState(payload: Record<string, any>, secret: string): string;
3124
+ export function verifySignedState(stateString: string, secret: string, maxAgeMs?: number): Record<string, any>;
3125
+
3126
+ export interface OAuthPluginOptions {
3127
+ client?: OAuthClient;
3128
+ providers?: Record<string, OAuthProviderConfig>;
3129
+ secret?: string;
3130
+ pathPrefix?: string;
3131
+ routes?: boolean;
3132
+ pkce?: boolean;
3133
+ stateTtlMs?: number;
3134
+ defaultReturnTo?: string;
3135
+ failureRedirect?: string;
3136
+ findOrCreateUser?: (params: {
3137
+ provider: string;
3138
+ profile: OAuthUserProfile;
3139
+ tokens: Record<string, any>;
3140
+ stateData: Record<string, any>;
3141
+ req: any;
3142
+ res: any;
3143
+ db?: any;
3144
+ }) => Promise<any>;
3145
+ onSuccess?: (params: {
3146
+ provider: string;
3147
+ user: any;
3148
+ profile: OAuthUserProfile;
3149
+ tokens: Record<string, any>;
3150
+ stateData: Record<string, any>;
3151
+ req: any;
3152
+ res: any;
3153
+ client: OAuthClient;
3154
+ }) => Promise<void | any>;
3155
+ onError?: (params: {
3156
+ error: Error | OAuthError;
3157
+ provider: string;
3158
+ req: any;
3159
+ res: any;
3160
+ client: OAuthClient;
3161
+ }) => Promise<void | any>;
3162
+ db?: any;
3163
+ }
2634
3164
 
3165
+ export function oauthPlugin(options?: OAuthPluginOptions): WebspressoPlugin;
3166
+
3167
+ // ==========================================
3168
+ // 2FA / TOTP (RFC 6238, RFC 4226, RFC 4648)
3169
+ // ==========================================
3170
+
3171
+ export interface Base32EncodeOptions {
3172
+ padding?: boolean;
3173
+ }
3174
+
3175
+ export interface TotpSecretOptions extends Base32EncodeOptions {
3176
+ length?: number;
3177
+ }
3178
+
3179
+ export interface HotpOptions {
3180
+ digits?: number;
3181
+ algorithm?: 'sha1' | 'sha256' | 'sha512' | string;
3182
+ encoding?: 'base32' | 'ascii' | 'utf8' | 'hex';
3183
+ }
2635
3184
 
3185
+ export interface TotpOptions extends HotpOptions {
3186
+ time?: number | Date;
3187
+ step?: number;
3188
+ epoch?: number;
3189
+ }
3190
+
3191
+ export interface TotpVerifyOptions extends TotpOptions {
3192
+ window?: number;
3193
+ detailed?: boolean;
3194
+ }
3195
+
3196
+ export interface TotpUriOptions {
3197
+ secret: string;
3198
+ account?: string;
3199
+ issuer?: string;
3200
+ label?: string;
3201
+ algorithm?: string;
3202
+ digits?: number;
3203
+ period?: number;
3204
+ }
3205
+
3206
+ export interface QrSvgOptions {
3207
+ size?: number;
3208
+ margin?: number;
3209
+ darkColor?: string;
3210
+ lightColor?: string;
3211
+ version?: number;
3212
+ ecc?: 'L' | 'M' | 'Q' | 'H';
3213
+ mask?: number;
3214
+ }
3215
+
3216
+ export interface RecoveryCodeOptions {
3217
+ count?: number;
3218
+ length?: number;
3219
+ hyphen?: boolean;
3220
+ }
3221
+
3222
+ export interface TotpSetupOptions extends TotpSecretOptions {
3223
+ user?: any;
3224
+ account?: string;
3225
+ issuer?: string;
3226
+ recoveryCodeCount?: number;
3227
+ qrOptions?: QrSvgOptions;
3228
+ algorithm?: string;
3229
+ digits?: number;
3230
+ period?: number;
3231
+ }
3232
+
3233
+ export interface TotpSetupResult {
3234
+ secret: string;
3235
+ uri: string;
3236
+ qrSvg: string;
3237
+ qrDataUri: string;
3238
+ recoveryCodes: string[];
3239
+ recoveryCodesHashed: string[];
3240
+ }
3241
+
3242
+ export function base32Encode(buffer: Buffer | string, options?: Base32EncodeOptions): string;
3243
+ export function base32Decode(input: string): Buffer;
3244
+ export function generateTotpSecret(options?: TotpSecretOptions): string;
3245
+ export function generateHotp(secret: string | Buffer, counter: number | bigint, options?: HotpOptions): string;
3246
+ export function verifyHotp(token: string, secret: string | Buffer, counter: number | bigint, options?: HotpOptions): boolean;
3247
+ export function generateTotp(secret: string | Buffer, options?: TotpOptions): string;
3248
+ export function verifyTotp(token: string, secret: string | Buffer, options?: TotpVerifyOptions): boolean | { valid: boolean; delta: number | null };
3249
+ export function generateTotpUri(options: TotpUriOptions): string;
3250
+ export function generateTotpQrSvg(uriOrOptions: string | TotpUriOptions, svgOptions?: QrSvgOptions): string;
3251
+ export function generateTotpQrDataUri(uriOrOptions: string | TotpUriOptions, svgOptions?: QrSvgOptions): string;
3252
+ export function generateRecoveryCodes(options?: RecoveryCodeOptions): string[];
3253
+ export function hashRecoveryCode(code: string): string;
3254
+ export function verifyRecoveryCode(code: string, hashedCodes: string[]): { valid: boolean; matchedIndex: number; remainingHashedCodes: string[] };
3255
+ export function createTotpSetup(options?: TotpSetupOptions): TotpSetupResult;
3256
+
3257
+ export function createQrMatrix(text: string, options?: QrSvgOptions): { matrix: boolean[][]; size: number; version: number };
3258
+ export function generateQrSvg(text: string, options?: QrSvgOptions): string;
3259
+ export function generateQrDataUri(text: string, options?: QrSvgOptions): string;
3260
+
3261
+ export namespace totp {
3262
+ export {
3263
+ base32Encode,
3264
+ base32Decode,
3265
+ generateTotpSecret,
3266
+ generateHotp,
3267
+ verifyHotp,
3268
+ generateTotp,
3269
+ verifyTotp,
3270
+ generateTotpUri,
3271
+ generateTotpQrSvg,
3272
+ generateTotpQrDataUri,
3273
+ generateRecoveryCodes,
3274
+ hashRecoveryCode,
3275
+ verifyRecoveryCode,
3276
+ createTotpSetup,
3277
+ createQrMatrix,
3278
+ generateQrSvg,
3279
+ generateQrDataUri,
3280
+ };
3281
+ }
3282
+
3283
+ // --- Magic Link / Passwordless Authentication ---
3284
+
3285
+ export interface BuildMagicLinkUrlOptions {
3286
+ baseUrl?: string;
3287
+ path?: string;
3288
+ token: string;
3289
+ }
3290
+
3291
+ export interface FormatMagicLinkHtmlOptions {
3292
+ name?: string;
3293
+ magicLinkUrl: string;
3294
+ expiresMinutes?: number;
3295
+ }
3296
+
3297
+ export interface MagicLinkVerifyMiddlewareOptions {
3298
+ tokenParam?: string;
3299
+ redirectTo?: string;
3300
+ failureRedirect?: string;
3301
+ markEmailVerified?: boolean;
3302
+ jwt?: boolean;
3303
+ }
3304
+
3305
+ export interface MagicLinkRequestOptions {
3306
+ baseUrl?: string;
3307
+ path?: string;
3308
+ tokenTtlMs?: number;
3309
+ hideUserNotFound?: boolean;
3310
+ buildMagicLinkUrl?: (token: string) => string;
3311
+ }
3312
+
3313
+ export interface MagicLinkRequestResult {
3314
+ sent: boolean;
3315
+ userFound: boolean;
3316
+ expiresAt?: Date;
3317
+ token?: string;
3318
+ magicLinkUrl?: string;
3319
+ }
3320
+
3321
+ export interface MagicLinkVerifyResult {
3322
+ ok: true;
3323
+ user: any;
3324
+ userId: string | number;
3325
+ accessToken?: string;
3326
+ refreshToken?: string;
3327
+ }
3328
+
3329
+ export function buildMagicLinkUrl(options: BuildMagicLinkUrlOptions): string;
3330
+ export function formatMagicLinkHtml(options: FormatMagicLinkHtmlOptions): string;
3331
+ export function createMagicLinkVerifyMiddleware(authManager: any, options?: MagicLinkVerifyMiddlewareOptions): (req: any, res: any, next: any) => Promise<any>;
3332
+ export function createMagicLinkRequestHandler(authManager: any, options?: MagicLinkRequestOptions): (req: any, res: any) => Promise<any>;
3333
+
3334
+ export namespace magicLink {
3335
+ export {
3336
+ buildMagicLinkUrl,
3337
+ formatMagicLinkHtml,
3338
+ createMagicLinkVerifyMiddleware,
3339
+ createMagicLinkRequestHandler,
3340
+ };
3341
+ }
3342
+
3343
+ // Active Devices & Session Management
3344
+ export interface DeviceInfo {
3345
+ browser: string;
3346
+ os: string;
3347
+ device: 'desktop' | 'mobile' | 'tablet' | 'bot' | 'unknown';
3348
+ isMobile: boolean;
3349
+ isTablet: boolean;
3350
+ isDesktop: boolean;
3351
+ isBot: boolean;
3352
+ }
3353
+
3354
+ export interface UserSession {
3355
+ id?: number | string;
3356
+ session_id: string;
3357
+ user_id: number | string;
3358
+ ip_address?: string | null;
3359
+ user_agent?: string | null;
3360
+ browser?: string | null;
3361
+ os?: string | null;
3362
+ device?: string | null;
3363
+ last_active_at: Date;
3364
+ created_at?: Date;
3365
+ is_current?: boolean;
3366
+ }
3367
+
3368
+ export interface SessionTracker {
3369
+ track(sessionId: string, userId: string | number, metadata?: { ip?: string; userAgent?: string; browser?: string; os?: string; device?: string }): Promise<UserSession | null>;
3370
+ touch(sessionId: string): Promise<boolean>;
3371
+ get(sessionId: string): Promise<UserSession | null>;
3372
+ list(userId: string | number, currentSessionId?: string | null): Promise<UserSession[]>;
3373
+ isSessionValid(sessionId: string, userId?: string | number | null): Promise<boolean>;
3374
+ revoke(sessionId: string): Promise<boolean>;
3375
+ revokeOthers(userId: string | number, currentSessionId?: string | null): Promise<number>;
3376
+ revokeAll(userId: string | number): Promise<number>;
3377
+ purgeExpired(maxAgeMs: number): Promise<number>;
3378
+ }
3379
+
3380
+ export interface SessionManagerOptions {
3381
+ tracker?: SessionTracker;
3382
+ sessionStore?: any;
3383
+ touchThrottleMs?: number;
3384
+ emitter?: any;
3385
+ }
3386
+
3387
+ export class SessionManager {
3388
+ constructor(options?: SessionManagerOptions);
3389
+ tracker: SessionTracker;
3390
+ sessionStore?: any;
3391
+ touchThrottleMs: number;
3392
+ emitter?: any;
3393
+ track(sessionId: string, userId: string | number, req?: any): Promise<UserSession | null>;
3394
+ touch(sessionId: string): Promise<boolean>;
3395
+ isSessionValid(sessionId: string, userId?: string | number | null): Promise<boolean>;
3396
+ listSessions(userId: string | number, currentSessionId?: string | null): Promise<UserSession[]>;
3397
+ revokeSession(sessionId: string, options?: { userId?: string | number; revokedBy?: string }): Promise<boolean>;
3398
+ revokeOtherSessions(userId: string | number, currentSessionId: string): Promise<number>;
3399
+ revokeAllSessions(userId: string | number): Promise<number>;
3400
+ }
3401
+
3402
+ export function parseUserAgent(userAgent?: string): DeviceInfo;
3403
+ export function getClientIp(req?: any): string;
3404
+ export function createUserSessionsTable(knex: any): Promise<void>;
3405
+ export function dropUserSessionsTable(knex: any): Promise<void>;
3406
+ export function createKnexSessionTracker(db: any, options?: { tableName?: string }): SessionTracker;
3407
+ export function createMemorySessionTracker(): SessionTracker;
3408
+ export function createListSessionsHandler(authManager: any): (req: any, res: any) => Promise<any>;
3409
+ export function createRevokeSessionHandler(authManager: any): (req: any, res: any) => Promise<any>;
3410
+
3411
+ export namespace sessions {
3412
+ export {
3413
+ SessionManager,
3414
+ createUserSessionsTable,
3415
+ dropUserSessionsTable,
3416
+ createKnexSessionTracker,
3417
+ createMemorySessionTracker,
3418
+ getClientIp,
3419
+ parseUserAgent,
3420
+ createListSessionsHandler,
3421
+ createRevokeSessionHandler,
3422
+ };
3423
+ }
2636
3424