@noormdev/sdk 1.0.0-alpha.12 → 1.0.0-alpha.14

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/dist/index.d.ts CHANGED
@@ -71,10 +71,6 @@ export interface ConnectionResult {
71
71
  * user: 'postgres',
72
72
  * password: 'postgres',
73
73
  * },
74
- * paths: {
75
- * sql: './sql',
76
- * changes: './changes',
77
- * },
78
74
  * }
79
75
  * ```
80
76
  */
@@ -84,10 +80,6 @@ export interface Config {
84
80
  isTest: boolean;
85
81
  protected: boolean;
86
82
  connection: ConnectionConfig;
87
- paths: {
88
- sql: string;
89
- changes: string;
90
- };
91
83
  identity?: string;
92
84
  }
93
85
  /**
@@ -623,214 +615,6 @@ export interface Identity {
623
615
  /** How the identity was resolved */
624
616
  source: IdentitySource;
625
617
  }
626
- /**
627
- * Overview counts for all categories.
628
- */
629
- export interface ExploreOverview {
630
- tables: number;
631
- views: number;
632
- procedures: number;
633
- functions: number;
634
- types: number;
635
- indexes: number;
636
- foreignKeys: number;
637
- triggers: number;
638
- locks: number;
639
- connections: number;
640
- }
641
- /**
642
- * Table summary for list display.
643
- */
644
- export interface TableSummary {
645
- name: string;
646
- schema?: string;
647
- columnCount: number;
648
- rowCountEstimate?: number;
649
- }
650
- /**
651
- * Index summary for list display.
652
- */
653
- export interface IndexSummary {
654
- name: string;
655
- schema?: string;
656
- tableName: string;
657
- tableSchema?: string;
658
- columns: string[];
659
- isUnique: boolean;
660
- isPrimary: boolean;
661
- }
662
- /**
663
- * Foreign key summary for list display.
664
- */
665
- export interface ForeignKeySummary {
666
- name: string;
667
- schema?: string;
668
- tableName: string;
669
- tableSchema?: string;
670
- columns: string[];
671
- referencedTable: string;
672
- referencedSchema?: string;
673
- referencedColumns: string[];
674
- onDelete?: string;
675
- onUpdate?: string;
676
- }
677
- /**
678
- * Column detail for tables/views.
679
- */
680
- export interface ColumnDetail {
681
- name: string;
682
- dataType: string;
683
- isNullable: boolean;
684
- defaultValue?: string;
685
- isPrimaryKey: boolean;
686
- ordinalPosition: number;
687
- }
688
- /**
689
- * Full table detail.
690
- */
691
- export interface TableDetail {
692
- name: string;
693
- schema?: string;
694
- columns: ColumnDetail[];
695
- indexes: IndexSummary[];
696
- foreignKeys: ForeignKeySummary[];
697
- rowCountEstimate?: number;
698
- }
699
- /**
700
- * Result of a truncate operation.
701
- */
702
- export interface TruncateResult {
703
- /** Tables that were truncated */
704
- truncated: string[];
705
- /** Tables that were preserved */
706
- preserved: string[];
707
- /** SQL statements executed (or would execute in dry-run) */
708
- statements: string[];
709
- /** Duration in milliseconds */
710
- durationMs: number;
711
- }
712
- /**
713
- * Result of a teardown operation.
714
- */
715
- export interface TeardownResult {
716
- /** Objects dropped by category */
717
- dropped: {
718
- tables: string[];
719
- views: string[];
720
- functions: string[];
721
- procedures: string[];
722
- types: string[];
723
- foreignKeys: string[];
724
- };
725
- /** Objects preserved */
726
- preserved: string[];
727
- /** SQL statements executed (or would execute in dry-run) */
728
- statements: string[];
729
- /** Duration in milliseconds */
730
- durationMs: number;
731
- /** Post-script execution result (if any) */
732
- postScriptResult?: {
733
- executed: boolean;
734
- error?: string;
735
- };
736
- /** Number of changes marked as stale (if configName provided) */
737
- staleCount?: number;
738
- /** ID of the reset record created (if configName provided) */
739
- resetRecordId?: number;
740
- }
741
- /**
742
- * Options for running SQL files.
743
- *
744
- * @example
745
- * ```typescript
746
- * const options: RunOptions = {
747
- * force: true, // Re-run even if unchanged
748
- * abortOnError: false // Continue on failures
749
- * }
750
- * ```
751
- */
752
- export interface RunOptions {
753
- /** Re-run files even if unchanged. Default: false */
754
- force?: boolean;
755
- /** Number of files to run in parallel. Default: 1 (sequential for DDL safety) */
756
- concurrency?: number;
757
- /** Stop execution on first failure. Default: true */
758
- abortOnError?: boolean;
759
- /** Report what would run without executing. Default: false */
760
- dryRun?: boolean;
761
- /** Output rendered SQL without executing. Default: false */
762
- preview?: boolean;
763
- /** Write preview output to file instead of stdout. Default: null */
764
- output?: string | null;
765
- }
766
- /**
767
- * Why a file was skipped.
768
- */
769
- export type SkipReason = "unchanged" | "already-run";
770
- /**
771
- * Result of executing a single file.
772
- *
773
- * @example
774
- * ```typescript
775
- * const result: FileResult = {
776
- * filepath: '/project/sql/001.sql',
777
- * checksum: 'abc123...',
778
- * status: 'success',
779
- * durationMs: 42,
780
- * }
781
- * ```
782
- */
783
- export interface FileResult {
784
- /** Absolute path to the file */
785
- filepath: string;
786
- /** SHA-256 hash of file contents */
787
- checksum: string;
788
- /** Execution status */
789
- status: ExecutionStatus;
790
- /** Why the file was skipped (only when status is 'skipped') */
791
- skipReason?: SkipReason;
792
- /** Execution time in milliseconds */
793
- durationMs?: number;
794
- /** Error message if failed */
795
- error?: string;
796
- /** Rendered SQL (only in preview mode) */
797
- renderedSql?: string;
798
- }
799
- /**
800
- * Overall status of a batch operation.
801
- */
802
- export type BatchStatus = "success" | "failed" | "partial";
803
- /**
804
- * Result of a batch operation (build, dir).
805
- *
806
- * @example
807
- * ```typescript
808
- * const result: BatchResult = {
809
- * status: 'success',
810
- * files: [...],
811
- * filesRun: 5,
812
- * filesSkipped: 2,
813
- * filesFailed: 0,
814
- * durationMs: 1234,
815
- * }
816
- * ```
817
- */
818
- export interface BatchResult {
819
- /** Overall status */
820
- status: BatchStatus;
821
- /** Results for each file */
822
- files: FileResult[];
823
- /** Number of files executed */
824
- filesRun: number;
825
- /** Number of files skipped */
826
- filesSkipped: number;
827
- /** Number of files that failed */
828
- filesFailed: number;
829
- /** Total execution time in milliseconds */
830
- durationMs: number;
831
- /** Change ID in tracking table */
832
- changeId?: number;
833
- }
834
618
  /**
835
619
  * File extension type in changes.
836
620
  *
@@ -1130,95 +914,778 @@ export interface FileHistoryRecord {
1130
914
  /** Duration in milliseconds */
1131
915
  durationMs: number;
1132
916
  }
1133
- declare class ChangeManager {
1134
- #private;
1135
- constructor(context: ChangeContext);
1136
- /**
1137
- * List all changes with status.
1138
- *
1139
- * Merges changes from disk with status from database.
1140
- * Includes orphaned changes (in DB but not on disk).
1141
- *
1142
- * @returns Array of changes with merged status
1143
- */
1144
- list(): Promise<ChangeListItem[]>;
1145
- /**
1146
- * Run a specific change by name.
1147
- *
1148
- * @param name - Change name
1149
- * @param options - Execution options
1150
- * @returns Execution result
1151
- */
1152
- run(name: string, options?: ChangeOptions): Promise<ChangeResult>;
1153
- /**
1154
- * Run a change object directly.
1155
- */
1156
- runChange(change: Change, options?: ChangeOptions): Promise<ChangeResult>;
1157
- /**
1158
- * Revert a specific change by name.
1159
- *
1160
- * @param name - Change name
1161
- * @param options - Execution options
1162
- * @returns Execution result
1163
- */
1164
- revert(name: string, options?: ChangeOptions): Promise<ChangeResult>;
1165
- /**
1166
- * Revert a change object directly.
1167
- */
1168
- revertChange(change: Change, options?: ChangeOptions): Promise<ChangeResult>;
1169
- /**
1170
- * Run next N pending changes.
1171
- *
1172
- * @param count - Number of changes to run (default: 1)
1173
- * @param options - Execution options
1174
- * @returns Batch result
1175
- */
1176
- next(count?: number, options?: BatchChangeOptions): Promise<BatchChangeResult>;
1177
- /**
1178
- * Fast-forward: run all pending changes.
917
+ /**
918
+ * Options for creating a new change.
919
+ */
920
+ export interface CreateChangeOptions {
921
+ /** Description for the change name */
922
+ description: string;
923
+ /** Optional date (defaults to today) */
924
+ date?: Date;
925
+ }
926
+ /**
927
+ * Options for adding a file to a change.
928
+ */
929
+ export interface AddFileOptions {
930
+ /** Descriptive name for the file */
931
+ name: string;
932
+ /** File type */
933
+ type: ChangeFileType;
934
+ /** For 'txt' type, the paths to include */
935
+ paths?: string[];
936
+ /** Initial content (optional) */
937
+ content?: string;
938
+ }
939
+ /**
940
+ * Error when change structure is invalid.
941
+ */
942
+ export declare class ChangeValidationError extends Error {
943
+ readonly changeName: string;
944
+ readonly issue: string;
945
+ readonly name: "ChangeValidationError";
946
+ constructor(changeName: string, issue: string);
947
+ }
948
+ /**
949
+ * Error when change is not found.
950
+ */
951
+ export declare class ChangeNotFoundError extends Error {
952
+ readonly changeName: string;
953
+ readonly name: "ChangeNotFoundError";
954
+ constructor(changeName: string);
955
+ }
956
+ /**
957
+ * Error when change is already applied.
958
+ */
959
+ export declare class ChangeAlreadyAppliedError extends Error {
960
+ readonly changeName: string;
961
+ readonly appliedAt: Date;
962
+ readonly name: "ChangeAlreadyAppliedError";
963
+ constructor(changeName: string, appliedAt: Date);
964
+ }
965
+ /**
966
+ * Error when trying to revert an unapplied change.
967
+ */
968
+ export declare class ChangeNotAppliedError extends Error {
969
+ readonly changeName: string;
970
+ readonly name: "ChangeNotAppliedError";
971
+ constructor(changeName: string);
972
+ }
973
+ /**
974
+ * Error when change is orphaned (in DB but not on disk).
975
+ */
976
+ export declare class ChangeOrphanedError extends Error {
977
+ readonly changeName: string;
978
+ readonly name: "ChangeOrphanedError";
979
+ constructor(changeName: string);
980
+ }
981
+ /**
982
+ * Error when .txt manifest has invalid references.
983
+ */
984
+ export declare class ManifestReferenceError extends Error {
985
+ readonly manifestPath: string;
986
+ readonly missingPath: string;
987
+ readonly name: "ManifestReferenceError";
988
+ constructor(manifestPath: string, missingPath: string);
989
+ }
990
+ /**
991
+ * Options for running SQL files.
992
+ *
993
+ * @example
994
+ * ```typescript
995
+ * const options: RunOptions = {
996
+ * force: true, // Re-run even if unchanged
997
+ * abortOnError: false // Continue on failures
998
+ * }
999
+ * ```
1000
+ */
1001
+ export interface RunOptions {
1002
+ /** Re-run files even if unchanged. Default: false */
1003
+ force?: boolean;
1004
+ /** Number of files to run in parallel. Default: 1 (sequential for DDL safety) */
1005
+ concurrency?: number;
1006
+ /** Stop execution on first failure. Default: true */
1007
+ abortOnError?: boolean;
1008
+ /** Report what would run without executing. Default: false */
1009
+ dryRun?: boolean;
1010
+ /** Output rendered SQL without executing. Default: false */
1011
+ preview?: boolean;
1012
+ /** Write preview output to file instead of stdout. Default: null */
1013
+ output?: string | null;
1014
+ }
1015
+ /**
1016
+ * Why a file was skipped.
1017
+ */
1018
+ export type SkipReason = "unchanged" | "already-run";
1019
+ /**
1020
+ * Result of executing a single file.
1021
+ *
1022
+ * @example
1023
+ * ```typescript
1024
+ * const result: FileResult = {
1025
+ * filepath: '/project/sql/001.sql',
1026
+ * checksum: 'abc123...',
1027
+ * status: 'success',
1028
+ * durationMs: 42,
1029
+ * }
1030
+ * ```
1031
+ */
1032
+ export interface FileResult {
1033
+ /** Absolute path to the file */
1034
+ filepath: string;
1035
+ /** SHA-256 hash of file contents */
1036
+ checksum: string;
1037
+ /** Execution status */
1038
+ status: ExecutionStatus;
1039
+ /** Why the file was skipped (only when status is 'skipped') */
1040
+ skipReason?: SkipReason;
1041
+ /** Execution time in milliseconds */
1042
+ durationMs?: number;
1043
+ /** Error message if failed */
1044
+ error?: string;
1045
+ /** Rendered SQL (only in preview mode) */
1046
+ renderedSql?: string;
1047
+ }
1048
+ /**
1049
+ * Overall status of a batch operation.
1050
+ */
1051
+ export type BatchStatus = "success" | "failed" | "partial";
1052
+ /**
1053
+ * Result of a batch operation (build, dir).
1054
+ *
1055
+ * @example
1056
+ * ```typescript
1057
+ * const result: BatchResult = {
1058
+ * status: 'success',
1059
+ * files: [...],
1060
+ * filesRun: 5,
1061
+ * filesSkipped: 2,
1062
+ * filesFailed: 0,
1063
+ * durationMs: 1234,
1064
+ * }
1065
+ * ```
1066
+ */
1067
+ export interface BatchResult {
1068
+ /** Overall status */
1069
+ status: BatchStatus;
1070
+ /** Results for each file */
1071
+ files: FileResult[];
1072
+ /** Number of files executed */
1073
+ filesRun: number;
1074
+ /** Number of files skipped */
1075
+ filesSkipped: number;
1076
+ /** Number of files that failed */
1077
+ filesFailed: number;
1078
+ /** Total execution time in milliseconds */
1079
+ durationMs: number;
1080
+ /** Change ID in tracking table */
1081
+ changeId?: number;
1082
+ }
1083
+ declare class ChangeManager {
1084
+ #private;
1085
+ constructor(context: ChangeContext);
1086
+ /**
1087
+ * List all changes with status.
1088
+ *
1089
+ * Merges changes from disk with status from database.
1090
+ * Includes orphaned changes (in DB but not on disk).
1091
+ *
1092
+ * @returns Array of changes with merged status
1093
+ */
1094
+ list(): Promise<ChangeListItem[]>;
1095
+ /**
1096
+ * Run a specific change by name.
1097
+ *
1098
+ * @param name - Change name
1099
+ * @param options - Execution options
1100
+ * @returns Execution result
1101
+ */
1102
+ run(name: string, options?: ChangeOptions): Promise<ChangeResult>;
1103
+ /**
1104
+ * Run a change object directly.
1105
+ */
1106
+ runChange(change: Change, options?: ChangeOptions): Promise<ChangeResult>;
1107
+ /**
1108
+ * Revert a specific change by name.
1109
+ *
1110
+ * @param name - Change name
1111
+ * @param options - Execution options
1112
+ * @returns Execution result
1113
+ */
1114
+ revert(name: string, options?: ChangeOptions): Promise<ChangeResult>;
1115
+ /**
1116
+ * Revert a change object directly.
1117
+ */
1118
+ revertChange(change: Change, options?: ChangeOptions): Promise<ChangeResult>;
1119
+ /**
1120
+ * Run next N pending changes.
1121
+ *
1122
+ * @param count - Number of changes to run (default: 1)
1123
+ * @param options - Execution options
1124
+ * @returns Batch result
1125
+ */
1126
+ next(count?: number, options?: BatchChangeOptions): Promise<BatchChangeResult>;
1127
+ /**
1128
+ * Fast-forward: run all pending changes.
1129
+ *
1130
+ * @param options - Execution options
1131
+ * @returns Batch result
1132
+ */
1133
+ ff(options?: BatchChangeOptions): Promise<BatchChangeResult>;
1134
+ /**
1135
+ * Rewind: revert changes in reverse order.
1136
+ *
1137
+ * @param target - Number of changes to revert, or name to revert to
1138
+ * @param options - Execution options
1139
+ * @returns Batch result
1140
+ */
1141
+ rewind(target: number | string, options?: BatchChangeOptions): Promise<BatchChangeResult>;
1142
+ /**
1143
+ * Get execution history.
1144
+ *
1145
+ * @param name - Optional change name (all if not provided)
1146
+ * @param limit - Max records to return
1147
+ * @returns Array of history records
1148
+ */
1149
+ getHistory(name?: string, limit?: number): Promise<ChangeHistoryRecord[]>;
1150
+ /**
1151
+ * Get file execution history for an operation.
1152
+ */
1153
+ getFileHistory(operationId: number): Promise<FileHistoryRecord[]>;
1154
+ /**
1155
+ * Remove a change from disk, database, or both.
1156
+ *
1157
+ * @param name - Change name
1158
+ * @param options - What to remove
1159
+ */
1160
+ remove(name: string, options: {
1161
+ disk?: boolean;
1162
+ db?: boolean;
1163
+ }): Promise<void>;
1164
+ /**
1165
+ * Get a specific change by name.
1166
+ */
1167
+ get(name: string): Promise<ChangeListItem | null>;
1168
+ /**
1169
+ * Load a change from disk.
1170
+ */
1171
+ load(name: string): Promise<Change>;
1172
+ }
1173
+ /**
1174
+ * SDK Types.
1175
+ *
1176
+ * All interfaces and types for the noorm programmatic SDK.
1177
+ */
1178
+ /**
1179
+ * Options for creating an SDK context.
1180
+ *
1181
+ * @example
1182
+ * ```typescript
1183
+ * // Basic usage with stored config
1184
+ * const ctx = await createContext({ config: 'dev' })
1185
+ *
1186
+ * // Require test database for safety
1187
+ * const ctx = await createContext({
1188
+ * config: 'test',
1189
+ * requireTest: true,
1190
+ * })
1191
+ *
1192
+ * // Allow destructive ops on protected config
1193
+ * const ctx = await createContext({
1194
+ * config: 'staging',
1195
+ * allowProtected: true,
1196
+ * })
1197
+ *
1198
+ * // Env-only mode (CI/CD) - no stored config needed
1199
+ * // Requires NOORM_CONNECTION_DIALECT and NOORM_CONNECTION_DATABASE
1200
+ * const ctx = await createContext()
1201
+ *
1202
+ * // Override stored config via NOORM_* env vars
1203
+ * // NOORM_CONNECTION_HOST=override.host
1204
+ * const ctx = await createContext({ config: 'prod' })
1205
+ * ```
1206
+ */
1207
+ export interface CreateContextOptions {
1208
+ /**
1209
+ * Config name from state.
1210
+ *
1211
+ * If omitted:
1212
+ * - Uses `NOORM_CONFIG` env var if set
1213
+ * - Falls back to env-only mode if `NOORM_CONNECTION_DIALECT`
1214
+ * and `NOORM_CONNECTION_DATABASE` are set
1215
+ */
1216
+ config?: string;
1217
+ /** Project root directory. Defaults to process.cwd() */
1218
+ projectRoot?: string;
1219
+ /** Refuse if config.isTest !== true. Default: false */
1220
+ requireTest?: boolean;
1221
+ /** Allow destructive ops on protected configs. Default: false */
1222
+ allowProtected?: boolean;
1223
+ /** Stage name for stage defaults (from settings.yml) */
1224
+ stage?: string;
1225
+ }
1226
+ /**
1227
+ * Options for build operations.
1228
+ */
1229
+ export interface BuildOptions {
1230
+ /** Skip checksum checks, rebuild everything. Default: false */
1231
+ force?: boolean;
1232
+ }
1233
+ /**
1234
+ * Options for exporting a table to a .dt file.
1235
+ *
1236
+ * Connection details (db, dialect) come from the context automatically.
1237
+ *
1238
+ * @example
1239
+ * ```typescript
1240
+ * const [result, err] = await ctx.exportTable('users', './exports/users.dtz', {
1241
+ * passphrase: 'secret',
1242
+ * batchSize: 5000,
1243
+ * });
1244
+ * ```
1245
+ */
1246
+ export interface ExportOptions {
1247
+ /** Passphrase for .dtzx encryption. */
1248
+ passphrase?: string;
1249
+ /** Schema/namespace (e.g., 'public' for PostgreSQL). */
1250
+ schema?: string;
1251
+ /** Rows per batch. Default: 1000. */
1252
+ batchSize?: number;
1253
+ }
1254
+ /**
1255
+ * Options for importing a .dt file into the database.
1256
+ *
1257
+ * Connection details (db, dialect) come from the context automatically.
1258
+ *
1259
+ * @example
1260
+ * ```typescript
1261
+ * const [result, err] = await ctx.importFile('./exports/users.dtz', {
1262
+ * onConflict: 'skip',
1263
+ * truncate: true,
1264
+ * });
1265
+ * ```
1266
+ */
1267
+ export interface ImportOptions {
1268
+ /** Passphrase for .dtzx decryption. */
1269
+ passphrase?: string;
1270
+ /** Rows per batch. Default: 1000. */
1271
+ batchSize?: number;
1272
+ /** Conflict strategy. Default: 'fail'. */
1273
+ onConflict?: "fail" | "skip" | "update" | "replace";
1274
+ /** Truncate target table before import. Default: false. */
1275
+ truncate?: boolean;
1276
+ }
1277
+ export interface ContextState {
1278
+ connection: ConnectionResult | null;
1279
+ config: Config;
1280
+ settings: Settings;
1281
+ identity: Identity;
1282
+ options: CreateContextOptions;
1283
+ projectRoot: string;
1284
+ changeManager: ChangeManager | null;
1285
+ }
1286
+ export declare class ChangesNamespace {
1287
+ #private;
1288
+ constructor(state: ContextState);
1289
+ /**
1290
+ * Create a new change directory with change/ and revert/ folders.
1291
+ *
1292
+ * @example
1293
+ * ```typescript
1294
+ * const change = await ctx.noorm.changes.create({ description: 'add-user-roles' })
1295
+ * ```
1296
+ */
1297
+ create(options: CreateChangeOptions): Promise<Change>;
1298
+ /**
1299
+ * Add a file to a change.
1300
+ *
1301
+ * @example
1302
+ * ```typescript
1303
+ * const updated = await ctx.noorm.changes.addFile(change, 'change', {
1304
+ * name: 'create-table',
1305
+ * type: 'sql',
1306
+ * })
1307
+ * ```
1308
+ */
1309
+ addFile(change: Change, folder: "change" | "revert", options: AddFileOptions): Promise<Change>;
1310
+ /**
1311
+ * Remove a file from a change.
1312
+ *
1313
+ * @example
1314
+ * ```typescript
1315
+ * await ctx.noorm.changes.removeFile(change, 'change', '001_create-table.sql')
1316
+ * ```
1317
+ */
1318
+ removeFile(change: Change, folder: "change" | "revert", filename: string): Promise<Change>;
1319
+ /**
1320
+ * Rename a file in a change.
1321
+ *
1322
+ * @example
1323
+ * ```typescript
1324
+ * await ctx.noorm.changes.renameFile(change, 'change', '001_old.sql', 'new-name')
1325
+ * ```
1326
+ */
1327
+ renameFile(change: Change, folder: "change" | "revert", oldFilename: string, newDescription: string): Promise<Change>;
1328
+ /**
1329
+ * Reorder files in a change folder.
1330
+ *
1331
+ * @example
1332
+ * ```typescript
1333
+ * await ctx.noorm.changes.reorderFiles(change, 'change', ['002_b.sql', '001_a.sql'])
1334
+ * ```
1335
+ */
1336
+ reorderFiles(change: Change, folder: "change" | "revert", newOrder: string[]): Promise<Change>;
1337
+ /**
1338
+ * Delete a change directory from disk.
1339
+ *
1340
+ * @example
1341
+ * ```typescript
1342
+ * await ctx.noorm.changes.delete(change)
1343
+ * ```
1344
+ */
1345
+ delete(change: Change): Promise<void>;
1346
+ /**
1347
+ * Discover all changes on disk.
1348
+ *
1349
+ * @example
1350
+ * ```typescript
1351
+ * const changes = await ctx.noorm.changes.discover()
1352
+ * ```
1353
+ */
1354
+ discover(): Promise<Change[]>;
1355
+ /**
1356
+ * Parse a single change from disk by name.
1357
+ *
1358
+ * @example
1359
+ * ```typescript
1360
+ * const change = await ctx.noorm.changes.parse('2024-01-15-add-users')
1361
+ * ```
1362
+ */
1363
+ parse(name: string): Promise<Change>;
1364
+ /**
1365
+ * Validate a change's structure.
1366
+ *
1367
+ * @throws ChangeValidationError if invalid
1368
+ *
1369
+ * @example
1370
+ * ```typescript
1371
+ * ctx.noorm.changes.validate(change)
1372
+ * ```
1373
+ */
1374
+ validate(change: Change): void;
1375
+ /**
1376
+ * Apply a specific change.
1377
+ *
1378
+ * @example
1379
+ * ```typescript
1380
+ * const result = await ctx.noorm.changes.apply('2024-01-15-add-users')
1381
+ * ```
1382
+ */
1383
+ apply(name: string, options?: ChangeOptions): Promise<ChangeResult>;
1384
+ /**
1385
+ * Revert a specific change.
1386
+ *
1387
+ * @example
1388
+ * ```typescript
1389
+ * const result = await ctx.noorm.changes.revert('2024-01-15-add-users')
1390
+ * ```
1391
+ */
1392
+ revert(name: string, options?: ChangeOptions): Promise<ChangeResult>;
1393
+ /**
1394
+ * Apply all pending changes.
1395
+ *
1396
+ * @example
1397
+ * ```typescript
1398
+ * const result = await ctx.noorm.changes.ff()
1399
+ * ```
1400
+ */
1401
+ ff(): Promise<BatchChangeResult>;
1402
+ /**
1403
+ * Get status of all changes (merged disk + DB).
1404
+ *
1405
+ * @example
1406
+ * ```typescript
1407
+ * const all = await ctx.noorm.changes.status()
1408
+ * ```
1409
+ */
1410
+ status(): Promise<ChangeListItem[]>;
1411
+ /**
1412
+ * Get only pending (unapplied or reverted) changes.
1413
+ *
1414
+ * @example
1415
+ * ```typescript
1416
+ * const pending = await ctx.noorm.changes.pending()
1417
+ * ```
1418
+ */
1419
+ pending(): Promise<ChangeListItem[]>;
1420
+ /**
1421
+ * Get execution history.
1422
+ *
1423
+ * @example
1424
+ * ```typescript
1425
+ * const history = await ctx.noorm.changes.history(10)
1426
+ * ```
1427
+ */
1428
+ history(limit?: number): Promise<ChangeHistoryRecord[]>;
1429
+ }
1430
+ export declare class RunNamespace {
1431
+ #private;
1432
+ constructor(state: ContextState);
1433
+ /**
1434
+ * Discover SQL files in a directory.
1435
+ *
1436
+ * @example
1437
+ * ```typescript
1438
+ * const files = await ctx.noorm.run.discover('sql/')
1439
+ * ```
1440
+ */
1441
+ discover(dirpath?: string): Promise<string[]>;
1442
+ /**
1443
+ * Preview SQL files — render templates without executing.
1444
+ *
1445
+ * @example
1446
+ * ```typescript
1447
+ * const results = await ctx.noorm.run.preview(['sql/001.sql', 'sql/002.sql'])
1448
+ * ```
1449
+ */
1450
+ preview(filepaths: string[], output?: string | null): Promise<FileResult[]>;
1451
+ /**
1452
+ * Execute a single SQL file.
1453
+ *
1454
+ * @example
1455
+ * ```typescript
1456
+ * await ctx.noorm.run.file('seeds/test-data.sql')
1457
+ * ```
1458
+ */
1459
+ file(filepath: string, options?: RunOptions): Promise<FileResult>;
1460
+ /**
1461
+ * Execute multiple SQL files sequentially.
1462
+ *
1463
+ * @example
1464
+ * ```typescript
1465
+ * await ctx.noorm.run.files(['functions/utils.sql', 'triggers/audit.sql'])
1466
+ * ```
1467
+ */
1468
+ files(filepaths: string[], options?: RunOptions): Promise<BatchResult>;
1469
+ /**
1470
+ * Execute all SQL files in a directory.
1471
+ *
1472
+ * @example
1473
+ * ```typescript
1474
+ * await ctx.noorm.run.dir('seeds/')
1475
+ * ```
1476
+ */
1477
+ dir(dirpath: string, options?: RunOptions): Promise<BatchResult>;
1478
+ /**
1479
+ * Execute all SQL files in the schema directory.
1480
+ *
1481
+ * @example
1482
+ * ```typescript
1483
+ * await ctx.noorm.run.build({ force: true })
1484
+ * ```
1485
+ */
1486
+ build(options?: BuildOptions): Promise<BatchResult>;
1487
+ }
1488
+ /**
1489
+ * Overview counts for all categories.
1490
+ */
1491
+ export interface ExploreOverview {
1492
+ tables: number;
1493
+ views: number;
1494
+ procedures: number;
1495
+ functions: number;
1496
+ types: number;
1497
+ indexes: number;
1498
+ foreignKeys: number;
1499
+ triggers: number;
1500
+ locks: number;
1501
+ connections: number;
1502
+ }
1503
+ /**
1504
+ * Table summary for list display.
1505
+ */
1506
+ export interface TableSummary {
1507
+ name: string;
1508
+ schema?: string;
1509
+ columnCount: number;
1510
+ rowCountEstimate?: number;
1511
+ }
1512
+ /**
1513
+ * Index summary for list display.
1514
+ */
1515
+ export interface IndexSummary {
1516
+ name: string;
1517
+ schema?: string;
1518
+ tableName: string;
1519
+ tableSchema?: string;
1520
+ columns: string[];
1521
+ isUnique: boolean;
1522
+ isPrimary: boolean;
1523
+ }
1524
+ /**
1525
+ * Foreign key summary for list display.
1526
+ */
1527
+ export interface ForeignKeySummary {
1528
+ name: string;
1529
+ schema?: string;
1530
+ tableName: string;
1531
+ tableSchema?: string;
1532
+ columns: string[];
1533
+ referencedTable: string;
1534
+ referencedSchema?: string;
1535
+ referencedColumns: string[];
1536
+ onDelete?: string;
1537
+ onUpdate?: string;
1538
+ }
1539
+ /**
1540
+ * Column detail for tables/views.
1541
+ */
1542
+ export interface ColumnDetail {
1543
+ name: string;
1544
+ dataType: string;
1545
+ isNullable: boolean;
1546
+ defaultValue?: string;
1547
+ isPrimaryKey: boolean;
1548
+ ordinalPosition: number;
1549
+ }
1550
+ /**
1551
+ * Full table detail.
1552
+ */
1553
+ export interface TableDetail {
1554
+ name: string;
1555
+ schema?: string;
1556
+ columns: ColumnDetail[];
1557
+ indexes: IndexSummary[];
1558
+ foreignKeys: ForeignKeySummary[];
1559
+ rowCountEstimate?: number;
1560
+ }
1561
+ /**
1562
+ * Result of a truncate operation.
1563
+ */
1564
+ export interface TruncateResult {
1565
+ /** Tables that were truncated */
1566
+ truncated: string[];
1567
+ /** Tables that were preserved */
1568
+ preserved: string[];
1569
+ /** SQL statements executed (or would execute in dry-run) */
1570
+ statements: string[];
1571
+ /** Duration in milliseconds */
1572
+ durationMs: number;
1573
+ }
1574
+ /**
1575
+ * Result of a teardown operation.
1576
+ */
1577
+ export interface TeardownResult {
1578
+ /** Objects dropped by category */
1579
+ dropped: {
1580
+ tables: string[];
1581
+ views: string[];
1582
+ functions: string[];
1583
+ procedures: string[];
1584
+ types: string[];
1585
+ foreignKeys: string[];
1586
+ };
1587
+ /** Objects preserved */
1588
+ preserved: string[];
1589
+ /** SQL statements executed (or would execute in dry-run) */
1590
+ statements: string[];
1591
+ /** Duration in milliseconds */
1592
+ durationMs: number;
1593
+ /** Post-script execution result (if any) */
1594
+ postScriptResult?: {
1595
+ executed: boolean;
1596
+ error?: string;
1597
+ };
1598
+ /** Number of changes marked as stale (if configName provided) */
1599
+ staleCount?: number;
1600
+ /** ID of the reset record created (if configName provided) */
1601
+ resetRecordId?: number;
1602
+ }
1603
+ /**
1604
+ * Preview of what would be affected by teardown.
1605
+ */
1606
+ export interface TeardownPreview {
1607
+ /** Objects that would be dropped */
1608
+ toDrop: {
1609
+ tables: string[];
1610
+ views: string[];
1611
+ functions: string[];
1612
+ procedures: string[];
1613
+ types: string[];
1614
+ foreignKeys: string[];
1615
+ };
1616
+ /** Objects that would be preserved */
1617
+ toPreserve: string[];
1618
+ /** SQL statements that would execute */
1619
+ statements: string[];
1620
+ }
1621
+ export declare class DbNamespace {
1622
+ #private;
1623
+ constructor(state: ContextState);
1624
+ /**
1625
+ * List all tables in the database.
1179
1626
  *
1180
- * @param options - Execution options
1181
- * @returns Batch result
1627
+ * @example
1628
+ * ```typescript
1629
+ * const tables = await ctx.noorm.db.listTables()
1630
+ * ```
1182
1631
  */
1183
- ff(options?: BatchChangeOptions): Promise<BatchChangeResult>;
1632
+ listTables(): Promise<TableSummary[]>;
1184
1633
  /**
1185
- * Rewind: revert changes in reverse order.
1634
+ * Get detailed information about a table.
1186
1635
  *
1187
- * @param target - Number of changes to revert, or name to revert to
1188
- * @param options - Execution options
1189
- * @returns Batch result
1636
+ * @example
1637
+ * ```typescript
1638
+ * const detail = await ctx.noorm.db.describeTable('users')
1639
+ * ```
1190
1640
  */
1191
- rewind(target: number | string, options?: BatchChangeOptions): Promise<BatchChangeResult>;
1641
+ describeTable(name: string, schema?: string): Promise<TableDetail | null>;
1192
1642
  /**
1193
- * Get execution history.
1643
+ * Get database overview with counts of all object types.
1194
1644
  *
1195
- * @param name - Optional change name (all if not provided)
1196
- * @param limit - Max records to return
1197
- * @returns Array of history records
1645
+ * @example
1646
+ * ```typescript
1647
+ * const overview = await ctx.noorm.db.overview()
1648
+ * ```
1198
1649
  */
1199
- getHistory(name?: string, limit?: number): Promise<ChangeHistoryRecord[]>;
1650
+ overview(): Promise<ExploreOverview>;
1200
1651
  /**
1201
- * Get file execution history for an operation.
1652
+ * Preview what teardown would drop without executing.
1653
+ *
1654
+ * @example
1655
+ * ```typescript
1656
+ * const preview = await ctx.noorm.db.previewTeardown()
1657
+ * ```
1202
1658
  */
1203
- getFileHistory(operationId: number): Promise<FileHistoryRecord[]>;
1659
+ previewTeardown(): Promise<TeardownPreview>;
1204
1660
  /**
1205
- * Remove a change from disk, database, or both.
1661
+ * Wipe all data, keeping the schema intact.
1206
1662
  *
1207
- * @param name - Change name
1208
- * @param options - What to remove
1663
+ * @example
1664
+ * ```typescript
1665
+ * const result = await ctx.noorm.db.truncate()
1666
+ * ```
1209
1667
  */
1210
- remove(name: string, options: {
1211
- disk?: boolean;
1212
- db?: boolean;
1213
- }): Promise<void>;
1668
+ truncate(): Promise<TruncateResult>;
1214
1669
  /**
1215
- * Get a specific change by name.
1670
+ * Drop all database objects except noorm tracking tables.
1671
+ *
1672
+ * @example
1673
+ * ```typescript
1674
+ * const result = await ctx.noorm.db.teardown()
1675
+ * ```
1216
1676
  */
1217
- get(name: string): Promise<ChangeListItem | null>;
1677
+ teardown(): Promise<TeardownResult>;
1218
1678
  /**
1219
- * Load a change from disk.
1679
+ * Full rebuild: teardown + build.
1680
+ *
1681
+ * @example
1682
+ * ```typescript
1683
+ * await ctx.noorm.db.reset()
1684
+ * ```
1220
1685
  */
1221
- load(name: string): Promise<Change>;
1686
+ reset(): Promise<void>;
1687
+ /** @internal Used by NoormOps to wire up reset -> build. */
1688
+ set _buildFn(fn: (opts?: BuildOptions) => Promise<unknown>);
1222
1689
  }
1223
1690
  /**
1224
1691
  * Lock manager types.
@@ -1368,6 +1835,286 @@ export declare class LockExpiredError extends Error {
1368
1835
  readonly name: "LockExpiredError";
1369
1836
  constructor(configName: string, identity: string, expiredAt: Date);
1370
1837
  }
1838
+ export declare class LockNamespace {
1839
+ #private;
1840
+ constructor(state: ContextState);
1841
+ /**
1842
+ * Acquire a database lock.
1843
+ *
1844
+ * @example
1845
+ * ```typescript
1846
+ * const lock = await ctx.noorm.lock.acquire({ timeout: 60000 })
1847
+ * ```
1848
+ */
1849
+ acquire(options?: LockOptions$1): Promise<Lock$1>;
1850
+ /**
1851
+ * Release the current lock.
1852
+ *
1853
+ * @example
1854
+ * ```typescript
1855
+ * await ctx.noorm.lock.release()
1856
+ * ```
1857
+ */
1858
+ release(): Promise<void>;
1859
+ /**
1860
+ * Get current lock status.
1861
+ *
1862
+ * @example
1863
+ * ```typescript
1864
+ * const status = await ctx.noorm.lock.status()
1865
+ * ```
1866
+ */
1867
+ status(): Promise<LockStatus>;
1868
+ /**
1869
+ * Execute an operation with automatic lock acquisition and release.
1870
+ *
1871
+ * @example
1872
+ * ```typescript
1873
+ * await ctx.noorm.lock.withLock(async () => {
1874
+ * await ctx.noorm.run.build()
1875
+ * })
1876
+ * ```
1877
+ */
1878
+ withLock<T>(fn: () => Promise<T>, options?: LockOptions$1): Promise<T>;
1879
+ /**
1880
+ * Force release any database lock regardless of ownership.
1881
+ *
1882
+ * @example
1883
+ * ```typescript
1884
+ * await ctx.noorm.lock.forceRelease()
1885
+ * ```
1886
+ */
1887
+ forceRelease(): Promise<boolean>;
1888
+ }
1889
+ /**
1890
+ * Vault secret entry (decrypted).
1891
+ */
1892
+ export interface VaultSecret {
1893
+ /** Secret key name */
1894
+ key: string;
1895
+ /** Decrypted value */
1896
+ value: string;
1897
+ /** Identity who set this secret */
1898
+ setBy: string;
1899
+ /** When created */
1900
+ createdAt: Date;
1901
+ /** When last updated */
1902
+ updatedAt: Date;
1903
+ }
1904
+ /**
1905
+ * Result of vault copy operation.
1906
+ */
1907
+ export interface VaultCopyResult {
1908
+ /** Keys that were successfully copied */
1909
+ copied: string[];
1910
+ /** Keys that were skipped (already exist and force not set) */
1911
+ skipped: string[];
1912
+ /** Keys that failed with errors */
1913
+ errors: Array<{
1914
+ key: string;
1915
+ error: string;
1916
+ }>;
1917
+ }
1918
+ /**
1919
+ * Result of vault propagation.
1920
+ */
1921
+ export interface VaultPropagationResult {
1922
+ /** Identity hashes that received the vault key */
1923
+ propagatedTo: string[];
1924
+ /** Count of users who already had access */
1925
+ alreadyHadAccess: number;
1926
+ }
1927
+ /**
1928
+ * Vault status for the current user.
1929
+ */
1930
+ export interface VaultStatus {
1931
+ /** Whether the vault is initialized (at least one user has the vault key) */
1932
+ isInitialized: boolean;
1933
+ /** Whether the current user has access to the vault */
1934
+ hasAccess: boolean;
1935
+ /** Number of secrets in the vault */
1936
+ secretCount: number;
1937
+ /** Number of users with vault access */
1938
+ usersWithAccess: number;
1939
+ /** Number of users without vault access */
1940
+ usersWithoutAccess: number;
1941
+ }
1942
+ /**
1943
+ * Vault event types.
1944
+ *
1945
+ * All events emitted by the vault module. These are merged into
1946
+ * NoormEvents via the VaultEvents interface.
1947
+ */
1948
+ /**
1949
+ * Vault events for observer integration.
1950
+ *
1951
+ * Events follow the naming convention `vault:{operation}`.
1952
+ */
1953
+ export interface VaultEvents {
1954
+ /** Vault was initialized for the first time */
1955
+ "vault:initialized": {
1956
+ identityHash: string;
1957
+ };
1958
+ /** New vault secret was created */
1959
+ "vault:secret:created": {
1960
+ key: string;
1961
+ setBy: string;
1962
+ };
1963
+ /** Existing vault secret was updated */
1964
+ "vault:secret:updated": {
1965
+ key: string;
1966
+ setBy: string;
1967
+ };
1968
+ /** Vault secret was deleted */
1969
+ "vault:secret:deleted": {
1970
+ key: string;
1971
+ };
1972
+ /** Vault key was propagated to a user */
1973
+ "vault:propagated": {
1974
+ toIdentityHash: string;
1975
+ toEmail: string;
1976
+ };
1977
+ /** Vault copy operation started */
1978
+ "vault:copy:starting": {
1979
+ source: string;
1980
+ destination: string;
1981
+ keys: "all" | number;
1982
+ };
1983
+ /** Vault copy operation completed */
1984
+ "vault:copy:completed": {
1985
+ source: string;
1986
+ destination: string;
1987
+ copied: number;
1988
+ skipped: number;
1989
+ errors: number;
1990
+ };
1991
+ }
1992
+ /**
1993
+ * Options for vault copy operation.
1994
+ */
1995
+ export interface VaultCopyOptions {
1996
+ /** Overwrite existing secrets in destination (default: false) */
1997
+ force?: boolean;
1998
+ }
1999
+ export declare class VaultNamespace {
2000
+ #private;
2001
+ constructor(state: ContextState);
2002
+ /**
2003
+ * Initialize the vault for this database.
2004
+ *
2005
+ * @example
2006
+ * ```typescript
2007
+ * const [vaultKey, err] = await ctx.noorm.vault.init()
2008
+ * ```
2009
+ */
2010
+ init(): Promise<[
2011
+ Buffer | null,
2012
+ Error | null
2013
+ ]>;
2014
+ /**
2015
+ * Get vault status.
2016
+ *
2017
+ * @example
2018
+ * ```typescript
2019
+ * const status = await ctx.noorm.vault.status()
2020
+ * ```
2021
+ */
2022
+ status(): Promise<VaultStatus>;
2023
+ /**
2024
+ * Set a vault secret.
2025
+ *
2026
+ * @example
2027
+ * ```typescript
2028
+ * const [, err] = await ctx.noorm.vault.set('API_KEY', 'sk-live-...', privateKey)
2029
+ * ```
2030
+ */
2031
+ set(key: string, value: string, privateKey: string): Promise<[
2032
+ void,
2033
+ Error | null
2034
+ ]>;
2035
+ /**
2036
+ * Get a vault secret by key.
2037
+ *
2038
+ * @example
2039
+ * ```typescript
2040
+ * const value = await ctx.noorm.vault.get('API_KEY', privateKey)
2041
+ * ```
2042
+ */
2043
+ get(key: string, privateKey: string): Promise<string | null>;
2044
+ /**
2045
+ * Get all vault secrets.
2046
+ *
2047
+ * @example
2048
+ * ```typescript
2049
+ * const all = await ctx.noorm.vault.getAll(privateKey)
2050
+ * ```
2051
+ */
2052
+ getAll(privateKey: string): Promise<Record<string, VaultSecret>>;
2053
+ /**
2054
+ * List all vault secret keys (without decrypting values).
2055
+ *
2056
+ * @example
2057
+ * ```typescript
2058
+ * const keys = await ctx.noorm.vault.list()
2059
+ * ```
2060
+ */
2061
+ list(): Promise<string[]>;
2062
+ /**
2063
+ * Delete a vault secret.
2064
+ *
2065
+ * @example
2066
+ * ```typescript
2067
+ * const [deleted, err] = await ctx.noorm.vault.delete('OLD_KEY')
2068
+ * ```
2069
+ */
2070
+ delete(key: string): Promise<[
2071
+ boolean,
2072
+ Error | null
2073
+ ]>;
2074
+ /**
2075
+ * Check if a vault secret exists.
2076
+ *
2077
+ * @example
2078
+ * ```typescript
2079
+ * const exists = await ctx.noorm.vault.exists('API_KEY')
2080
+ * ```
2081
+ */
2082
+ exists(key: string): Promise<boolean>;
2083
+ /**
2084
+ * Propagate vault key to all users without access.
2085
+ *
2086
+ * @example
2087
+ * ```typescript
2088
+ * const result = await ctx.noorm.vault.propagate(privateKey)
2089
+ * ```
2090
+ */
2091
+ propagate(privateKey: string): Promise<VaultPropagationResult>;
2092
+ /**
2093
+ * Copy vault secrets to another config's database.
2094
+ *
2095
+ * @example
2096
+ * ```typescript
2097
+ * const [result, err] = await ctx.noorm.vault.copy(destConfig, ['API_KEY'], privateKey)
2098
+ * ```
2099
+ */
2100
+ copy(destConfig: Config, keys: string[] | "all", privateKey: string, options?: VaultCopyOptions): Promise<[
2101
+ VaultCopyResult | null,
2102
+ Error | null
2103
+ ]>;
2104
+ }
2105
+ export declare class SecretsNamespace {
2106
+ #private;
2107
+ constructor(state: ContextState);
2108
+ /**
2109
+ * Get a config-scoped secret.
2110
+ *
2111
+ * @example
2112
+ * ```typescript
2113
+ * const apiKey = ctx.noorm.secrets.get('API_KEY')
2114
+ * ```
2115
+ */
2116
+ get(key: string): string | undefined;
2117
+ }
1371
2118
  /**
1372
2119
  * Result of processing a SQL file.
1373
2120
  */
@@ -1385,6 +2132,19 @@ interface ProcessResult {
1385
2132
  */
1386
2133
  durationMs?: number;
1387
2134
  }
2135
+ export declare class TemplatesNamespace {
2136
+ #private;
2137
+ constructor(state: ContextState);
2138
+ /**
2139
+ * Render a template file without executing.
2140
+ *
2141
+ * @example
2142
+ * ```typescript
2143
+ * const result = await ctx.noorm.templates.render('sql/001_users.sql.tmpl')
2144
+ * ```
2145
+ */
2146
+ render(filepath: string): Promise<ProcessResult>;
2147
+ }
1388
2148
  /**
1389
2149
  * Simple types stored as native JSON values. No encoding tuple needed.
1390
2150
  */
@@ -1547,118 +2307,97 @@ export interface TransferResult {
1547
2307
  /** Total duration in milliseconds */
1548
2308
  durationMs: number;
1549
2309
  }
1550
- /**
1551
- * SDK Types.
1552
- *
1553
- * All interfaces and types for the noorm programmatic SDK.
1554
- */
1555
- /**
1556
- * Options for creating an SDK context.
1557
- *
1558
- * @example
1559
- * ```typescript
1560
- * // Basic usage with stored config
1561
- * const ctx = await createContext({ config: 'dev' })
1562
- *
1563
- * // Require test database for safety
1564
- * const ctx = await createContext({
1565
- * config: 'test',
1566
- * requireTest: true,
1567
- * })
1568
- *
1569
- * // Allow destructive ops on protected config
1570
- * const ctx = await createContext({
1571
- * config: 'staging',
1572
- * allowProtected: true,
1573
- * })
1574
- *
1575
- * // Env-only mode (CI/CD) - no stored config needed
1576
- * // Requires NOORM_CONNECTION_DIALECT and NOORM_CONNECTION_DATABASE
1577
- * const ctx = await createContext()
1578
- *
1579
- * // Override stored config via NOORM_* env vars
1580
- * // NOORM_CONNECTION_HOST=override.host
1581
- * const ctx = await createContext({ config: 'prod' })
1582
- * ```
1583
- */
1584
- export interface CreateContextOptions {
2310
+ export declare class TransferNamespace {
2311
+ #private;
2312
+ constructor(state: ContextState);
1585
2313
  /**
1586
- * Config name from state.
2314
+ * Transfer data to a destination database.
1587
2315
  *
1588
- * If omitted:
1589
- * - Uses `NOORM_CONFIG` env var if set
1590
- * - Falls back to env-only mode if `NOORM_CONNECTION_DIALECT`
1591
- * and `NOORM_CONNECTION_DATABASE` are set
2316
+ * @example
2317
+ * ```typescript
2318
+ * const [result, err] = await ctx.noorm.transfer.to(destConfig, {
2319
+ * tables: ['users', 'posts'],
2320
+ * onConflict: 'skip',
2321
+ * })
2322
+ * ```
1592
2323
  */
1593
- config?: string;
1594
- /** Project root directory. Defaults to process.cwd() */
1595
- projectRoot?: string;
1596
- /** Refuse if config.isTest !== true. Default: false */
1597
- requireTest?: boolean;
1598
- /** Allow destructive ops on protected configs. Default: false */
1599
- allowProtected?: boolean;
1600
- /** Stage name for stage defaults (from settings.yml) */
1601
- stage?: string;
1602
- }
1603
- /**
1604
- * Options for build operations.
1605
- */
1606
- export interface BuildOptions {
1607
- /** Skip checksum checks, rebuild everything. Default: false */
1608
- force?: boolean;
1609
- }
1610
- /**
1611
- * Options for exporting a table to a .dt file.
1612
- *
1613
- * Connection details (db, dialect) come from the context automatically.
1614
- *
1615
- * @example
1616
- * ```typescript
1617
- * const [result, err] = await ctx.exportTable('users', './exports/users.dtz', {
1618
- * passphrase: 'secret',
1619
- * batchSize: 5000,
1620
- * });
1621
- * ```
1622
- */
1623
- export interface ExportOptions {
1624
- /** Passphrase for .dtzx encryption. */
1625
- passphrase?: string;
1626
- /** Schema/namespace (e.g., 'public' for PostgreSQL). */
1627
- schema?: string;
1628
- /** Rows per batch. Default: 1000. */
1629
- batchSize?: number;
2324
+ to(destConfig: Config, options?: TransferOptions): Promise<[
2325
+ TransferResult | null,
2326
+ Error | null
2327
+ ]>;
2328
+ /**
2329
+ * Generate a transfer plan without executing.
2330
+ *
2331
+ * @example
2332
+ * ```typescript
2333
+ * const [plan, err] = await ctx.noorm.transfer.plan(destConfig)
2334
+ * ```
2335
+ */
2336
+ plan(destConfig: Config, options?: TransferOptions): Promise<[
2337
+ TransferPlan | null,
2338
+ Error | null
2339
+ ]>;
1630
2340
  }
1631
- /**
1632
- * Options for importing a .dt file into the database.
1633
- *
1634
- * Connection details (db, dialect) come from the context automatically.
1635
- *
1636
- * @example
1637
- * ```typescript
1638
- * const [result, err] = await ctx.importFile('./exports/users.dtz', {
1639
- * onConflict: 'skip',
1640
- * truncate: true,
1641
- * });
1642
- * ```
1643
- */
1644
- export interface ImportOptions {
1645
- /** Passphrase for .dtzx decryption. */
1646
- passphrase?: string;
1647
- /** Rows per batch. Default: 1000. */
1648
- batchSize?: number;
1649
- /** Conflict strategy. Default: 'fail'. */
1650
- onConflict?: "fail" | "skip" | "update" | "replace";
1651
- /** Truncate target table before import. Default: false. */
1652
- truncate?: boolean;
2341
+ export declare class DtNamespace {
2342
+ #private;
2343
+ constructor(state: ContextState);
2344
+ /**
2345
+ * Export a table to a .dt file.
2346
+ *
2347
+ * @example
2348
+ * ```typescript
2349
+ * const [result, err] = await ctx.noorm.dt.exportTable('users', './exports/users.dtz')
2350
+ * ```
2351
+ */
2352
+ exportTable(tableName: string, filepath: string, options?: ExportOptions): Promise<[
2353
+ {
2354
+ rowsWritten: number;
2355
+ bytesWritten: number;
2356
+ } | null,
2357
+ Error | null
2358
+ ]>;
2359
+ /**
2360
+ * Import a .dt file into the connected database.
2361
+ *
2362
+ * @example
2363
+ * ```typescript
2364
+ * const [result, err] = await ctx.noorm.dt.importFile('./exports/users.dtz', {
2365
+ * onConflict: 'skip',
2366
+ * })
2367
+ * ```
2368
+ */
2369
+ importFile(filepath: string, options?: ImportOptions): Promise<[
2370
+ {
2371
+ rowsImported: number;
2372
+ rowsSkipped: number;
2373
+ } | null,
2374
+ Error | null
2375
+ ]>;
1653
2376
  }
1654
- export interface ContextState {
1655
- connection: ConnectionResult | null;
1656
- config: Config;
1657
- settings: Settings;
1658
- identity: Identity;
1659
- options: CreateContextOptions;
1660
- projectRoot: string;
1661
- changeManager: ChangeManager | null;
2377
+ export declare class UtilsNamespace {
2378
+ #private;
2379
+ constructor(state: ContextState);
2380
+ /**
2381
+ * Compute SHA-256 checksum for a file.
2382
+ *
2383
+ * @example
2384
+ * ```typescript
2385
+ * const checksum = await ctx.noorm.utils.checksum('sql/001_users.sql')
2386
+ * ```
2387
+ */
2388
+ checksum(filepath: string): Promise<string>;
2389
+ /**
2390
+ * Tests if the connection can be established.
2391
+ *
2392
+ * @example
2393
+ * ```typescript
2394
+ * const result = await ctx.noorm.utils.testConnection()
2395
+ * ```
2396
+ */
2397
+ testConnection(): Promise<{
2398
+ ok: boolean;
2399
+ error?: string;
2400
+ }>;
1662
2401
  }
1663
2402
  export type Events<Shape> = keyof Shape;
1664
2403
  declare namespace ObserverEngine {
@@ -2334,62 +3073,12 @@ export interface UpdateEvents {
2334
3073
  version: string;
2335
3074
  reason: "user-denied" | "user-deferred";
2336
3075
  };
2337
- "global-settings:loaded": {
2338
- settings: GlobalSettings;
2339
- };
2340
- "global-settings:updated": {
2341
- key: string;
2342
- value: unknown;
2343
- };
2344
- }
2345
- /**
2346
- * Vault event types.
2347
- *
2348
- * All events emitted by the vault module. These are merged into
2349
- * NoormEvents via the VaultEvents interface.
2350
- */
2351
- /**
2352
- * Vault events for observer integration.
2353
- *
2354
- * Events follow the naming convention `vault:{operation}`.
2355
- */
2356
- export interface VaultEvents {
2357
- /** Vault was initialized for the first time */
2358
- "vault:initialized": {
2359
- identityHash: string;
2360
- };
2361
- /** New vault secret was created */
2362
- "vault:secret:created": {
2363
- key: string;
2364
- setBy: string;
2365
- };
2366
- /** Existing vault secret was updated */
2367
- "vault:secret:updated": {
2368
- key: string;
2369
- setBy: string;
2370
- };
2371
- /** Vault secret was deleted */
2372
- "vault:secret:deleted": {
2373
- key: string;
2374
- };
2375
- /** Vault key was propagated to a user */
2376
- "vault:propagated": {
2377
- toIdentityHash: string;
2378
- toEmail: string;
2379
- };
2380
- /** Vault copy operation started */
2381
- "vault:copy:starting": {
2382
- source: string;
2383
- destination: string;
2384
- keys: "all" | number;
3076
+ "global-settings:loaded": {
3077
+ settings: GlobalSettings;
2385
3078
  };
2386
- /** Vault copy operation completed */
2387
- "vault:copy:completed": {
2388
- source: string;
2389
- destination: string;
2390
- copied: number;
2391
- skipped: number;
2392
- errors: number;
3079
+ "global-settings:updated": {
3080
+ key: string;
3081
+ value: unknown;
2393
3082
  };
2394
3083
  }
2395
3084
  /**
@@ -2796,18 +3485,17 @@ export type NoormEventNames = Events<NoormEvents>;
2796
3485
  /**
2797
3486
  * Noorm-specific operations accessed via ctx.noorm.
2798
3487
  *
2799
- * All database management operations — schema, changes, locks,
2800
- * runner, explore, transfer, DT — live here. The shared ContextState
2801
- * keeps connection state in sync with the parent Context.
3488
+ * Domain-aligned sub-namespaces mirror the TUI home screen:
3489
+ * changes, run, db, lock, vault, secrets, templates, transfer, dt, utils.
2802
3490
  *
2803
3491
  * @example
2804
3492
  * ```typescript
