webspresso 0.0.99 → 0.0.101
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/.agents/ADMIN.md +47 -4
- package/.agents/AGENTS.md +4 -2
- package/.agents/AUTH.md +309 -0
- package/.agents/CLI.md +128 -0
- package/.agents/EMAIL.md +84 -2
- package/.agents/ERRORS.md +59 -0
- package/.agents/EVENTS.md +179 -0
- package/.agents/ORM.md +149 -0
- package/.agents/PLUGINS.md +44 -7
- package/.agents/QUEUE.md +18 -10
- package/.agents/ROUTING.md +97 -1
- package/.agents/STREAMING.md +35 -0
- package/AGENTS.md +2 -0
- package/README.md +145 -93
- package/bin/commands/add-docker.js +467 -0
- package/bin/commands/db-makemigrations.js +83 -0
- package/bin/commands/deploy-check.js +339 -0
- package/bin/commands/list.js +96 -0
- package/bin/commands/make-command.js +93 -0
- package/bin/commands/make-event.js +80 -0
- package/bin/commands/make-factory.js +72 -0
- package/bin/commands/make-mail.js +93 -0
- package/bin/commands/make-policy.js +106 -0
- package/bin/commands/run.js +195 -0
- package/bin/webspresso.js +21 -0
- package/core/auth/bouncer.js +196 -0
- package/core/auth/index.js +73 -1
- package/core/auth/magic-link.js +170 -0
- package/core/auth/manager.js +343 -3
- package/core/auth/middleware.js +45 -6
- package/core/auth/session-manager.js +255 -0
- package/core/auth/sessions.js +351 -0
- package/core/auth/tokens.js +1 -0
- package/core/auth/totp.js +4 -1
- package/core/auth/user-agent.js +161 -0
- package/core/commands/define-command.js +48 -0
- package/core/commands/index.js +18 -0
- package/core/commands/registry.js +156 -0
- package/core/commands/runner.js +76 -0
- package/core/compression/compressible.js +1 -1
- package/core/compression/middleware.js +35 -251
- package/core/content/service.js +8 -2
- package/core/events/discovery.js +142 -0
- package/core/events/dispatcher.js +552 -0
- package/core/events/index.js +23 -0
- package/core/events/signal.js +92 -0
- package/core/forms/flash.js +234 -0
- package/core/forms/form-builder.js +214 -0
- package/core/forms/index.js +16 -0
- package/core/mail/index.js +23 -0
- package/core/mail/mailable.js +250 -0
- package/core/mail/mailer.js +184 -0
- package/core/mail/transports.js +238 -0
- package/core/orm/factory.js +250 -0
- package/core/orm/index.js +8 -1
- package/core/orm/migrations/diff.js +185 -0
- package/core/orm/migrations/index.js +22 -4
- package/core/orm/model.js +55 -1
- package/core/orm/repository.js +283 -13
- package/core/orm/scopes.js +3 -2
- package/core/orm/types.js +6 -1
- package/core/queue/cron.js +252 -39
- package/core/queue/manager.js +20 -2
- package/core/queue/scheduler.js +115 -59
- package/core/ssr/stream.js +62 -2
- package/index.d.ts +540 -14
- package/index.js +44 -0
- package/package.json +11 -5
- package/plugins/admin-panel/api.js +509 -3
- package/plugins/admin-panel/index.js +17 -0
- package/plugins/admin-panel/modules/admin-users.js +1 -1
- package/plugins/audit-log/admin-component.js +54 -54
- package/plugins/audit-log/index.js +2 -2
- package/plugins/content/client/inline-edit.js +2 -46
- package/plugins/content/models/content-entry.js +4 -3
- package/plugins/content/models/content-type.js +4 -3
- package/plugins/cors.js +15 -4
- package/plugins/email/auth-bridge.js +66 -0
- package/plugins/email/bundled-templates.js +15 -0
- package/plugins/email/index.js +48 -0
- package/plugins/email/preview-handler.js +555 -0
- package/plugins/email/service.js +23 -12
- package/plugins/email/templates/auth-magic-link.mjml +13 -0
- package/plugins/email/transport.js +30 -11
- package/plugins/file-manager/admin-component.js +49 -49
- package/plugins/file-manager/index.js +4 -4
- package/plugins/index.js +2 -0
- package/plugins/redirect/index.js +1 -1
- package/plugins/webhooks/admin-component.js +608 -0
- package/plugins/webhooks/api-handlers.js +237 -0
- package/plugins/webhooks/crypto.js +144 -0
- package/plugins/webhooks/dispatcher.js +708 -0
- package/plugins/webhooks/index.js +263 -0
- package/plugins/webhooks/matcher.js +113 -0
- package/plugins/webhooks/migration-template.js +75 -0
- package/plugins/webhooks/models.js +98 -0
- package/plugins/webhooks/sender.js +176 -0
- package/src/api/api-loader.js +1 -1
- package/src/app-context.js +48 -6
- package/src/bundle/index.js +2 -1
- package/src/dev-reload/index.js +9 -1
- package/src/discovery/scan-routes.js +10 -1
- package/src/file-router.js +173 -4
- package/src/helpers.js +150 -1
- package/src/njk-frontmatter.js +3 -0
- package/src/pages/page-loader.js +1 -1
- package/src/routing/cascading.js +120 -4
- package/src/server.js +180 -26
package/index.d.ts
CHANGED
|
@@ -509,6 +509,8 @@ export function getAppContext(): {
|
|
|
509
509
|
db: DatabaseInstance | null;
|
|
510
510
|
shutdownManager: ShutdownManager | null;
|
|
511
511
|
serviceRegistry: ServiceRegistry | null;
|
|
512
|
+
events?: any;
|
|
513
|
+
mailer?: Mailer | null;
|
|
512
514
|
};
|
|
513
515
|
|
|
514
516
|
export function getDb(): DatabaseInstance;
|
|
@@ -523,12 +525,18 @@ export function getServiceRegistry(): ServiceRegistry | null;
|
|
|
523
525
|
|
|
524
526
|
export function hasServiceRegistry(): boolean;
|
|
525
527
|
|
|
528
|
+
export function getMailer(): Mailer | null;
|
|
529
|
+
|
|
530
|
+
export function hasMailer(): boolean;
|
|
531
|
+
|
|
526
532
|
export function resetAppContext(): void;
|
|
527
533
|
|
|
528
534
|
export function setAppContext(partial: {
|
|
529
535
|
db?: DatabaseInstance | null;
|
|
530
536
|
shutdownManager?: ShutdownManager | null;
|
|
531
537
|
serviceRegistry?: ServiceRegistry | null;
|
|
538
|
+
events?: any;
|
|
539
|
+
mailer?: Mailer | null;
|
|
532
540
|
}): void;
|
|
533
541
|
|
|
534
542
|
// --- File router ---
|
|
@@ -547,6 +555,19 @@ export interface CascadingLayoutInfo {
|
|
|
547
555
|
configPath: string | null;
|
|
548
556
|
}
|
|
549
557
|
|
|
558
|
+
export interface CascadingErrorBoundaryInfo {
|
|
559
|
+
dirSegment: string;
|
|
560
|
+
errorRelPath: string;
|
|
561
|
+
fullPath: string;
|
|
562
|
+
configPath: string | null;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
export interface CascadingLoadingInfo {
|
|
566
|
+
dirSegment: string;
|
|
567
|
+
loadingRelPath: string;
|
|
568
|
+
fullPath: string;
|
|
569
|
+
}
|
|
570
|
+
|
|
550
571
|
export namespace cascading {
|
|
551
572
|
export function getDirectoryChain(relativeFilePath: string): string[];
|
|
552
573
|
export function templateHasExtends(templateBody?: string | null, fullPath?: string): boolean;
|
|
@@ -568,6 +589,16 @@ export namespace cascading {
|
|
|
568
589
|
renderContext: Record<string, unknown>,
|
|
569
590
|
isDev?: boolean
|
|
570
591
|
): string;
|
|
592
|
+
export function findNearestErrorBoundary(
|
|
593
|
+
baseDir: string,
|
|
594
|
+
relativeFilePath: string,
|
|
595
|
+
isDev?: boolean
|
|
596
|
+
): CascadingErrorBoundaryInfo | null;
|
|
597
|
+
export function findNearestLoadingTemplate(
|
|
598
|
+
baseDir: string,
|
|
599
|
+
relativeFilePath: string,
|
|
600
|
+
isDev?: boolean
|
|
601
|
+
): CascadingLoadingInfo | null;
|
|
571
602
|
export function clearCascadingCaches(): void;
|
|
572
603
|
}
|
|
573
604
|
|
|
@@ -649,6 +680,125 @@ export function loadNjkRouteTemplate(
|
|
|
649
680
|
|
|
650
681
|
export function clearNjkFrontmatterCaches(): void;
|
|
651
682
|
|
|
683
|
+
// --- Forms & Flash subsystem (AdonisJS & Django-inspired) ---
|
|
684
|
+
|
|
685
|
+
export interface FlashMessages {
|
|
686
|
+
old?: Record<string, any>;
|
|
687
|
+
errors?: Record<string, string[]>;
|
|
688
|
+
[key: string]: any;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
export function createFlashMiddleware(options?: { cookieName?: string }): import('express').RequestHandler;
|
|
692
|
+
|
|
693
|
+
export function normalizeErrors(errors: any): Record<string, string[]>;
|
|
694
|
+
|
|
695
|
+
export interface FieldRenderOptions {
|
|
696
|
+
label?: string;
|
|
697
|
+
type?: string;
|
|
698
|
+
placeholder?: string;
|
|
699
|
+
required?: boolean;
|
|
700
|
+
disabled?: boolean;
|
|
701
|
+
readonly?: boolean;
|
|
702
|
+
className?: string;
|
|
703
|
+
wrapperClass?: string;
|
|
704
|
+
errorClass?: string;
|
|
705
|
+
showError?: boolean;
|
|
706
|
+
rows?: number;
|
|
707
|
+
selectOptions?: (string | { label: string; value: any })[];
|
|
708
|
+
helpText?: string;
|
|
709
|
+
value?: any;
|
|
710
|
+
default?: any;
|
|
711
|
+
attributes?: Record<string, string>;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
export function renderField(name: string, options?: FieldRenderOptions, ctx?: { req?: any; res?: any }): string;
|
|
715
|
+
|
|
716
|
+
export interface FormForOptions {
|
|
717
|
+
action?: string;
|
|
718
|
+
method?: string;
|
|
719
|
+
exclude?: string[];
|
|
720
|
+
include?: string[];
|
|
721
|
+
submitLabel?: string;
|
|
722
|
+
csrf?: boolean;
|
|
723
|
+
formClass?: string;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
export function renderFormFor(modelOrRepo: any, options?: FormForOptions, ctx?: { req?: any; res?: any }): string;
|
|
727
|
+
|
|
728
|
+
// --- Authorization & Bouncer (AdonisJS Bouncer & Django Permissions-inspired) ---
|
|
729
|
+
|
|
730
|
+
export class Bouncer {
|
|
731
|
+
constructor(user?: any, policyManager?: any);
|
|
732
|
+
user: any;
|
|
733
|
+
forUser(user: any): Bouncer;
|
|
734
|
+
allows(actionOrPolicy: string | Function, ...args: any[]): boolean;
|
|
735
|
+
denies(actionOrPolicy: string | Function, ...args: any[]): boolean;
|
|
736
|
+
authorize(actionOrPolicy: string | Function, ...args: any[]): boolean;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
export function createBouncer(user?: any, policyManager?: any): Bouncer;
|
|
740
|
+
|
|
741
|
+
export function createBouncerMiddleware(options?: { policyManager?: any }): import('express').RequestHandler;
|
|
742
|
+
|
|
743
|
+
export function definePolicy(name: string, rules: Record<string, (user: any, ...args: any[]) => boolean | Promise<boolean>>): void;
|
|
744
|
+
|
|
745
|
+
export function defineGate(name: string, callback: (user: any, ...args: any[]) => boolean | Promise<boolean>): void;
|
|
746
|
+
|
|
747
|
+
export function can(user: any, action: string, policy?: string | null, resource?: any): boolean;
|
|
748
|
+
|
|
749
|
+
export function cannot(user: any, action: string, policy?: string | null, resource?: any): boolean;
|
|
750
|
+
|
|
751
|
+
export function authorize(user: any, action: string, policy?: string | null, resource?: any): void;
|
|
752
|
+
|
|
753
|
+
// --- Decoupled Events & Signals (AdonisJS Events & Django Signals-inspired) ---
|
|
754
|
+
|
|
755
|
+
export interface EventListenerOptions {
|
|
756
|
+
sender?: any;
|
|
757
|
+
priority?: number;
|
|
758
|
+
once?: boolean;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
export class EventDispatcher {
|
|
762
|
+
constructor(options?: { queue?: any; maxListeners?: number; logger?: any });
|
|
763
|
+
on(event: string, handler: Function, options?: EventListenerOptions): () => void;
|
|
764
|
+
once(event: string, handler: Function, options?: EventListenerOptions): () => void;
|
|
765
|
+
off(event: string, handler: Function): this;
|
|
766
|
+
onAny(handler: (eventName: string, data: any, meta: any) => any, options?: { priority?: number; once?: boolean }): () => void;
|
|
767
|
+
emit(eventOrInstance: string | object, data?: any, options?: { sender?: any }): boolean;
|
|
768
|
+
emitAsync(eventOrInstance: string | object, data?: any, options?: { sender?: any }): Promise<Array<{ status: 'fulfilled' | 'rejected'; value?: any; reason?: any }>>;
|
|
769
|
+
emitParallel(eventOrInstance: string | object, data?: any, options?: { sender?: any }): Promise<Array<{ status: 'fulfilled' | 'rejected'; value?: any; reason?: any }>>;
|
|
770
|
+
emitSerial(eventOrInstance: string | object, data?: any, options?: { sender?: any }): Promise<any[]>;
|
|
771
|
+
emitWaterfall(eventOrInstance: string | object, initialData: any, options?: { sender?: any }): Promise<any>;
|
|
772
|
+
listenAndQueue(event: string, jobName: string, queueOptions?: Record<string, unknown>): () => void;
|
|
773
|
+
bridgeOrm(modelEvents?: any): () => void;
|
|
774
|
+
setQueue(queueManager: any): this;
|
|
775
|
+
eventNames(): string[];
|
|
776
|
+
listenerCount(event?: string): number;
|
|
777
|
+
removeAllListeners(event?: string): this;
|
|
778
|
+
clear(): void;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
export function createEventDispatcher(options?: { queue?: any; maxListeners?: number; logger?: any }): EventDispatcher;
|
|
782
|
+
|
|
783
|
+
export const events: EventDispatcher;
|
|
784
|
+
|
|
785
|
+
export class Signal {
|
|
786
|
+
constructor(name: string, dispatcher: EventDispatcher);
|
|
787
|
+
name: string;
|
|
788
|
+
dispatcher: EventDispatcher;
|
|
789
|
+
connect(receiver: Function, options?: EventListenerOptions): () => void;
|
|
790
|
+
disconnect(receiver: Function): this;
|
|
791
|
+
send(data?: any, options?: { sender?: any }): boolean;
|
|
792
|
+
sendAsync(data?: any, options?: { sender?: any }): Promise<Array<{ status: 'fulfilled' | 'rejected'; value?: any; reason?: any }>>;
|
|
793
|
+
sendSerial(data?: any, options?: { sender?: any }): Promise<any[]>;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
export function defineSignal(name: string, dispatcher?: EventDispatcher): Signal;
|
|
797
|
+
|
|
798
|
+
export function defineListener(event: string | string[], handler: Function, options?: EventListenerOptions): { event: string | string[]; handle: Function; [key: string]: any };
|
|
799
|
+
|
|
800
|
+
export function loadListeners(dirPath: string, dispatcher: EventDispatcher, options?: { logger?: any }): Array<{ file: string; event: string; handler: Function }>;
|
|
801
|
+
|
|
652
802
|
// --- Helpers / assets ---
|
|
653
803
|
|
|
654
804
|
export function createHelpers(context: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -745,11 +895,20 @@ export interface ScopeContext {
|
|
|
745
895
|
|
|
746
896
|
export type RelationType = 'belongsTo' | 'hasMany' | 'hasOne';
|
|
747
897
|
|
|
898
|
+
export type RelationCascadeOption =
|
|
899
|
+
| boolean
|
|
900
|
+
| 'delete'
|
|
901
|
+
| 'restore'
|
|
902
|
+
| 'all'
|
|
903
|
+
| ('delete' | 'restore' | 'all')[]
|
|
904
|
+
| { delete?: boolean; restore?: boolean };
|
|
905
|
+
|
|
748
906
|
export interface RelationDefinition {
|
|
749
907
|
type: RelationType;
|
|
750
|
-
model: () => ModelDefinition;
|
|
908
|
+
model: string | (() => ModelDefinition<any> | string);
|
|
751
909
|
foreignKey: string;
|
|
752
910
|
localKey?: string;
|
|
911
|
+
cascade?: RelationCascadeOption;
|
|
753
912
|
}
|
|
754
913
|
|
|
755
914
|
export interface AdminPermissions {
|
|
@@ -955,6 +1114,8 @@ export function hasModel(name: string): boolean;
|
|
|
955
1114
|
|
|
956
1115
|
export function clearRegistry(): void;
|
|
957
1116
|
|
|
1117
|
+
export function isCascadeEnabled(relation: RelationDefinition, operation: 'delete' | 'restore'): boolean;
|
|
1118
|
+
|
|
958
1119
|
// --- ORM: schema & columns ---
|
|
959
1120
|
|
|
960
1121
|
/** zdb column helpers (id, string, timestamp, …) + `schema()` */
|
|
@@ -1040,9 +1201,9 @@ export interface Repository<T = Record<string, any>> {
|
|
|
1040
1201
|
createMany(data: (Partial<T> | Record<string, unknown>)[]): Promise<T[]>;
|
|
1041
1202
|
update(id: string | number, data: Partial<T> | Record<string, unknown>): Promise<T | null>;
|
|
1042
1203
|
updateWhere(conditions: Partial<T> | Record<string, unknown>, data: Partial<T> | Record<string, unknown>): Promise<number>;
|
|
1043
|
-
delete(id: string | number): Promise<boolean>;
|
|
1044
|
-
forceDelete(id: string | number): Promise<boolean>;
|
|
1045
|
-
restore(id: string | number): Promise<T | null>;
|
|
1204
|
+
delete(id: string | number, options?: { cascade?: boolean; deletedAt?: Date }): Promise<boolean>;
|
|
1205
|
+
forceDelete(id: string | number, options?: { cascade?: boolean }): Promise<boolean>;
|
|
1206
|
+
restore(id: string | number, options?: { cascade?: boolean; allChildren?: boolean }): Promise<T | null>;
|
|
1046
1207
|
query(): QueryBuilder<T>;
|
|
1047
1208
|
raw(sql: string, bindings?: unknown[]): Promise<unknown>;
|
|
1048
1209
|
count(conditions?: Partial<T> | Record<string, unknown>): Promise<number>;
|
|
@@ -1126,6 +1287,8 @@ export interface MigrationManager {
|
|
|
1126
1287
|
getConfig(): MigrationConfig & { directory: string; tableName: string };
|
|
1127
1288
|
hasTable(): Promise<boolean>;
|
|
1128
1289
|
unlock(): Promise<void>;
|
|
1290
|
+
diff(options?: { models?: ModelDefinition<any>[]; includeDrops?: boolean }): Promise<{ hasChanges: boolean; changes: Array<any> }>;
|
|
1291
|
+
makeMigrations(options?: { modelsDir?: string; dryRun?: boolean; includeDrops?: boolean; name?: string }): Promise<{ hasChanges: boolean; created: Array<any>; skipped: Array<any> }>;
|
|
1129
1292
|
}
|
|
1130
1293
|
|
|
1131
1294
|
export interface WebspressoModels {
|
|
@@ -1192,6 +1355,30 @@ export function createMemoryCacheProvider(options?: OrmMemoryCacheOptions): {
|
|
|
1192
1355
|
getSizeStats(): { entries: number; tags: number };
|
|
1193
1356
|
};
|
|
1194
1357
|
|
|
1358
|
+
// --- ORM: Model Factory & Seeding (AdonisJS Lucid-inspired) ---
|
|
1359
|
+
|
|
1360
|
+
export interface FactoryBuilder<T = Record<string, any>> {
|
|
1361
|
+
count(n: number): FactoryBuilder<T>;
|
|
1362
|
+
state(...stateNames: string[]): FactoryBuilder<T>;
|
|
1363
|
+
apply(...stateNames: string[]): FactoryBuilder<T>;
|
|
1364
|
+
merge(overrides: Partial<T>): FactoryBuilder<T>;
|
|
1365
|
+
make(overrides?: Partial<T>): T | T[];
|
|
1366
|
+
create(options: { db?: DatabaseInstance | Repository<T>; merge?: Partial<T> } | DatabaseInstance | Repository<T>): Promise<T | T[]>;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
export function defineFactory<T = Record<string, any>>(
|
|
1370
|
+
modelName: string,
|
|
1371
|
+
definitionFn: (ctx: { faker: any; index: number }) => Partial<T>
|
|
1372
|
+
): FactoryBuilder<T> & {
|
|
1373
|
+
state(name: string, handler: ((ctx: { faker: any; index: number; current: Partial<T> }) => Partial<T>) | Partial<T>): FactoryBuilder<T>;
|
|
1374
|
+
registerState(name: string, handler: ((ctx: { faker: any; index: number; current: Partial<T> }) => Partial<T>) | Partial<T>): FactoryBuilder<T>;
|
|
1375
|
+
};
|
|
1376
|
+
|
|
1377
|
+
// --- ORM: Schema Diff & Makemigrations (Django-inspired) ---
|
|
1378
|
+
|
|
1379
|
+
export function diffSchema(options: { knex: Knex; models?: ModelDefinition<any>[]; includeDrops?: boolean }): Promise<{ hasChanges: boolean; changes: Array<any> }>;
|
|
1380
|
+
export function makeMigrations(options: { knex: Knex; modelsDir?: string; migrationDir?: string; dryRun?: boolean; includeDrops?: boolean; name?: string }): Promise<{ hasChanges: boolean; created: Array<any>; skipped: Array<any> }>;
|
|
1381
|
+
|
|
1195
1382
|
// --- ORM: nanoid / zod ---
|
|
1196
1383
|
|
|
1197
1384
|
export function generateNanoid(options?: { maxLength?: number } | number): string;
|
|
@@ -1533,11 +1720,73 @@ export function emailPlugin(options?: EmailPluginOptions): WebspressoPlugin & {
|
|
|
1533
1720
|
isTransportReady(): boolean;
|
|
1534
1721
|
loadFromManifest(chunks: any): void;
|
|
1535
1722
|
emailPluginOptionsFromManifest(manifest: any): any;
|
|
1723
|
+
mailer?: Mailer;
|
|
1724
|
+
Mailable?: typeof Mailable;
|
|
1725
|
+
getOutbox?(): any[];
|
|
1726
|
+
clearOutbox?(): void;
|
|
1727
|
+
lastMessage?(): any;
|
|
1536
1728
|
};
|
|
1537
1729
|
dispose?(): void;
|
|
1538
1730
|
shutdown?(): void;
|
|
1539
1731
|
};
|
|
1540
1732
|
|
|
1733
|
+
export class Mailable {
|
|
1734
|
+
constructor();
|
|
1735
|
+
to(recipient: string | string[] | any, name?: string): this;
|
|
1736
|
+
from(address: string, name?: string): this;
|
|
1737
|
+
replyTo(address: string): this;
|
|
1738
|
+
cc(recipient: string | string[]): this;
|
|
1739
|
+
bcc(recipient: string | string[]): this;
|
|
1740
|
+
subject(subj: string): this;
|
|
1741
|
+
template(tplName: string): this;
|
|
1742
|
+
html(htmlContent: string): this;
|
|
1743
|
+
text(textContent: string): this;
|
|
1744
|
+
mjml(mjmlContent: string): this;
|
|
1745
|
+
view(templateOrData: string | Record<string, unknown>, data?: Record<string, unknown>): this;
|
|
1746
|
+
data(keyOrObj: string | Record<string, unknown>, value?: any): this;
|
|
1747
|
+
attach(attachment: any): this;
|
|
1748
|
+
header(key: string, value: string): this;
|
|
1749
|
+
prepare(): void;
|
|
1750
|
+
build(): void;
|
|
1751
|
+
toMessage(): Record<string, any>;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
export class Mailer {
|
|
1755
|
+
constructor(options?: any);
|
|
1756
|
+
send(mailableOrOptions: Mailable | Record<string, any>): Promise<any>;
|
|
1757
|
+
preview(mailableOrOptions: Mailable | Record<string, any>): Promise<any>;
|
|
1758
|
+
getOutbox(): any[];
|
|
1759
|
+
clearOutbox(): void;
|
|
1760
|
+
lastMessage(): any;
|
|
1761
|
+
verify(): Promise<any>;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
export function createMailer(options?: any): Mailer;
|
|
1765
|
+
|
|
1766
|
+
export class MemoryTransport {
|
|
1767
|
+
outbox: any[];
|
|
1768
|
+
constructor(options?: any);
|
|
1769
|
+
sendMail(mailOptions: any): Promise<any>;
|
|
1770
|
+
getOutbox(): any[];
|
|
1771
|
+
clearOutbox(): void;
|
|
1772
|
+
lastMessage(): any;
|
|
1773
|
+
findById(id: string): any;
|
|
1774
|
+
verify(): Promise<boolean>;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
export class ConsoleTransport {
|
|
1778
|
+
constructor(options?: any);
|
|
1779
|
+
sendMail(mailOptions: any): Promise<any>;
|
|
1780
|
+
verify(): Promise<boolean>;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
export class FileTransport {
|
|
1784
|
+
dir: string;
|
|
1785
|
+
constructor(options?: any);
|
|
1786
|
+
sendMail(mailOptions: any): Promise<any>;
|
|
1787
|
+
verify(): Promise<boolean>;
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1541
1790
|
export function recaptchaPlugin(options?: Record<string, unknown>): WebspressoPlugin;
|
|
1542
1791
|
|
|
1543
1792
|
export interface SwaggerPluginOptions {
|
|
@@ -1795,6 +2044,82 @@ export interface ApiKeyRouteOptions {
|
|
|
1795
2044
|
export function apiKeyPlugin(options?: ApiKeyPluginOptions): WebspressoPlugin;
|
|
1796
2045
|
export function createApiKeyMiddleware(options?: ApiKeyPluginOptions & ApiKeyRouteOptions): RequestHandler;
|
|
1797
2046
|
|
|
2047
|
+
export interface WebhookEndpoint {
|
|
2048
|
+
id?: number | string;
|
|
2049
|
+
name: string;
|
|
2050
|
+
url: string;
|
|
2051
|
+
secret?: string;
|
|
2052
|
+
events?: string[] | string;
|
|
2053
|
+
is_active?: boolean;
|
|
2054
|
+
description?: string | null;
|
|
2055
|
+
headers?: Record<string, string> | string | null;
|
|
2056
|
+
metadata?: Record<string, any> | string | null;
|
|
2057
|
+
created_at?: Date | string;
|
|
2058
|
+
updated_at?: Date | string;
|
|
2059
|
+
[key: string]: any;
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
export interface WebhookDelivery {
|
|
2063
|
+
id?: number | string;
|
|
2064
|
+
endpoint_id: number | string;
|
|
2065
|
+
event: string;
|
|
2066
|
+
payload: string;
|
|
2067
|
+
status_code?: number | null;
|
|
2068
|
+
success: boolean;
|
|
2069
|
+
duration_ms?: number | null;
|
|
2070
|
+
error?: string | null;
|
|
2071
|
+
response_body?: string | null;
|
|
2072
|
+
attempt?: number;
|
|
2073
|
+
max_attempts?: number;
|
|
2074
|
+
next_retry_at?: Date | string | null;
|
|
2075
|
+
created_at?: Date | string;
|
|
2076
|
+
updated_at?: Date | string;
|
|
2077
|
+
[key: string]: any;
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
export interface WebhooksPluginOptions {
|
|
2081
|
+
db?: any;
|
|
2082
|
+
knex?: any;
|
|
2083
|
+
endpointsTable?: string;
|
|
2084
|
+
deliveriesTable?: string;
|
|
2085
|
+
maxAttempts?: number;
|
|
2086
|
+
backoffBaseMs?: number;
|
|
2087
|
+
timeoutMs?: number;
|
|
2088
|
+
wrapPayload?: boolean;
|
|
2089
|
+
queue?: any;
|
|
2090
|
+
endpoints?: WebhookEndpoint[];
|
|
2091
|
+
apiPrefix?: string;
|
|
2092
|
+
includeDefaultPage?: boolean;
|
|
2093
|
+
pageTitle?: string;
|
|
2094
|
+
menuOrder?: number;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
export interface WebhookDispatchResult {
|
|
2098
|
+
dispatched: number;
|
|
2099
|
+
deliveries: WebhookDelivery[];
|
|
2100
|
+
results?: Array<{ success?: boolean; statusCode?: number; error?: string; [key: string]: any }>;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
export interface WebhookDispatcherInstance {
|
|
2104
|
+
dispatch(event: string, payload: any, options?: { wait?: boolean; endpointId?: number | string }): Promise<WebhookDispatchResult>;
|
|
2105
|
+
pingEndpoint(endpointId: number | string): Promise<any>;
|
|
2106
|
+
retryDelivery(deliveryId: number | string): Promise<any>;
|
|
2107
|
+
createEndpoint(data: Partial<WebhookEndpoint>): Promise<WebhookEndpoint>;
|
|
2108
|
+
getEndpoint(id: number | string): Promise<WebhookEndpoint | null>;
|
|
2109
|
+
updateEndpoint(id: number | string, data: Partial<WebhookEndpoint>): Promise<WebhookEndpoint | null>;
|
|
2110
|
+
deleteEndpoint(id: number | string): Promise<boolean>;
|
|
2111
|
+
listEndpoints(filters?: { active?: boolean; search?: string; limit?: number; offset?: number }): Promise<WebhookEndpoint[]>;
|
|
2112
|
+
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 }>;
|
|
2113
|
+
getDelivery(id: number | string): Promise<WebhookDelivery | null>;
|
|
2114
|
+
purgeDeliveries(options?: { days?: number }): Promise<number>;
|
|
2115
|
+
dispose(): void;
|
|
2116
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
export function webhooksPlugin(options?: WebhooksPluginOptions): WebspressoPlugin & {
|
|
2120
|
+
dispatcher: WebhookDispatcherInstance;
|
|
2121
|
+
};
|
|
2122
|
+
|
|
1798
2123
|
export interface ContentPluginOptions {
|
|
1799
2124
|
db: import('./index').Database;
|
|
1800
2125
|
adminPath?: string;
|
|
@@ -2283,8 +2608,11 @@ export interface QueueRetentionConfig {
|
|
|
2283
2608
|
export interface ScheduleOptions {
|
|
2284
2609
|
id?: string;
|
|
2285
2610
|
overlap?: boolean;
|
|
2611
|
+
preventOverlap?: boolean;
|
|
2286
2612
|
maxRuns?: number;
|
|
2287
2613
|
utc?: boolean;
|
|
2614
|
+
timezone?: string;
|
|
2615
|
+
tz?: string;
|
|
2288
2616
|
runImmediately?: boolean;
|
|
2289
2617
|
delay?: number | Date;
|
|
2290
2618
|
attempts?: number;
|
|
@@ -2306,6 +2634,7 @@ export interface ScheduleInfo {
|
|
|
2306
2634
|
nextRunAt: Date | null;
|
|
2307
2635
|
isRunning: boolean;
|
|
2308
2636
|
activeJobId: string | number | null;
|
|
2637
|
+
activeJobIds?: (string | number)[];
|
|
2309
2638
|
registeredAt: Date;
|
|
2310
2639
|
}
|
|
2311
2640
|
|
|
@@ -2313,21 +2642,22 @@ export class CronExpression {
|
|
|
2313
2642
|
rawExpression: string;
|
|
2314
2643
|
resolvedExpression: string;
|
|
2315
2644
|
utc: boolean;
|
|
2645
|
+
timezone: string | null;
|
|
2316
2646
|
minutes: Set<number>;
|
|
2317
2647
|
hours: Set<number>;
|
|
2318
2648
|
doms: Set<number>;
|
|
2319
2649
|
months: Set<number>;
|
|
2320
2650
|
dows: Set<number>;
|
|
2321
|
-
constructor(expression: string, options?: { utc?: boolean });
|
|
2322
|
-
match(date?: Date): boolean;
|
|
2323
|
-
getNextDate(fromDate?: Date): Date | null;
|
|
2324
|
-
getNextDates(count?: number, fromDate?: Date): Date[];
|
|
2325
|
-
static isValid(expression: string): boolean;
|
|
2326
|
-
static parse(expression: string, options?: { utc?: boolean }): CronExpression;
|
|
2651
|
+
constructor(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string });
|
|
2652
|
+
match(date?: Date | string | number): boolean;
|
|
2653
|
+
getNextDate(fromDate?: Date | string | number): Date | null;
|
|
2654
|
+
getNextDates(count?: number, fromDate?: Date | string | number): Date[];
|
|
2655
|
+
static isValid(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string }): boolean;
|
|
2656
|
+
static parse(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string }): CronExpression;
|
|
2327
2657
|
}
|
|
2328
2658
|
|
|
2329
|
-
export function parseCron(expression: string, options?: { utc?: boolean }): CronExpression;
|
|
2330
|
-
export function isValidCron(expression: string): boolean;
|
|
2659
|
+
export function parseCron(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string }): CronExpression;
|
|
2660
|
+
export function isValidCron(expression: string, options?: { utc?: boolean; timezone?: string; tz?: string }): boolean;
|
|
2331
2661
|
export function resolveCronAlias(str: string): string;
|
|
2332
2662
|
export const CRON_ALIASES: Record<string, string>;
|
|
2333
2663
|
|
|
@@ -2345,6 +2675,8 @@ export class TaskScheduler {
|
|
|
2345
2675
|
trigger(idOrJobName: string): Promise<Job | null>;
|
|
2346
2676
|
start(): this;
|
|
2347
2677
|
stop(): this;
|
|
2678
|
+
pause(): this;
|
|
2679
|
+
resume(): this;
|
|
2348
2680
|
clear(): void;
|
|
2349
2681
|
destroy(): void;
|
|
2350
2682
|
}
|
|
@@ -2379,6 +2711,8 @@ export class QueueManager extends EventEmitter {
|
|
|
2379
2711
|
unschedule(idOrJobName: string): boolean;
|
|
2380
2712
|
getSchedules(): ScheduleInfo[];
|
|
2381
2713
|
getSchedule(idOrJobName: string): ScheduleInfo | null;
|
|
2714
|
+
triggerSchedule(idOrJobName: string): Promise<Job | null>;
|
|
2715
|
+
triggerCron(idOrJobName: string): Promise<Job | null>;
|
|
2382
2716
|
start(): this;
|
|
2383
2717
|
pause(): this;
|
|
2384
2718
|
resume(): this;
|
|
@@ -2453,14 +2787,20 @@ export interface HtmlStreamOptions {
|
|
|
2453
2787
|
env: import('nunjucks').Environment;
|
|
2454
2788
|
templatePath: string;
|
|
2455
2789
|
context?: Record<string, unknown>;
|
|
2456
|
-
defer?: Record<string, Promise<unknown> | { promise: Promise<unknown>; template?: string }>;
|
|
2790
|
+
defer?: Record<string, Promise<unknown> | { promise: Promise<unknown>; template?: string; loadingTemplate?: string }>;
|
|
2791
|
+
nonce?: string;
|
|
2792
|
+
loadingTemplate?: string | null;
|
|
2793
|
+
layouts?: CascadingLayoutInfo[];
|
|
2457
2794
|
}
|
|
2458
2795
|
|
|
2459
2796
|
export interface RenderStreamOptions {
|
|
2460
2797
|
env?: import('nunjucks').Environment;
|
|
2461
|
-
defer?: Record<string, Promise<unknown> | { promise: Promise<unknown>; template?: string }>;
|
|
2798
|
+
defer?: Record<string, Promise<unknown> | { promise: Promise<unknown>; template?: string; loadingTemplate?: string }>;
|
|
2462
2799
|
status?: number;
|
|
2463
2800
|
flushImmediately?: boolean;
|
|
2801
|
+
nonce?: string;
|
|
2802
|
+
loadingTemplate?: string | null;
|
|
2803
|
+
layouts?: CascadingLayoutInfo[];
|
|
2464
2804
|
}
|
|
2465
2805
|
|
|
2466
2806
|
export function createHtmlStream(options: HtmlStreamOptions): import('stream').Readable;
|
|
@@ -3155,10 +3495,196 @@ export namespace totp {
|
|
|
3155
3495
|
};
|
|
3156
3496
|
}
|
|
3157
3497
|
|
|
3498
|
+
// --- Magic Link / Passwordless Authentication ---
|
|
3158
3499
|
|
|
3500
|
+
export interface BuildMagicLinkUrlOptions {
|
|
3501
|
+
baseUrl?: string;
|
|
3502
|
+
path?: string;
|
|
3503
|
+
token: string;
|
|
3504
|
+
}
|
|
3159
3505
|
|
|
3506
|
+
export interface FormatMagicLinkHtmlOptions {
|
|
3507
|
+
name?: string;
|
|
3508
|
+
magicLinkUrl: string;
|
|
3509
|
+
expiresMinutes?: number;
|
|
3510
|
+
}
|
|
3160
3511
|
|
|
3512
|
+
export interface MagicLinkVerifyMiddlewareOptions {
|
|
3513
|
+
tokenParam?: string;
|
|
3514
|
+
redirectTo?: string;
|
|
3515
|
+
failureRedirect?: string;
|
|
3516
|
+
markEmailVerified?: boolean;
|
|
3517
|
+
jwt?: boolean;
|
|
3518
|
+
}
|
|
3161
3519
|
|
|
3520
|
+
export interface MagicLinkRequestOptions {
|
|
3521
|
+
baseUrl?: string;
|
|
3522
|
+
path?: string;
|
|
3523
|
+
tokenTtlMs?: number;
|
|
3524
|
+
hideUserNotFound?: boolean;
|
|
3525
|
+
buildMagicLinkUrl?: (token: string) => string;
|
|
3526
|
+
}
|
|
3162
3527
|
|
|
3528
|
+
export interface MagicLinkRequestResult {
|
|
3529
|
+
sent: boolean;
|
|
3530
|
+
userFound: boolean;
|
|
3531
|
+
expiresAt?: Date;
|
|
3532
|
+
token?: string;
|
|
3533
|
+
magicLinkUrl?: string;
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
export interface MagicLinkVerifyResult {
|
|
3537
|
+
ok: true;
|
|
3538
|
+
user: any;
|
|
3539
|
+
userId: string | number;
|
|
3540
|
+
accessToken?: string;
|
|
3541
|
+
refreshToken?: string;
|
|
3542
|
+
}
|
|
3543
|
+
|
|
3544
|
+
export function buildMagicLinkUrl(options: BuildMagicLinkUrlOptions): string;
|
|
3545
|
+
export function formatMagicLinkHtml(options: FormatMagicLinkHtmlOptions): string;
|
|
3546
|
+
export function createMagicLinkVerifyMiddleware(authManager: any, options?: MagicLinkVerifyMiddlewareOptions): (req: any, res: any, next: any) => Promise<any>;
|
|
3547
|
+
export function createMagicLinkRequestHandler(authManager: any, options?: MagicLinkRequestOptions): (req: any, res: any) => Promise<any>;
|
|
3548
|
+
|
|
3549
|
+
export namespace magicLink {
|
|
3550
|
+
export {
|
|
3551
|
+
buildMagicLinkUrl,
|
|
3552
|
+
formatMagicLinkHtml,
|
|
3553
|
+
createMagicLinkVerifyMiddleware,
|
|
3554
|
+
createMagicLinkRequestHandler,
|
|
3555
|
+
};
|
|
3556
|
+
}
|
|
3557
|
+
|
|
3558
|
+
// Active Devices & Session Management
|
|
3559
|
+
export interface DeviceInfo {
|
|
3560
|
+
browser: string;
|
|
3561
|
+
os: string;
|
|
3562
|
+
device: 'desktop' | 'mobile' | 'tablet' | 'bot' | 'unknown';
|
|
3563
|
+
isMobile: boolean;
|
|
3564
|
+
isTablet: boolean;
|
|
3565
|
+
isDesktop: boolean;
|
|
3566
|
+
isBot: boolean;
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
export interface UserSession {
|
|
3570
|
+
id?: number | string;
|
|
3571
|
+
session_id: string;
|
|
3572
|
+
user_id: number | string;
|
|
3573
|
+
ip_address?: string | null;
|
|
3574
|
+
user_agent?: string | null;
|
|
3575
|
+
browser?: string | null;
|
|
3576
|
+
os?: string | null;
|
|
3577
|
+
device?: string | null;
|
|
3578
|
+
last_active_at: Date;
|
|
3579
|
+
created_at?: Date;
|
|
3580
|
+
is_current?: boolean;
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
export interface SessionTracker {
|
|
3584
|
+
track(sessionId: string, userId: string | number, metadata?: { ip?: string; userAgent?: string; browser?: string; os?: string; device?: string }): Promise<UserSession | null>;
|
|
3585
|
+
touch(sessionId: string): Promise<boolean>;
|
|
3586
|
+
get(sessionId: string): Promise<UserSession | null>;
|
|
3587
|
+
list(userId: string | number, currentSessionId?: string | null): Promise<UserSession[]>;
|
|
3588
|
+
isSessionValid(sessionId: string, userId?: string | number | null): Promise<boolean>;
|
|
3589
|
+
revoke(sessionId: string): Promise<boolean>;
|
|
3590
|
+
revokeOthers(userId: string | number, currentSessionId?: string | null): Promise<number>;
|
|
3591
|
+
revokeAll(userId: string | number): Promise<number>;
|
|
3592
|
+
purgeExpired(maxAgeMs: number): Promise<number>;
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3595
|
+
export interface SessionManagerOptions {
|
|
3596
|
+
tracker?: SessionTracker;
|
|
3597
|
+
sessionStore?: any;
|
|
3598
|
+
touchThrottleMs?: number;
|
|
3599
|
+
emitter?: any;
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
export class SessionManager {
|
|
3603
|
+
constructor(options?: SessionManagerOptions);
|
|
3604
|
+
tracker: SessionTracker;
|
|
3605
|
+
sessionStore?: any;
|
|
3606
|
+
touchThrottleMs: number;
|
|
3607
|
+
emitter?: any;
|
|
3608
|
+
track(sessionId: string, userId: string | number, req?: any): Promise<UserSession | null>;
|
|
3609
|
+
touch(sessionId: string): Promise<boolean>;
|
|
3610
|
+
isSessionValid(sessionId: string, userId?: string | number | null): Promise<boolean>;
|
|
3611
|
+
listSessions(userId: string | number, currentSessionId?: string | null): Promise<UserSession[]>;
|
|
3612
|
+
revokeSession(sessionId: string, options?: { userId?: string | number; revokedBy?: string }): Promise<boolean>;
|
|
3613
|
+
revokeOtherSessions(userId: string | number, currentSessionId: string): Promise<number>;
|
|
3614
|
+
revokeAllSessions(userId: string | number): Promise<number>;
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3617
|
+
export function parseUserAgent(userAgent?: string): DeviceInfo;
|
|
3618
|
+
export function getClientIp(req?: any): string;
|
|
3619
|
+
export function createUserSessionsTable(knex: any): Promise<void>;
|
|
3620
|
+
export function dropUserSessionsTable(knex: any): Promise<void>;
|
|
3621
|
+
export function createKnexSessionTracker(db: any, options?: { tableName?: string }): SessionTracker;
|
|
3622
|
+
export function createMemorySessionTracker(): SessionTracker;
|
|
3623
|
+
export function createListSessionsHandler(authManager: any): (req: any, res: any) => Promise<any>;
|
|
3624
|
+
export function createRevokeSessionHandler(authManager: any): (req: any, res: any) => Promise<any>;
|
|
3625
|
+
|
|
3626
|
+
export namespace sessions {
|
|
3627
|
+
export {
|
|
3628
|
+
SessionManager,
|
|
3629
|
+
createUserSessionsTable,
|
|
3630
|
+
dropUserSessionsTable,
|
|
3631
|
+
createKnexSessionTracker,
|
|
3632
|
+
createMemorySessionTracker,
|
|
3633
|
+
getClientIp,
|
|
3634
|
+
parseUserAgent,
|
|
3635
|
+
createListSessionsHandler,
|
|
3636
|
+
createRevokeSessionHandler,
|
|
3637
|
+
};
|
|
3638
|
+
}
|
|
3639
|
+
|
|
3640
|
+
// Custom Management Commands (Django & Adonis Ace-inspired)
|
|
3641
|
+
export interface CommandOption {
|
|
3642
|
+
flags: string;
|
|
3643
|
+
description?: string;
|
|
3644
|
+
defaultValue?: any;
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
export interface CommandExecutionContext {
|
|
3648
|
+
db: any;
|
|
3649
|
+
queue: any;
|
|
3650
|
+
services: any;
|
|
3651
|
+
mailer: any;
|
|
3652
|
+
events: any;
|
|
3653
|
+
logger: any;
|
|
3654
|
+
args: string[];
|
|
3655
|
+
flags: Record<string, any>;
|
|
3656
|
+
}
|
|
3657
|
+
|
|
3658
|
+
export interface CommandDefinition {
|
|
3659
|
+
name: string;
|
|
3660
|
+
description?: string;
|
|
3661
|
+
options?: CommandOption[];
|
|
3662
|
+
handle: (ctx: CommandExecutionContext) => Promise<any> | any;
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
export interface CommandRegistry {
|
|
3666
|
+
register(cmd: CommandDefinition): CommandDefinition;
|
|
3667
|
+
reload(): void;
|
|
3668
|
+
has(name: string): boolean;
|
|
3669
|
+
get(name: string): CommandDefinition | null;
|
|
3670
|
+
list(): CommandDefinition[];
|
|
3671
|
+
names(): string[];
|
|
3672
|
+
readonly commandsDir: string;
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3675
|
+
export function defineCommand(definition: CommandDefinition): CommandDefinition;
|
|
3676
|
+
export function createCommandRegistry(options?: { commandsDir?: string; autoLoad?: boolean }): CommandRegistry;
|
|
3677
|
+
export function executeCommand(
|
|
3678
|
+
commandDef: CommandDefinition,
|
|
3679
|
+
executionOptions?: Partial<CommandExecutionContext>
|
|
3680
|
+
): Promise<{ success: boolean; result?: any; error?: Error; durationMs: number }>;
|
|
3681
|
+
|
|
3682
|
+
export namespace commands {
|
|
3683
|
+
export {
|
|
3684
|
+
defineCommand,
|
|
3685
|
+
createCommandRegistry,
|
|
3686
|
+
executeCommand,
|
|
3687
|
+
};
|
|
3688
|
+
}
|
|
3163
3689
|
|
|
3164
3690
|
|