drizzle-multitenant 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1067 @@
1
+ import { C as Config } from './types-CGqsPe2Q.js';
2
+ import { Pool } from 'pg';
3
+ import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
4
+
5
+ /**
6
+ * Table format for tracking migrations
7
+ * - "name": drizzle-multitenant native (filename-based)
8
+ * - "hash": SHA-256 hash with timestamp
9
+ * - "drizzle-kit": Exact drizzle-kit format (hash + bigint timestamp)
10
+ */
11
+ type TableFormat = 'name' | 'hash' | 'drizzle-kit';
12
+ /**
13
+ * Detected table format information
14
+ */
15
+ interface DetectedFormat {
16
+ /** The detected format type */
17
+ format: TableFormat;
18
+ /** The table name */
19
+ tableName: string;
20
+ /** Column configuration */
21
+ columns: {
22
+ /** Column used for identifying migrations */
23
+ identifier: 'name' | 'hash';
24
+ /** Column used for timestamp */
25
+ timestamp: 'applied_at' | 'created_at';
26
+ /** Data type of timestamp column */
27
+ timestampType: 'timestamp' | 'bigint';
28
+ };
29
+ }
30
+ /**
31
+ * Default format configuration for new tables
32
+ */
33
+ declare const DEFAULT_FORMAT: DetectedFormat;
34
+ /**
35
+ * drizzle-kit format configuration
36
+ */
37
+ declare const DRIZZLE_KIT_FORMAT: DetectedFormat;
38
+ /**
39
+ * Detect the format of an existing migrations table
40
+ *
41
+ * @param pool - Database connection pool
42
+ * @param schemaName - Schema to check
43
+ * @param tableName - Migrations table name
44
+ * @returns Detected format or null if table doesn't exist
45
+ */
46
+ declare function detectTableFormat(pool: Pool, schemaName: string, tableName: string): Promise<DetectedFormat | null>;
47
+ /**
48
+ * Get the format configuration for a specific format type
49
+ */
50
+ declare function getFormatConfig(format: TableFormat, tableName?: string): DetectedFormat;
51
+
52
+ /**
53
+ * Types for tenant cloning module
54
+ * @module clone/types
55
+ */
56
+
57
+ /**
58
+ * Value to use for anonymization (v1: null or fixed value)
59
+ */
60
+ type AnonymizeValue = null | string | number | boolean;
61
+ /**
62
+ * Anonymization rules by table and column
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * const rules: AnonymizeRules = {
67
+ * users: {
68
+ * email: null,
69
+ * phone: null,
70
+ * ssn: '000-00-0000',
71
+ * },
72
+ * payments: {
73
+ * card_number: null,
74
+ * },
75
+ * };
76
+ * ```
77
+ */
78
+ interface AnonymizeRules {
79
+ [tableName: string]: {
80
+ [columnName: string]: AnonymizeValue;
81
+ };
82
+ }
83
+ /**
84
+ * Anonymization options
85
+ */
86
+ interface AnonymizeOptions {
87
+ /** Enable anonymization */
88
+ enabled: boolean;
89
+ /** Rules per table/column */
90
+ rules?: AnonymizeRules;
91
+ }
92
+ /**
93
+ * Options for cloning a tenant
94
+ */
95
+ interface CloneTenantOptions {
96
+ /** Include data (default: false, schema only) */
97
+ includeData?: boolean;
98
+ /** Anonymize sensitive data */
99
+ anonymize?: AnonymizeOptions;
100
+ /** Tables to exclude from cloning */
101
+ excludeTables?: string[];
102
+ /** Progress callback */
103
+ onProgress?: CloneProgressCallback;
104
+ /** Error handler */
105
+ onError?: (error: Error) => 'continue' | 'abort';
106
+ }
107
+ /**
108
+ * Progress status for cloning operation
109
+ */
110
+ type CloneProgressStatus = 'starting' | 'introspecting' | 'creating_schema' | 'creating_tables' | 'creating_indexes' | 'creating_constraints' | 'copying_data' | 'completed' | 'failed';
111
+ /**
112
+ * Progress callback for cloning
113
+ */
114
+ type CloneProgressCallback = (status: CloneProgressStatus, details?: {
115
+ table?: string;
116
+ progress?: number;
117
+ total?: number;
118
+ }) => void;
119
+ /**
120
+ * Result of cloning a tenant
121
+ */
122
+ interface CloneTenantResult {
123
+ /** Source tenant ID */
124
+ sourceTenant: string;
125
+ /** Target tenant ID */
126
+ targetTenant: string;
127
+ /** Target schema name */
128
+ targetSchema: string;
129
+ /** Whether the operation was successful */
130
+ success: boolean;
131
+ /** Error message if failed */
132
+ error?: string;
133
+ /** Tables cloned */
134
+ tables: string[];
135
+ /** Number of rows copied (if includeData) */
136
+ rowsCopied?: number;
137
+ /** Duration in milliseconds */
138
+ durationMs: number;
139
+ }
140
+ /**
141
+ * Configuration for Cloner
142
+ */
143
+ interface ClonerConfig {
144
+ /** Migrations table name (excluded from data copy) */
145
+ migrationsTable?: string;
146
+ }
147
+ /**
148
+ * Dependencies for Cloner
149
+ */
150
+ interface ClonerDependencies {
151
+ /** Create pool for specific schema */
152
+ createPool: (schemaName: string) => Promise<Pool>;
153
+ /** Create pool without schema (root) */
154
+ createRootPool: () => Promise<Pool>;
155
+ /** Schema name template function */
156
+ schemaNameTemplate: (tenantId: string) => string;
157
+ /** Check if schema exists */
158
+ schemaExists: (tenantId: string) => Promise<boolean>;
159
+ /** Create schema */
160
+ createSchema: (tenantId: string) => Promise<void>;
161
+ }
162
+
163
+ /**
164
+ * Seed function signature
165
+ * Called with the tenant database instance and tenant ID
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * const seed: SeedFunction = async (db, tenantId) => {
170
+ * await db.insert(roles).values([
171
+ * { name: 'admin', permissions: ['*'] },
172
+ * { name: 'user', permissions: ['read'] },
173
+ * ]);
174
+ * };
175
+ * ```
176
+ */
177
+ type SeedFunction<TSchema extends Record<string, unknown> = Record<string, unknown>> = (db: PostgresJsDatabase<TSchema>, tenantId: string) => Promise<void>;
178
+ /**
179
+ * Seed result for a single tenant
180
+ */
181
+ interface TenantSeedResult {
182
+ tenantId: string;
183
+ schemaName: string;
184
+ success: boolean;
185
+ error?: string;
186
+ durationMs: number;
187
+ }
188
+ /**
189
+ * Aggregate seed results
190
+ */
191
+ interface SeedResults {
192
+ total: number;
193
+ succeeded: number;
194
+ failed: number;
195
+ skipped: number;
196
+ details: TenantSeedResult[];
197
+ }
198
+ /**
199
+ * Options for seed operations
200
+ */
201
+ interface SeedOptions {
202
+ /** Number of concurrent seed operations */
203
+ concurrency?: number;
204
+ /** Progress callback */
205
+ onProgress?: (tenantId: string, status: 'starting' | 'seeding' | 'completed' | 'failed' | 'skipped') => void;
206
+ /** Error handler */
207
+ onError?: (tenantId: string, error: Error) => 'continue' | 'abort';
208
+ }
209
+ /**
210
+ * Migration file metadata
211
+ */
212
+ interface MigrationFile {
213
+ /** Migration file name */
214
+ name: string;
215
+ /** Full file path */
216
+ path: string;
217
+ /** SQL content */
218
+ sql: string;
219
+ /** Timestamp extracted from filename */
220
+ timestamp: number;
221
+ /** SHA-256 hash of file content (for drizzle-kit compatibility) */
222
+ hash: string;
223
+ }
224
+ /**
225
+ * Migration status for a tenant
226
+ */
227
+ interface TenantMigrationStatus {
228
+ tenantId: string;
229
+ schemaName: string;
230
+ appliedCount: number;
231
+ pendingCount: number;
232
+ pendingMigrations: string[];
233
+ status: 'ok' | 'behind' | 'error';
234
+ error?: string;
235
+ /** Detected table format (null for new tenants without migrations table) */
236
+ format: TableFormat | null;
237
+ }
238
+ /**
239
+ * Migration result for a single tenant
240
+ */
241
+ interface TenantMigrationResult {
242
+ tenantId: string;
243
+ schemaName: string;
244
+ success: boolean;
245
+ appliedMigrations: string[];
246
+ error?: string;
247
+ durationMs: number;
248
+ /** Table format used for this migration */
249
+ format?: TableFormat;
250
+ }
251
+ /**
252
+ * Aggregate migration results
253
+ */
254
+ interface MigrationResults {
255
+ total: number;
256
+ succeeded: number;
257
+ failed: number;
258
+ skipped: number;
259
+ details: TenantMigrationResult[];
260
+ }
261
+ /**
262
+ * Progress callback for migrations
263
+ */
264
+ type MigrationProgressCallback = (tenantId: string, status: 'starting' | 'migrating' | 'completed' | 'failed' | 'skipped', migrationName?: string) => void;
265
+ /**
266
+ * Error handler for migrations
267
+ */
268
+ type MigrationErrorHandler = (tenantId: string, error: Error) => 'continue' | 'abort';
269
+ /**
270
+ * Migration hooks
271
+ */
272
+ interface MigrationHooks {
273
+ /** Called before migrating a tenant */
274
+ beforeTenant?: (tenantId: string) => void | Promise<void>;
275
+ /** Called after migrating a tenant */
276
+ afterTenant?: (tenantId: string, result: TenantMigrationResult) => void | Promise<void>;
277
+ /** Called before applying a migration */
278
+ beforeMigration?: (tenantId: string, migrationName: string) => void | Promise<void>;
279
+ /** Called after applying a migration */
280
+ afterMigration?: (tenantId: string, migrationName: string, durationMs: number) => void | Promise<void>;
281
+ }
282
+ /**
283
+ * Migrator configuration
284
+ */
285
+ interface MigratorConfig {
286
+ /** Path to tenant migrations folder */
287
+ migrationsFolder: string;
288
+ /** Table name for tracking migrations */
289
+ migrationsTable?: string;
290
+ /** Function to discover tenant IDs */
291
+ tenantDiscovery: () => Promise<string[]>;
292
+ /** Migration hooks */
293
+ hooks?: MigrationHooks;
294
+ /**
295
+ * Table format for tracking migrations
296
+ * - "auto": Auto-detect existing format, use defaultFormat for new tables
297
+ * - "name": Use filename (drizzle-multitenant native)
298
+ * - "hash": Use SHA-256 hash
299
+ * - "drizzle-kit": Exact drizzle-kit format (hash + bigint timestamp)
300
+ * @default "auto"
301
+ */
302
+ tableFormat?: 'auto' | TableFormat;
303
+ /**
304
+ * When using "auto" format and no table exists, which format to create
305
+ * @default "name"
306
+ */
307
+ defaultFormat?: TableFormat;
308
+ /**
309
+ * Path to shared schema migrations folder
310
+ * If provided, enables shared schema migration support
311
+ */
312
+ sharedMigrationsFolder?: string;
313
+ /**
314
+ * Table name for tracking shared migrations
315
+ * @default "__drizzle_shared_migrations"
316
+ */
317
+ sharedMigrationsTable?: string;
318
+ /**
319
+ * Hooks for shared schema migrations
320
+ */
321
+ sharedHooks?: SharedMigrationHooks;
322
+ }
323
+ /**
324
+ * Migrate options
325
+ */
326
+ interface MigrateOptions {
327
+ /** Number of concurrent migrations */
328
+ concurrency?: number;
329
+ /** Progress callback */
330
+ onProgress?: MigrationProgressCallback;
331
+ /** Error handler */
332
+ onError?: MigrationErrorHandler;
333
+ /** Dry run mode */
334
+ dryRun?: boolean;
335
+ }
336
+ /**
337
+ * Tenant creation options
338
+ */
339
+ interface CreateTenantOptions {
340
+ /** Apply all migrations after creating schema */
341
+ migrate?: boolean;
342
+ }
343
+ /**
344
+ * Tenant drop options
345
+ */
346
+ interface DropTenantOptions {
347
+ /** Skip confirmation (force drop) */
348
+ force?: boolean;
349
+ /** Cascade drop */
350
+ cascade?: boolean;
351
+ }
352
+ /**
353
+ * Applied migration record
354
+ */
355
+ interface AppliedMigration {
356
+ id: number;
357
+ /** Migration identifier (name or hash depending on format) */
358
+ identifier: string;
359
+ /** Migration name (only available in name-based format) */
360
+ name?: string;
361
+ /** Migration hash (only available in hash-based format) */
362
+ hash?: string;
363
+ appliedAt: Date;
364
+ }
365
+ /**
366
+ * Sync status for a single tenant
367
+ */
368
+ interface TenantSyncStatus {
369
+ tenantId: string;
370
+ schemaName: string;
371
+ /** Migrations in disk but not tracked in database */
372
+ missing: string[];
373
+ /** Migrations tracked in database but not found in disk */
374
+ orphans: string[];
375
+ /** Whether the tenant is in sync */
376
+ inSync: boolean;
377
+ /** Table format used */
378
+ format: TableFormat | null;
379
+ /** Error if any */
380
+ error?: string;
381
+ }
382
+ /**
383
+ * Aggregate sync status
384
+ */
385
+ interface SyncStatus {
386
+ total: number;
387
+ inSync: number;
388
+ outOfSync: number;
389
+ error: number;
390
+ details: TenantSyncStatus[];
391
+ }
392
+ /**
393
+ * Sync result for a single tenant
394
+ */
395
+ interface TenantSyncResult {
396
+ tenantId: string;
397
+ schemaName: string;
398
+ success: boolean;
399
+ /** Migrations that were marked as applied */
400
+ markedMigrations: string[];
401
+ /** Orphan records that were removed */
402
+ removedOrphans: string[];
403
+ error?: string;
404
+ durationMs: number;
405
+ }
406
+ /**
407
+ * Aggregate sync results
408
+ */
409
+ interface SyncResults {
410
+ total: number;
411
+ succeeded: number;
412
+ failed: number;
413
+ details: TenantSyncResult[];
414
+ }
415
+ /**
416
+ * Options for sync operations
417
+ */
418
+ interface SyncOptions {
419
+ /** Number of concurrent operations */
420
+ concurrency?: number;
421
+ /** Progress callback */
422
+ onProgress?: (tenantId: string, status: 'starting' | 'syncing' | 'completed' | 'failed') => void;
423
+ /** Error handler */
424
+ onError?: MigrationErrorHandler;
425
+ }
426
+ /**
427
+ * Column information from database introspection
428
+ */
429
+ interface ColumnInfo {
430
+ /** Column name */
431
+ name: string;
432
+ /** PostgreSQL data type */
433
+ dataType: string;
434
+ /** Full data type (e.g., varchar(255)) */
435
+ udtName: string;
436
+ /** Whether column is nullable */
437
+ isNullable: boolean;
438
+ /** Default value expression */
439
+ columnDefault: string | null;
440
+ /** Character maximum length for varchar/char */
441
+ characterMaximumLength: number | null;
442
+ /** Numeric precision for numeric types */
443
+ numericPrecision: number | null;
444
+ /** Numeric scale for numeric types */
445
+ numericScale: number | null;
446
+ /** Ordinal position in table */
447
+ ordinalPosition: number;
448
+ }
449
+ /**
450
+ * Index information from database introspection
451
+ */
452
+ interface IndexInfo {
453
+ /** Index name */
454
+ name: string;
455
+ /** Column names in the index */
456
+ columns: string[];
457
+ /** Whether index is unique */
458
+ isUnique: boolean;
459
+ /** Whether index is primary key */
460
+ isPrimary: boolean;
461
+ /** Index definition SQL */
462
+ definition: string;
463
+ }
464
+ /**
465
+ * Constraint information from database introspection
466
+ */
467
+ interface ConstraintInfo {
468
+ /** Constraint name */
469
+ name: string;
470
+ /** Constraint type (PRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK) */
471
+ type: 'PRIMARY KEY' | 'FOREIGN KEY' | 'UNIQUE' | 'CHECK';
472
+ /** Columns involved in constraint */
473
+ columns: string[];
474
+ /** Foreign table (for foreign keys) */
475
+ foreignTable?: string;
476
+ /** Foreign columns (for foreign keys) */
477
+ foreignColumns?: string[];
478
+ /** Check expression (for check constraints) */
479
+ checkExpression?: string;
480
+ }
481
+ /**
482
+ * Table schema information
483
+ */
484
+ interface TableSchema {
485
+ /** Table name */
486
+ name: string;
487
+ /** Columns in the table */
488
+ columns: ColumnInfo[];
489
+ /** Indexes on the table */
490
+ indexes: IndexInfo[];
491
+ /** Constraints on the table */
492
+ constraints: ConstraintInfo[];
493
+ }
494
+ /**
495
+ * Full schema for a tenant
496
+ */
497
+ interface TenantSchema {
498
+ /** Tenant ID */
499
+ tenantId: string;
500
+ /** Schema name */
501
+ schemaName: string;
502
+ /** Tables in the schema */
503
+ tables: TableSchema[];
504
+ /** Introspection timestamp */
505
+ introspectedAt: Date;
506
+ }
507
+ /**
508
+ * Column drift details
509
+ */
510
+ interface ColumnDrift {
511
+ /** Column name */
512
+ column: string;
513
+ /** Type of drift */
514
+ type: 'missing' | 'extra' | 'type_mismatch' | 'nullable_mismatch' | 'default_mismatch';
515
+ /** Expected value (from reference) */
516
+ expected?: string | boolean | null;
517
+ /** Actual value (from tenant) */
518
+ actual?: string | boolean | null;
519
+ /** Human-readable description */
520
+ description: string;
521
+ }
522
+ /**
523
+ * Index drift details
524
+ */
525
+ interface IndexDrift {
526
+ /** Index name */
527
+ index: string;
528
+ /** Type of drift */
529
+ type: 'missing' | 'extra' | 'definition_mismatch';
530
+ /** Expected definition */
531
+ expected?: string;
532
+ /** Actual definition */
533
+ actual?: string;
534
+ /** Human-readable description */
535
+ description: string;
536
+ }
537
+ /**
538
+ * Constraint drift details
539
+ */
540
+ interface ConstraintDrift {
541
+ /** Constraint name */
542
+ constraint: string;
543
+ /** Type of drift */
544
+ type: 'missing' | 'extra' | 'definition_mismatch';
545
+ /** Expected details */
546
+ expected?: string;
547
+ /** Actual details */
548
+ actual?: string;
549
+ /** Human-readable description */
550
+ description: string;
551
+ }
552
+ /**
553
+ * Table drift details
554
+ */
555
+ interface TableDrift {
556
+ /** Table name */
557
+ table: string;
558
+ /** Whether the entire table is missing or extra */
559
+ status: 'ok' | 'missing' | 'extra' | 'drifted';
560
+ /** Column drifts */
561
+ columns: ColumnDrift[];
562
+ /** Index drifts */
563
+ indexes: IndexDrift[];
564
+ /** Constraints drifts */
565
+ constraints: ConstraintDrift[];
566
+ }
567
+ /**
568
+ * Schema drift for a single tenant
569
+ */
570
+ interface TenantSchemaDrift {
571
+ /** Tenant ID */
572
+ tenantId: string;
573
+ /** Schema name */
574
+ schemaName: string;
575
+ /** Whether schema has drift */
576
+ hasDrift: boolean;
577
+ /** Table-level drifts */
578
+ tables: TableDrift[];
579
+ /** Total number of issues */
580
+ issueCount: number;
581
+ /** Error if introspection failed */
582
+ error?: string;
583
+ }
584
+ /**
585
+ * Aggregate schema drift status
586
+ */
587
+ interface SchemaDriftStatus {
588
+ /** Reference tenant used for comparison */
589
+ referenceTenant: string;
590
+ /** Total tenants checked */
591
+ total: number;
592
+ /** Tenants without drift */
593
+ noDrift: number;
594
+ /** Tenants with drift */
595
+ withDrift: number;
596
+ /** Tenants with errors */
597
+ error: number;
598
+ /** Detailed results per tenant */
599
+ details: TenantSchemaDrift[];
600
+ /** Timestamp of the check */
601
+ timestamp: string;
602
+ /** Duration of the check in ms */
603
+ durationMs: number;
604
+ }
605
+ /**
606
+ * Options for schema drift detection
607
+ */
608
+ interface SchemaDriftOptions {
609
+ /** Tenant ID to use as reference (default: first tenant) */
610
+ referenceTenant?: string;
611
+ /** Specific tenant IDs to check (default: all tenants) */
612
+ tenantIds?: string[];
613
+ /** Number of concurrent checks */
614
+ concurrency?: number;
615
+ /** Whether to include index comparison */
616
+ includeIndexes?: boolean;
617
+ /** Whether to include constraint comparison */
618
+ includeConstraints?: boolean;
619
+ /** Tables to exclude from comparison */
620
+ excludeTables?: string[];
621
+ /** Progress callback */
622
+ onProgress?: (tenantId: string, status: 'starting' | 'introspecting' | 'comparing' | 'completed' | 'failed') => void;
623
+ }
624
+
625
+ /**
626
+ * Migration status for the shared schema (public)
627
+ */
628
+ interface SharedMigrationStatus {
629
+ /** Schema name (usually 'public') */
630
+ schemaName: string;
631
+ /** Number of applied migrations */
632
+ appliedCount: number;
633
+ /** Number of pending migrations */
634
+ pendingCount: number;
635
+ /** Names of pending migrations */
636
+ pendingMigrations: string[];
637
+ /** Overall status */
638
+ status: 'ok' | 'behind' | 'error';
639
+ /** Error message if status is 'error' */
640
+ error?: string;
641
+ /** Detected table format */
642
+ format: TableFormat | null;
643
+ }
644
+ /**
645
+ * Migration result for the shared schema
646
+ */
647
+ interface SharedMigrationResult {
648
+ /** Schema name (usually 'public') */
649
+ schemaName: string;
650
+ /** Whether migration was successful */
651
+ success: boolean;
652
+ /** List of applied migration names */
653
+ appliedMigrations: string[];
654
+ /** Error message if failed */
655
+ error?: string;
656
+ /** Duration in milliseconds */
657
+ durationMs: number;
658
+ /** Table format used */
659
+ format?: TableFormat;
660
+ }
661
+ /**
662
+ * Shared migration configuration (extends MigratorConfig)
663
+ */
664
+ interface SharedMigratorConfig {
665
+ /** Path to shared schema migrations folder */
666
+ sharedMigrationsFolder: string;
667
+ /** Table name for tracking shared migrations (default: '__drizzle_shared_migrations') */
668
+ sharedMigrationsTable?: string;
669
+ /** Migration hooks for shared schema */
670
+ hooks?: SharedMigrationHooks;
671
+ /**
672
+ * Table format for tracking migrations
673
+ * @default "auto"
674
+ */
675
+ tableFormat?: 'auto' | TableFormat;
676
+ /**
677
+ * Default format when creating new table
678
+ * @default "name"
679
+ */
680
+ defaultFormat?: TableFormat;
681
+ }
682
+ /**
683
+ * Hooks for shared schema migrations
684
+ */
685
+ interface SharedMigrationHooks {
686
+ /** Called before starting shared migration */
687
+ beforeMigration?: () => void | Promise<void>;
688
+ /** Called after shared migration completes */
689
+ afterMigration?: (result: SharedMigrationResult) => void | Promise<void>;
690
+ /** Called before applying a specific migration */
691
+ beforeApply?: (migrationName: string) => void | Promise<void>;
692
+ /** Called after applying a specific migration */
693
+ afterApply?: (migrationName: string, durationMs: number) => void | Promise<void>;
694
+ }
695
+ /**
696
+ * Options for shared migration operations
697
+ */
698
+ interface SharedMigrateOptions {
699
+ /** Dry run mode - show what would be applied without executing */
700
+ dryRun?: boolean;
701
+ /** Progress callback */
702
+ onProgress?: (status: 'starting' | 'migrating' | 'completed' | 'failed', migrationName?: string) => void;
703
+ }
704
+ /**
705
+ * Seed function signature for shared schema
706
+ * Called with the shared database instance
707
+ */
708
+ type SharedSeedFunction<TSchema extends Record<string, unknown> = Record<string, unknown>> = (db: PostgresJsDatabase<TSchema>) => Promise<void>;
709
+ /**
710
+ * Result of shared schema seeding
711
+ */
712
+ interface SharedSeedResult {
713
+ /** Schema name (usually 'public') */
714
+ schemaName: string;
715
+ /** Whether seeding was successful */
716
+ success: boolean;
717
+ /** Error message if failed */
718
+ error?: string;
719
+ /** Duration in milliseconds */
720
+ durationMs: number;
721
+ }
722
+
723
+ /**
724
+ * Parallel migration engine for multi-tenant applications
725
+ */
726
+ declare class Migrator<TTenantSchema extends Record<string, unknown>, TSharedSchema extends Record<string, unknown>> {
727
+ private readonly migratorConfig;
728
+ private readonly migrationsTable;
729
+ private readonly schemaManager;
730
+ private readonly driftDetector;
731
+ private readonly seeder;
732
+ private readonly syncManager;
733
+ private readonly migrationExecutor;
734
+ private readonly batchExecutor;
735
+ private readonly cloner;
736
+ private readonly sharedMigrationExecutor;
737
+ private readonly sharedSeeder;
738
+ constructor(tenantConfig: Config<TTenantSchema, TSharedSchema>, migratorConfig: MigratorConfig);
739
+ /**
740
+ * Migrate all tenants in parallel
741
+ *
742
+ * Delegates to BatchExecutor for parallel migration operations.
743
+ */
744
+ migrateAll(options?: MigrateOptions): Promise<MigrationResults>;
745
+ /**
746
+ * Migrate a single tenant
747
+ *
748
+ * Delegates to MigrationExecutor for single tenant operations.
749
+ */
750
+ migrateTenant(tenantId: string, migrations?: MigrationFile[], options?: {
751
+ dryRun?: boolean;
752
+ onProgress?: MigrateOptions['onProgress'];
753
+ }): Promise<TenantMigrationResult>;
754
+ /**
755
+ * Migrate specific tenants
756
+ *
757
+ * Delegates to BatchExecutor for parallel migration operations.
758
+ */
759
+ migrateTenants(tenantIds: string[], options?: MigrateOptions): Promise<MigrationResults>;
760
+ /**
761
+ * Get migration status for all tenants
762
+ *
763
+ * Delegates to BatchExecutor for status operations.
764
+ */
765
+ getStatus(): Promise<TenantMigrationStatus[]>;
766
+ /**
767
+ * Get migration status for a specific tenant
768
+ *
769
+ * Delegates to MigrationExecutor for single tenant operations.
770
+ */
771
+ getTenantStatus(tenantId: string, migrations?: MigrationFile[]): Promise<TenantMigrationStatus>;
772
+ /**
773
+ * Create a new tenant schema and optionally apply migrations
774
+ */
775
+ createTenant(tenantId: string, options?: CreateTenantOptions): Promise<void>;
776
+ /**
777
+ * Drop a tenant schema
778
+ */
779
+ dropTenant(tenantId: string, options?: DropTenantOptions): Promise<void>;
780
+ /**
781
+ * Check if a tenant schema exists
782
+ */
783
+ tenantExists(tenantId: string): Promise<boolean>;
784
+ /**
785
+ * Clone a tenant to a new tenant
786
+ *
787
+ * By default, clones only schema structure. Use includeData to copy data.
788
+ *
789
+ * @example
790
+ * ```typescript
791
+ * // Schema-only clone
792
+ * await migrator.cloneTenant('production', 'dev');
793
+ *
794
+ * // Clone with data
795
+ * await migrator.cloneTenant('production', 'dev', { includeData: true });
796
+ *
797
+ * // Clone with anonymization
798
+ * await migrator.cloneTenant('production', 'dev', {
799
+ * includeData: true,
800
+ * anonymize: {
801
+ * enabled: true,
802
+ * rules: {
803
+ * users: { email: null, phone: null },
804
+ * },
805
+ * },
806
+ * });
807
+ * ```
808
+ */
809
+ cloneTenant(sourceTenantId: string, targetTenantId: string, options?: CloneTenantOptions): Promise<CloneTenantResult>;
810
+ /**
811
+ * Mark migrations as applied without executing SQL
812
+ * Useful for syncing tracking state with already-applied migrations
813
+ *
814
+ * Delegates to MigrationExecutor for single tenant operations.
815
+ */
816
+ markAsApplied(tenantId: string, options?: {
817
+ onProgress?: MigrateOptions['onProgress'];
818
+ }): Promise<TenantMigrationResult>;
819
+ /**
820
+ * Mark migrations as applied for all tenants without executing SQL
821
+ * Useful for syncing tracking state with already-applied migrations
822
+ *
823
+ * Delegates to BatchExecutor for parallel operations.
824
+ */
825
+ markAllAsApplied(options?: MigrateOptions): Promise<MigrationResults>;
826
+ /**
827
+ * Get sync status for all tenants
828
+ * Detects divergences between migrations on disk and tracking in database
829
+ */
830
+ getSyncStatus(): Promise<SyncStatus>;
831
+ /**
832
+ * Get sync status for a specific tenant
833
+ */
834
+ getTenantSyncStatus(tenantId: string, migrations?: MigrationFile[]): Promise<TenantSyncStatus>;
835
+ /**
836
+ * Mark missing migrations as applied for a tenant
837
+ */
838
+ markMissing(tenantId: string): Promise<TenantSyncResult>;
839
+ /**
840
+ * Mark missing migrations as applied for all tenants
841
+ */
842
+ markAllMissing(options?: SyncOptions): Promise<SyncResults>;
843
+ /**
844
+ * Remove orphan migration records for a tenant
845
+ */
846
+ cleanOrphans(tenantId: string): Promise<TenantSyncResult>;
847
+ /**
848
+ * Remove orphan migration records for all tenants
849
+ */
850
+ cleanAllOrphans(options?: SyncOptions): Promise<SyncResults>;
851
+ /**
852
+ * Seed a single tenant with initial data
853
+ *
854
+ * @example
855
+ * ```typescript
856
+ * const seed: SeedFunction = async (db, tenantId) => {
857
+ * await db.insert(roles).values([
858
+ * { name: 'admin', permissions: ['*'] },
859
+ * { name: 'user', permissions: ['read'] },
860
+ * ]);
861
+ * };
862
+ *
863
+ * await migrator.seedTenant('tenant-123', seed);
864
+ * ```
865
+ */
866
+ seedTenant(tenantId: string, seedFn: SeedFunction<TTenantSchema>): Promise<TenantSeedResult>;
867
+ /**
868
+ * Seed all tenants with initial data in parallel
869
+ *
870
+ * @example
871
+ * ```typescript
872
+ * const seed: SeedFunction = async (db, tenantId) => {
873
+ * await db.insert(roles).values([
874
+ * { name: 'admin', permissions: ['*'] },
875
+ * ]);
876
+ * };
877
+ *
878
+ * await migrator.seedAll(seed, { concurrency: 10 });
879
+ * ```
880
+ */
881
+ seedAll(seedFn: SeedFunction<TTenantSchema>, options?: SeedOptions): Promise<SeedResults>;
882
+ /**
883
+ * Seed specific tenants with initial data
884
+ */
885
+ seedTenants(tenantIds: string[], seedFn: SeedFunction<TTenantSchema>, options?: SeedOptions): Promise<SeedResults>;
886
+ /**
887
+ * Check if shared schema seeding is available
888
+ *
889
+ * @returns True if shared schema is configured
890
+ */
891
+ hasSharedSeeding(): boolean;
892
+ /**
893
+ * Seed the shared schema with initial data
894
+ *
895
+ * Seeds the public/shared schema with common data like plans, roles, permissions.
896
+ * Must have schemas.shared configured in the tenant config.
897
+ *
898
+ * @example
899
+ * ```typescript
900
+ * if (migrator.hasSharedSeeding()) {
901
+ * const result = await migrator.seedShared(async (db) => {
902
+ * await db.insert(plans).values([
903
+ * { id: 'free', name: 'Free', price: 0 },
904
+ * { id: 'pro', name: 'Pro', price: 29 },
905
+ * { id: 'enterprise', name: 'Enterprise', price: 99 },
906
+ * ]).onConflictDoNothing();
907
+ *
908
+ * await db.insert(roles).values([
909
+ * { name: 'admin', permissions: ['*'] },
910
+ * { name: 'user', permissions: ['read'] },
911
+ * ]).onConflictDoNothing();
912
+ * });
913
+ *
914
+ * if (result.success) {
915
+ * console.log(`Seeded shared schema in ${result.durationMs}ms`);
916
+ * }
917
+ * }
918
+ * ```
919
+ */
920
+ seedShared(seedFn: SharedSeedFunction<TSharedSchema>): Promise<SharedSeedResult>;
921
+ /**
922
+ * Seed shared schema first, then all tenants
923
+ *
924
+ * Convenience method for the common pattern of seeding shared tables
925
+ * before tenant tables.
926
+ *
927
+ * @example
928
+ * ```typescript
929
+ * const result = await migrator.seedAllWithShared(
930
+ * async (db) => {
931
+ * await db.insert(plans).values([{ id: 'free', name: 'Free' }]);
932
+ * },
933
+ * async (db, tenantId) => {
934
+ * await db.insert(roles).values([{ name: 'admin' }]);
935
+ * },
936
+ * { concurrency: 10 }
937
+ * );
938
+ *
939
+ * if (result.shared.success) {
940
+ * console.log('Shared seeding completed');
941
+ * }
942
+ * console.log(`Tenants: ${result.tenants.succeeded}/${result.tenants.total}`);
943
+ * ```
944
+ */
945
+ seedAllWithShared(sharedSeedFn: SharedSeedFunction<TSharedSchema>, tenantSeedFn: SeedFunction<TTenantSchema>, options?: SeedOptions): Promise<{
946
+ shared: SharedSeedResult;
947
+ tenants: SeedResults;
948
+ }>;
949
+ /**
950
+ * Load migration files from the migrations folder
951
+ */
952
+ private loadMigrations;
953
+ /**
954
+ * Get or detect the format for a schema
955
+ * Returns the configured format or auto-detects from existing table
956
+ *
957
+ * Note: This method is shared with SyncManager and MigrationExecutor via dependency injection.
958
+ */
959
+ private getOrDetectFormat;
960
+ /**
961
+ * Load shared migration files from the shared migrations folder
962
+ */
963
+ private loadSharedMigrations;
964
+ /**
965
+ * Get or detect the format for the shared schema
966
+ */
967
+ private getOrDetectSharedFormat;
968
+ /**
969
+ * Check if shared schema migrations are configured
970
+ *
971
+ * @returns True if sharedMigrationsFolder is configured and exists
972
+ */
973
+ hasSharedMigrations(): boolean;
974
+ /**
975
+ * Migrate the shared schema (public)
976
+ *
977
+ * Applies pending migrations to the shared/public schema.
978
+ * Must have sharedMigrationsFolder configured.
979
+ *
980
+ * @example
981
+ * ```typescript
982
+ * if (migrator.hasSharedMigrations()) {
983
+ * const result = await migrator.migrateShared();
984
+ * console.log(`Applied ${result.appliedMigrations.length} shared migrations`);
985
+ * }
986
+ * ```
987
+ */
988
+ migrateShared(options?: SharedMigrateOptions): Promise<SharedMigrationResult>;
989
+ /**
990
+ * Get migration status for the shared schema
991
+ *
992
+ * @returns Status with applied/pending counts
993
+ */
994
+ getSharedStatus(): Promise<SharedMigrationStatus>;
995
+ /**
996
+ * Mark shared schema migrations as applied without executing SQL
997
+ *
998
+ * Useful for syncing tracking state with already-applied migrations.
999
+ */
1000
+ markSharedAsApplied(options?: {
1001
+ onProgress?: SharedMigrateOptions['onProgress'];
1002
+ }): Promise<SharedMigrationResult>;
1003
+ /**
1004
+ * Migrate shared schema first, then all tenants
1005
+ *
1006
+ * Convenience method for the common pattern of migrating shared tables
1007
+ * before tenant tables.
1008
+ *
1009
+ * @example
1010
+ * ```typescript
1011
+ * const result = await migrator.migrateAllWithShared({
1012
+ * concurrency: 10,
1013
+ * onProgress: (tenantId, status) => console.log(`${tenantId}: ${status}`),
1014
+ * });
1015
+ *
1016
+ * console.log(`Shared: ${result.shared.appliedMigrations.length} applied`);
1017
+ * console.log(`Tenants: ${result.tenants.succeeded}/${result.tenants.total} succeeded`);
1018
+ * ```
1019
+ */
1020
+ migrateAllWithShared(options?: MigrateOptions & {
1021
+ sharedOptions?: SharedMigrateOptions;
1022
+ }): Promise<{
1023
+ shared: SharedMigrationResult;
1024
+ tenants: MigrationResults;
1025
+ }>;
1026
+ /**
1027
+ * Detect schema drift across all tenants
1028
+ * Compares each tenant's schema against a reference tenant (first tenant by default)
1029
+ *
1030
+ * @example
1031
+ * ```typescript
1032
+ * const drift = await migrator.getSchemaDrift();
1033
+ * if (drift.withDrift > 0) {
1034
+ * console.log('Schema drift detected!');
1035
+ * for (const tenant of drift.details) {
1036
+ * if (tenant.hasDrift) {
1037
+ * console.log(`Tenant ${tenant.tenantId} has drift:`);
1038
+ * for (const table of tenant.tables) {
1039
+ * for (const col of table.columns) {
1040
+ * console.log(` - ${table.table}.${col.column}: ${col.description}`);
1041
+ * }
1042
+ * }
1043
+ * }
1044
+ * }
1045
+ * }
1046
+ * ```
1047
+ */
1048
+ getSchemaDrift(options?: SchemaDriftOptions): Promise<SchemaDriftStatus>;
1049
+ /**
1050
+ * Get schema drift for a specific tenant compared to a reference
1051
+ */
1052
+ getTenantSchemaDrift(tenantId: string, referenceTenantId: string, options?: Pick<SchemaDriftOptions, 'includeIndexes' | 'includeConstraints' | 'excludeTables'>): Promise<TenantSchemaDrift>;
1053
+ /**
1054
+ * Introspect the schema of a tenant
1055
+ */
1056
+ introspectTenantSchema(tenantId: string, options?: {
1057
+ includeIndexes?: boolean;
1058
+ includeConstraints?: boolean;
1059
+ excludeTables?: string[];
1060
+ }): Promise<TenantSchema | null>;
1061
+ }
1062
+ /**
1063
+ * Create a migrator instance
1064
+ */
1065
+ declare function createMigrator<TTenantSchema extends Record<string, unknown>, TSharedSchema extends Record<string, unknown>>(tenantConfig: Config<TTenantSchema, TSharedSchema>, migratorConfig: MigratorConfig): Migrator<TTenantSchema, TSharedSchema>;
1066
+
1067
+ export { type AnonymizeRules as $, type AppliedMigration as A, type SharedMigrationStatus as B, type CreateTenantOptions as C, type DropTenantOptions as D, detectTableFormat as E, getFormatConfig as F, DEFAULT_FORMAT as G, DRIZZLE_KIT_FORMAT as H, type TableFormat as I, type ColumnInfo as J, type IndexInfo as K, type ConstraintInfo as L, Migrator as M, type TableSchema as N, type TenantSchema as O, type ColumnDrift as P, type IndexDrift as Q, type ConstraintDrift as R, type SeedFunction as S, type TenantMigrationResult as T, type TableDrift as U, type TenantSchemaDrift as V, type SchemaDriftStatus as W, type SchemaDriftOptions as X, type CloneProgressCallback as Y, type CloneProgressStatus as Z, type AnonymizeOptions as _, type MigratorConfig as a, type AnonymizeValue as a0, type SharedMigratorConfig as a1, type SharedMigrationHooks as a2, type MigrationFile as b, createMigrator as c, type MigrateOptions as d, type MigrationResults as e, type TenantMigrationStatus as f, type MigrationHooks as g, type MigrationProgressCallback as h, type MigrationErrorHandler as i, type SeedOptions as j, type TenantSeedResult as k, type SeedResults as l, type SharedSeedFunction as m, type SharedSeedResult as n, type DetectedFormat as o, type SyncStatus as p, type TenantSyncStatus as q, type TenantSyncResult as r, type SyncOptions as s, type SyncResults as t, type ClonerConfig as u, type ClonerDependencies as v, type CloneTenantOptions as w, type CloneTenantResult as x, type SharedMigrateOptions as y, type SharedMigrationResult as z };