2805
3493
  * const ctx = await createContext({ config: 'dev' })
2806
3494
  * await ctx.connect()
2807
3495
  *
2808
- * await ctx.noorm.build()
2809
- * await ctx.noorm.fastForward()
2810
- * const tables = await ctx.noorm.listTables()
3496
+ * await ctx.noorm.run.build()
3497
+ * await ctx.noorm.changes.ff()
3498
+ * const tables = await ctx.noorm.db.listTables()
2811
3499
  * ```
2812
3500
  */
2813
3501
  export declare class NoormOps {
@@ -2817,299 +3505,16 @@ export declare class NoormOps {
2817
3505
  get settings(): Settings;
2818
3506
  get identity(): Identity;
2819
3507
  get observer(): ObserverEngine<NoormEvents>;
2820
- /**
2821
- * List all tables in the database.
2822
- *
2823
- * @example
2824
- * ```typescript
2825
- * const tables = await ctx.noorm.listTables()
2826
- * ```
2827
- */
2828
- listTables(): Promise<TableSummary[]>;
2829
- /**
2830
- * Get detailed information about a table.
2831
- *
2832
- * @example
2833
- * ```typescript
2834
- * const detail = await ctx.noorm.describeTable('users')
2835
- * ```
2836
- */
2837
- describeTable(name: string, schema?: string): Promise<TableDetail | null>;
2838
- /**
2839
- * Get database overview with counts of all object types.
2840
- *
2841
- * @example
2842
- * ```typescript
2843
- * const overview = await ctx.noorm.overview()
2844
- * ```
2845
- */
2846
- overview(): Promise<ExploreOverview>;
2847
- /**
2848
- * Wipe all data, keeping the schema intact.
2849
- *
2850
- * @example
2851
- * ```typescript
2852
- * const result = await ctx.noorm.truncate()
2853
- * ```
2854
- */
2855
- truncate(): Promise<TruncateResult>;
2856
- /**
2857
- * Drop all database objects except noorm tracking tables.
2858
- *
2859
- * @example
2860
- * ```typescript
2861
- * const result = await ctx.noorm.teardown()
2862
- * ```
2863
- */
2864
- teardown(): Promise<TeardownResult>;
2865
- /**
2866
- * Execute all SQL files in the schema directory.
2867
- *
2868
- * @example
2869
- * ```typescript
2870
- * const result = await ctx.noorm.build({ force: true })
2871
- * ```
2872
- */
2873
- build(options?: BuildOptions): Promise<BatchResult>;
2874
- /**
2875
- * Full rebuild: teardown + build.
2876
- *
2877
- * @example
2878
- * ```typescript
2879
- * await ctx.noorm.reset()
2880
- * ```
2881
- */
2882
- reset(): Promise<void>;
2883
- /**
2884
- * Execute a single SQL file.
2885
- *
2886
- * @example
2887
- * ```typescript
2888
- * await ctx.noorm.runFile('seeds/test-data.sql')
2889
- * ```
2890
- */
2891
- runFile(filepath: string, options?: RunOptions): Promise<FileResult>;
2892
- /**
2893
- * Execute multiple SQL files sequentially.
2894
- *
2895
- * @example
2896
- * ```typescript
2897
- * await ctx.noorm.runFiles(['functions/utils.sql', 'triggers/audit.sql'])
2898
- * ```
2899
- */
2900
- runFiles(filepaths: string[], options?: RunOptions): Promise<BatchResult>;
2901
- /**
2902
- * Execute all SQL files in a directory.
2903
- *
2904
- * @example
2905
- * ```typescript
2906
- * await ctx.noorm.runDir('seeds/')
2907
- * ```
2908
- */
2909
- runDir(dirpath: string, options?: RunOptions): Promise<BatchResult>;
2910
- /**
2911
- * Apply a specific change.
2912
- *
2913
- * @example
2914
- * ```typescript
2915
- * const result = await ctx.noorm.applyChange('2024-01-15-add-users')
2916
- * ```
2917
- */
2918
- applyChange(name: string, options?: ChangeOptions): Promise<ChangeResult>;
2919
- /**
2920
- * Revert a specific change.
2921
- *
2922
- * @example
2923
- * ```typescript
2924
- * const result = await ctx.noorm.revertChange('2024-01-15-add-users')
2925
- * ```
2926
- */
2927
- revertChange(name: string, options?: ChangeOptions): Promise<ChangeResult>;
2928
- /**
2929
- * Apply all pending changes.
2930
- *
2931
- * @example
2932
- * ```typescript
2933
- * const result = await ctx.noorm.fastForward()
2934
- * ```
2935
- */
2936
- fastForward(): Promise<BatchChangeResult>;
2937
- /**
2938
- * Get status of all changes.
2939
- *
2940
- * @example
2941
- * ```typescript
2942
- * const changes = await ctx.noorm.getChangeStatus()
2943
- * ```
2944
- */
2945
- getChangeStatus(): Promise<ChangeListItem[]>;
2946
- /**
2947
- * Get only pending changes.
2948
- *
2949
- * @example
2950
- * ```typescript
2951
- * const pending = await ctx.noorm.getPendingChanges()
2952
- * ```
2953
- */
2954
- getPendingChanges(): Promise<ChangeListItem[]>;
2955
- /**
2956
- * Get a config-scoped secret.
2957
- *
2958
- * @example
2959
- * ```typescript
2960
- * const apiKey = ctx.noorm.getSecret('API_KEY')
2961
- * ```
2962
- */
2963
- getSecret(key: string): string | undefined;
2964
- /**
2965
- * Acquire a database lock.
2966
- *
2967
- * @example
2968
- * ```typescript
2969
- * const lock = await ctx.noorm.acquireLock({ timeout: 60000 })
2970
- * ```
2971
- */
2972
- acquireLock(options?: LockOptions$1): Promise<Lock$1>;
2973
- /**
2974
- * Release the current lock.
2975
- *
2976
- * @example
2977
- * ```typescript
2978
- * await ctx.noorm.releaseLock()
2979
- * ```
2980
- */
2981
- releaseLock(): Promise<void>;
2982
- /**
2983
- * Get current lock status.
2984
- *
2985
- * @example
2986
- * ```typescript
2987
- * const status = await ctx.noorm.getLockStatus()
2988
- * ```
2989
- */
2990
- getLockStatus(): Promise<LockStatus>;
2991
- /**
2992
- * Execute an operation with automatic lock acquisition and release.
2993
- *
2994
- * @example
2995
- * ```typescript
2996
- * await ctx.noorm.withLock(async () => {
2997
- * await ctx.noorm.build()
2998
- * await ctx.noorm.fastForward()
2999
- * })
3000
- * ```
3001
- */
3002
- withLock<T>(fn: () => Promise<T>, options?: LockOptions$1): Promise<T>;
3003
- /**
3004
- * Force release any database lock regardless of ownership.
3005
- *
3006
- * @example
3007
- * ```typescript
3008
- * await ctx.noorm.forceReleaseLock()
3009
- * ```
3010
- */
3011
- forceReleaseLock(): Promise<boolean>;
3012
- /**
3013
- * Render a template file without executing.
3014
- *
3015
- * @example
3016
- * ```typescript
3017
- * const result = await ctx.noorm.renderTemplate('sql/001_users.sql.tmpl')
3018
- * ```
3019
- */
3020
- renderTemplate(filepath: string): Promise<ProcessResult>;
3021
- /**
3022
- * Get execution history.
3023
- *
3024
- * @example
3025
- * ```typescript
3026
- * const history = await ctx.noorm.getHistory(10)
3027
- * ```
3028
- */
3029
- getHistory(limit?: number): Promise<ChangeHistoryRecord[]>;
3030
- /**
3031
- * Compute SHA-256 checksum for a file.
3032
- *
3033
- * @example
3034
- * ```typescript
3035
- * const checksum = await ctx.noorm.computeChecksum('sql/001_users.sql')
3036
- * ```
3037
- */
3038
- computeChecksum(filepath: string): Promise<string>;
3039
- /**
3040
- * Tests if the connection can be established.
3041
- *
3042
- * @example
3043
- * ```typescript
3044
- * const result = await ctx.noorm.testConnection()
3045
- * ```
3046
- */
3047
- testConnection(): Promise<{
3048
- ok: boolean;
3049
- error?: string;
3050
- }>;
3051
- /**
3052
- * Transfer data from this context's database to a destination context.
3053
- *
3054
- * Both contexts must be connected. Uses each context's config for
3055
- * connection management.
3056
- *
3057
- * @example
3058
- * ```typescript
3059
- * const [result, err] = await source.noorm.transferTo(dest, {
3060
- * tables: ['users', 'posts'],
3061
- * onConflict: 'skip',
3062
- * })
3063
- * ```
3064
- */
3065
- transferTo(destConfig: Config, options?: TransferOptions): Promise<[
3066
- TransferResult | null,
3067
- Error | null
3068
- ]>;
3069
- /**
3070
- * Generate a transfer plan without executing.
3071
- *
3072
- * @example
3073
- * ```typescript
3074
- * const [plan, err] = await source.noorm.transferPlan(destConfig)
3075
- * ```
3076
- */
3077
- transferPlan(destConfig: Config, options?: TransferOptions): Promise<[
3078
- TransferPlan | null,
3079
- Error | null
3080
- ]>;
3081
- /**
3082
- * Export a table to a .dt file.
3083
- *
3084
- * @example
3085
- * ```typescript
3086
- * const [result, err] = await ctx.noorm.exportTable('users', './exports/users.dtz')
3087
- * ```
3088
- */
3089
- exportTable(tableName: string, filepath: string, options?: ExportOptions): Promise<[
3090
- {
3091
- rowsWritten: number;
3092
- bytesWritten: number;
3093
- } | null,
3094
- Error | null
3095
- ]>;
3096
- /**
3097
- * Import a .dt file into the connected database.
3098
- *
3099
- * @example
3100
- * ```typescript
3101
- * const [result, err] = await ctx.noorm.importFile('./exports/users.dtz', {
3102
- * onConflict: 'skip',
3103
- * })
3104
- * ```
3105
- */
3106
- importFile(filepath: string, options?: ImportOptions): Promise<[
3107
- {
3108
- rowsImported: number;
3109
- rowsSkipped: number;
3110
- } | null,
3111
- Error | null
3112
- ]>;
3508
+ get changes(): ChangesNamespace;
3509
+ get run(): RunNamespace;
3510
+ get db(): DbNamespace;
3511
+ get lock(): LockNamespace;
3512
+ get vault(): VaultNamespace;
3513
+ get secrets(): SecretsNamespace;
3514
+ get templates(): TemplatesNamespace;
3515
+ get transfer(): TransferNamespace;
3516
+ get dt(): DtNamespace;
3517
+ get utils(): UtilsNamespace;
3113
3518
  }
3114
3519
  /**
3115
3520
  * SDK Context implementation.
@@ -3129,8 +3534,8 @@ export declare class NoormOps {
3129
3534
  * .execute()
3130
3535
  *
3131
3536
  * // Noorm operations — under namespace
3132
- * await ctx.noorm.build()
3133
- * await ctx.noorm.fastForward()
3537
+ * await ctx.noorm.run.build()
3538
+ * await ctx.noorm.changes.ff()
3134
3539
  *
3135
3540
  * await ctx.disconnect()
3136
3541
  * ```
@@ -3149,9 +3554,9 @@ export declare class Context<DB = unknown, Procs = object, Funcs = object> {
3149
3554
  *
3150
3555
  * @example
3151
3556
  * ```typescript
3152
- * await ctx.noorm.build()
3153
- * await ctx.noorm.fastForward()
3154
- * const tables = await ctx.noorm.listTables()
3557
+ * await ctx.noorm.run.build()
3558
+ * await ctx.noorm.changes.ff()
3559
+ * const tables = await ctx.noorm.db.listTables()
3155
3560
  * ```
3156
3561
  */
3157
3562
  get noorm(): NoormOps;