@zintrust/d1-migrator 1.8.1 → 1.8.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"DataMigrator.d.ts","sourceRoot":"","sources":["../../src/cli/DataMigrator.ts"],"names":[],"mappings":"AACA;;;GAGG;AAWH,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,GAAG,WAAW,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxE,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAsEF;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB;;OAEG;wBACuB,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmFtE;;OAEG;4BAC2B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoEzE;;OAEG;4BAC2B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyCzE;;OAEG;0CAEiB,gBAAgB,oBAChB,gBAAgB,UAC1B,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC;IAqChB;;OAEG;+BAC8B,gBAAgB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,EAAE,CAAA;KAAE,CAAC;IAiBpF;;OAEG;wBAEM,SAAS,oBACE,gBAAgB,oBAChB,gBAAgB,UAC1B,eAAe,GACtB,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA4EtD;;OAEG;oCAEiB,gBAAgB,aACvB,MAAM,UACT,MAAM,aACH,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAkBrC;;OAEG;yBAEM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,aACrB,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IA4CrC;;OAEG;iCAEiB,gBAAgB,aACvB,MAAM,QACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAC9B,OAAO,CAAC,MAAM,CAAC;IAkClB;;OAEG;gCACyB,eAAe,CAAC,cAAc,CAAC,aAAa,MAAM,GAAG,MAAM;IAavF;;OAEG;wCAEM,MAAM,UACL,MAAM,gBACA,MAAM,gBACN,MAAM,GACnB,0BAA0B;IAS7B;;OAEG;gCACyB,MAAM,GAAG,iBAAiB;IAetD;;OAEG;6BAES,iBAAiB,WAClB,OAAO,CAAC,iBAAiB,CAAC,GAClC,iBAAiB;EAGpB,CAAC"}
1
+ {"version":3,"file":"DataMigrator.d.ts","sourceRoot":"","sources":["../../src/cli/DataMigrator.ts"],"names":[],"mappings":"AACA;;;GAGG;AAWH,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,GAAG,WAAW,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxE,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAkLF;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB;;OAEG;wBACuB,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAqFtE;;OAEG;4BAC2B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4BzE;;OAEG;4BAC2B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyCzE;;OAEG;0CAEiB,gBAAgB,oBAChB,gBAAgB,UAC1B,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC;IAqChB;;OAEG;+BAC8B,gBAAgB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,EAAE,CAAA;KAAE,CAAC;IAiBpF;;OAEG;wBAEM,SAAS,oBACE,gBAAgB,oBAChB,gBAAgB,UAC1B,eAAe,GACtB,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA4EtD;;OAEG;oCAEiB,gBAAgB,aACvB,MAAM,UACT,MAAM,aACH,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAkBrC;;OAEG;yBAEM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,aACrB,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IA4CrC;;OAEG;iCAEiB,gBAAgB,aACvB,MAAM,QACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAC9B,OAAO,CAAC,MAAM,CAAC;IAkClB;;OAEG;gCACyB,eAAe,CAAC,cAAc,CAAC,aAAa,MAAM,GAAG,MAAM;IAavF;;OAEG;wCAEM,MAAM,UACL,MAAM,gBACA,MAAM,gBACN,MAAM,GACnB,0BAA0B;IAS7B;;OAEG;gCACyB,MAAM,GAAG,iBAAiB;IAetD;;OAEG;6BAES,iBAAiB,WAClB,OAAO,CAAC,iBAAiB,CAAC,GAClC,iBAAiB;EAGpB,CAAC"}
@@ -10,6 +10,47 @@ import { SQLiteAdapter } from '@zintrust/db-sqlite';
10
10
  import { SQLServerAdapter } from '@zintrust/db-sqlserver';
11
11
  import { SchemaBuilder } from '../schema/SchemaBuilder.js';
12
12
  import { SchemaAnalyzer } from './SchemaAnalyzer.js';
13
+ const redactConnectionString = (connectionString) => {
14
+ try {
15
+ const parsed = new URL(connectionString);
16
+ if (parsed.password.trim() !== '') {
17
+ parsed.password = '***';
18
+ }
19
+ return parsed.toString();
20
+ }
21
+ catch {
22
+ return connectionString;
23
+ }
24
+ };
25
+ const getErrorCause = (error) => {
26
+ if (error === null || typeof error !== 'object') {
27
+ return undefined;
28
+ }
29
+ return error.cause;
30
+ };
31
+ const getErrorMessage = (error) => {
32
+ if (error instanceof Error) {
33
+ return error.message;
34
+ }
35
+ return String(error);
36
+ };
37
+ const getErrorChainMessages = (error) => {
38
+ const messages = [];
39
+ let current = error;
40
+ while (current !== undefined) {
41
+ const message = getErrorMessage(current);
42
+ if (message.trim() !== '') {
43
+ messages.push(message);
44
+ }
45
+ current = getErrorCause(current);
46
+ }
47
+ return [...new Set(messages)];
48
+ };
49
+ const describePasswordForLog = (password) => {
50
+ const hasSpecialCharacters = /[^a-zA-Z0-9]/.test(password);
51
+ const containsBang = password.includes('!');
52
+ return `len=${password.length}, special_chars=${hasSpecialCharacters}, contains_bang=${containsBang}`;
53
+ };
13
54
  const normalizeNullLikeValue = (value) => {
14
55
  if (typeof value !== 'string')
15
56
  return value;
@@ -51,6 +92,47 @@ const parseSqliteDatabasePath = (connectionString) => {
51
92
  return trimmed;
52
93
  }
53
94
  };
95
+ const createSourceAdapter = (config) => {
96
+ switch (config.sourceDriver) {
97
+ case 'mysql': {
98
+ const connectionDetails = parseConnectionDetails(config.sourceConnection, 3306, 'mysql', 'root');
99
+ Logger.info(`[DataMigrator] Source password diagnostics: ${describePasswordForLog(connectionDetails.password)}`);
100
+ return MySQLAdapter.create({
101
+ driver: 'mysql',
102
+ connectionString: config.sourceConnection,
103
+ });
104
+ }
105
+ case 'postgresql': {
106
+ const connectionDetails = parseConnectionDetails(config.sourceConnection, 5432, 'postgres', 'postgres');
107
+ return PostgreSQLAdapter.create({
108
+ driver: 'postgresql',
109
+ host: connectionDetails.host,
110
+ port: connectionDetails.port,
111
+ database: connectionDetails.database,
112
+ username: connectionDetails.username,
113
+ password: connectionDetails.password,
114
+ });
115
+ }
116
+ case 'sqlite':
117
+ return SQLiteAdapter.create({
118
+ driver: 'sqlite',
119
+ database: parseSqliteDatabasePath(config.sourceConnection),
120
+ });
121
+ case 'sqlserver': {
122
+ const connectionDetails = parseConnectionDetails(config.sourceConnection, 1433, 'master', 'sa');
123
+ return SQLServerAdapter.create({
124
+ driver: 'sqlserver',
125
+ host: connectionDetails.host,
126
+ port: connectionDetails.port,
127
+ database: connectionDetails.database,
128
+ username: connectionDetails.username,
129
+ password: connectionDetails.password,
130
+ });
131
+ }
132
+ default:
133
+ throw ErrorFactory.createValidationError(`Unsupported driver: ${config.sourceDriver}`);
134
+ }
135
+ };
54
136
  const safelyDisconnect = async (label, connection) => {
55
137
  try {
56
138
  await connection?.adapter?.disconnect?.();
@@ -121,7 +203,9 @@ export const DataMigrator = Object.freeze({
121
203
  return progress;
122
204
  }
123
205
  catch (error) {
124
- Logger.error('Data migration failed:', error);
206
+ const errorChain = getErrorChainMessages(error);
207
+ Logger.error(`Data migration failed: ${errorChain.join(' -> ')}`);
208
+ Logger.error('Data migration failure details:', error);
125
209
  throw error;
126
210
  }
127
211
  finally {
@@ -133,49 +217,18 @@ export const DataMigrator = Object.freeze({
133
217
  * Connect to source database
134
218
  */
135
219
  async connectToSource(config) {
136
- Logger.info(`Connecting to ${config.sourceDriver} database: ${config.sourceConnection}`);
137
- let adapter;
138
- switch (config.sourceDriver) {
139
- case 'mysql':
140
- adapter = MySQLAdapter.create({
141
- driver: 'mysql',
142
- connectionString: config.sourceConnection,
143
- });
144
- break;
145
- case 'postgresql': {
146
- const connectionDetails = parseConnectionDetails(config.sourceConnection, 5432, 'postgres', 'postgres');
147
- adapter = PostgreSQLAdapter.create({
148
- driver: 'postgresql',
149
- host: connectionDetails.host,
150
- port: connectionDetails.port,
151
- database: connectionDetails.database,
152
- username: connectionDetails.username,
153
- password: connectionDetails.password,
154
- });
155
- break;
156
- }
157
- case 'sqlite':
158
- adapter = SQLiteAdapter.create({
159
- driver: 'sqlite',
160
- database: parseSqliteDatabasePath(config.sourceConnection),
161
- });
162
- break;
163
- case 'sqlserver': {
164
- const connectionDetails = parseConnectionDetails(config.sourceConnection, 1433, 'master', 'sa');
165
- adapter = SQLServerAdapter.create({
166
- driver: 'sqlserver',
167
- host: connectionDetails.host,
168
- port: connectionDetails.port,
169
- database: connectionDetails.database,
170
- username: connectionDetails.username,
171
- password: connectionDetails.password,
172
- });
173
- break;
174
- }
175
- default:
176
- throw ErrorFactory.createValidationError(`Unsupported driver: ${config.sourceDriver}`);
220
+ Logger.info(`Connecting to ${config.sourceDriver} database...`);
221
+ Logger.info(`[DataMigrator] Source connection (redacted): ${redactConnectionString(config.sourceConnection)}`);
222
+ const adapter = createSourceAdapter(config);
223
+ try {
224
+ await adapter.connect();
225
+ }
226
+ catch (error) {
227
+ const errorChain = getErrorChainMessages(error);
228
+ Logger.error(`Source database connection failed: ${errorChain.join(' -> ')}`);
229
+ Logger.error('Source database connection failure details:', error);
230
+ throw error;
177
231
  }
178
- await adapter.connect();
179
232
  const connection = {
180
233
  driver: config.sourceDriver,
181
234
  connectionString: config.sourceConnection || '',
@@ -1 +1 @@
1
- {"version":3,"file":"MigrateToD1Command.d.ts","sourceRoot":"","sources":["../../src/cli/MigrateToD1Command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAOhD,KAAK,iBAAiB,GAAG;IACvB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,IAAI,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B,CAAC;AAwgBF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,iBAgG/B,CAAC;AAEH;;GAEG;AACH,iBAAe,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CActE;AAED;;GAEG;AACH,iBAAe,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAkGxE;AAED;;GAEG;AACH,iBAAe,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAiGtE;AAED;;GAEG;AACH,iBAAS,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CA2BrF;AAGD,eAAO,MAAM,iBAAiB;;;;;EAK5B,CAAC"}
1
+ {"version":3,"file":"MigrateToD1Command.d.ts","sourceRoot":"","sources":["../../src/cli/MigrateToD1Command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAOhD,KAAK,iBAAiB,GAAG;IACvB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,IAAI,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B,CAAC;AA6rBF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,iBA4G/B,CAAC;AAEH;;GAEG;AACH,iBAAe,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CActE;AAED;;GAEG;AACH,iBAAe,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAkGxE;AAED;;GAEG;AACH,iBAAe,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAiGtE;AAED;;GAEG;AACH,iBAAS,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CA2BrF;AAGD,eAAO,MAAM,iBAAiB;;;;;EAK5B,CAAC"}
@@ -48,6 +48,18 @@ const TARGET_DATABASE_ENV_KEYS = Object.freeze([
48
48
  'D1_DATABASE',
49
49
  'D1_DATABASE_ID',
50
50
  ]);
51
+ const uniq = (items) => {
52
+ const seen = new Set();
53
+ const out = [];
54
+ for (const item of items) {
55
+ if (seen.has(item)) {
56
+ continue;
57
+ }
58
+ seen.add(item);
59
+ out.push(item);
60
+ }
61
+ return out;
62
+ };
51
63
  const describeConfiguredD1Target = (config) => {
52
64
  const parts = [];
53
65
  if (typeof config.database_name === 'string' && config.database_name.trim() !== '') {
@@ -157,6 +169,112 @@ const encodeConnectionSegment = (value) => {
157
169
  return `%${match.charCodeAt(0).toString(16).toUpperCase()}`;
158
170
  });
159
171
  };
172
+ const decodeConnectionSegment = (value) => {
173
+ return value.trim() === '' ? '' : decodeURIComponent(value);
174
+ };
175
+ const getNetworkScheme = (sourceDriver) => {
176
+ if (sourceDriver === 'mysql')
177
+ return 'mysql';
178
+ if (sourceDriver === 'postgresql')
179
+ return 'postgresql';
180
+ if (sourceDriver === 'sqlserver')
181
+ return 'mssql';
182
+ return undefined;
183
+ };
184
+ const getDefaultNetworkPort = (sourceDriver) => {
185
+ if (sourceDriver === 'mysql')
186
+ return 3306;
187
+ if (sourceDriver === 'postgresql')
188
+ return 5432;
189
+ return 1433;
190
+ };
191
+ const parseNetworkConnectionDetails = (connectionString, sourceDriver) => {
192
+ const expectedScheme = getNetworkScheme(sourceDriver);
193
+ if (expectedScheme === undefined) {
194
+ return undefined;
195
+ }
196
+ try {
197
+ const parsed = new URL(connectionString);
198
+ const protocol = parsed.protocol.replace(/:$/, '').toLowerCase();
199
+ const allowedProtocols = sourceDriver === 'sqlserver' ? ['mssql', 'sqlserver'] : [expectedScheme];
200
+ if (!allowedProtocols.includes(protocol)) {
201
+ return undefined;
202
+ }
203
+ return {
204
+ scheme: expectedScheme,
205
+ host: parsed.hostname || 'localhost',
206
+ port: parsed.port.trim() === ''
207
+ ? getDefaultNetworkPort(sourceDriver)
208
+ : Number.parseInt(parsed.port, 10),
209
+ database: decodeConnectionSegment(parsed.pathname.replace(/^\/+/, '')),
210
+ username: decodeConnectionSegment(parsed.username),
211
+ password: decodeConnectionSegment(parsed.password),
212
+ };
213
+ }
214
+ catch {
215
+ return undefined;
216
+ }
217
+ };
218
+ const normalizeSourceConnectionString = (sourceConnection, sourceDriver) => {
219
+ const details = parseNetworkConnectionDetails(sourceConnection, sourceDriver);
220
+ if (details === undefined) {
221
+ return sourceConnection;
222
+ }
223
+ return buildNetworkConnectionString(details);
224
+ };
225
+ const redactConnectionString = (sourceConnection) => {
226
+ try {
227
+ const parsed = new URL(sourceConnection);
228
+ if (parsed.password.trim() !== '') {
229
+ parsed.password = '***';
230
+ }
231
+ return parsed.toString();
232
+ }
233
+ catch {
234
+ return sourceConnection;
235
+ }
236
+ };
237
+ const describePasswordForLog = (password) => {
238
+ const hasSpecialCharacters = /[^a-zA-Z0-9]/.test(password);
239
+ const containsBang = password.includes('!');
240
+ return `len=${password.length}, special_chars=${hasSpecialCharacters}, contains_bang=${containsBang}`;
241
+ };
242
+ const getErrorCause = (error) => {
243
+ if (error === null || typeof error !== 'object') {
244
+ return undefined;
245
+ }
246
+ return error.cause;
247
+ };
248
+ const getErrorMessage = (error) => {
249
+ if (error instanceof Error) {
250
+ return error.message;
251
+ }
252
+ return String(error);
253
+ };
254
+ const getErrorChainMessages = (error) => {
255
+ const messages = [];
256
+ let current = error;
257
+ while (current !== undefined) {
258
+ const message = getErrorMessage(current);
259
+ if (message.trim() !== '') {
260
+ messages.push(message);
261
+ }
262
+ current = getErrorCause(current);
263
+ }
264
+ return uniq(messages);
265
+ };
266
+ const logSourceConnectionDiagnostics = (sourceDriver, sourceConnection, origin, originalValue) => {
267
+ Logger.info(`[d1-migrator] Source connection origin: ${origin}`);
268
+ Logger.info(`[d1-migrator] Source connection driver: ${sourceDriver}`);
269
+ Logger.info(`[d1-migrator] Source connection (redacted): ${redactConnectionString(sourceConnection)}`);
270
+ const originalDetails = parseNetworkConnectionDetails(originalValue, sourceDriver);
271
+ const finalDetails = parseNetworkConnectionDetails(sourceConnection, sourceDriver);
272
+ if (originalDetails === undefined || finalDetails === undefined) {
273
+ Logger.info('[d1-migrator] Source connection diagnostics: non-network source or unable to parse URL');
274
+ return;
275
+ }
276
+ Logger.info(`[d1-migrator] Source password diagnostics: provided(${describePasswordForLog(originalDetails.password)}), final(${describePasswordForLog(finalDetails.password)}), matches=${originalDetails.password === finalDetails.password}`);
277
+ };
160
278
  const normalizeSourceDriver = (value) => {
161
279
  if (value === undefined) {
162
280
  return undefined;
@@ -272,15 +390,27 @@ const buildSourceConnectionFromDbEnv = (sourceDriver) => {
272
390
  const resolveSourceConnection = (options, sourceDriver) => {
273
391
  const fromOption = readOptionString(options, ['source-connection', 'sourceConnection']);
274
392
  if (fromOption !== undefined) {
275
- return fromOption;
393
+ return {
394
+ value: normalizeSourceConnectionString(fromOption, sourceDriver),
395
+ origin: 'option',
396
+ originalValue: fromOption,
397
+ };
276
398
  }
277
399
  const fromEnv = readEnvString(SOURCE_CONNECTION_ENV_KEYS);
278
400
  if (fromEnv !== undefined) {
279
- return fromEnv;
401
+ return {
402
+ value: normalizeSourceConnectionString(fromEnv, sourceDriver),
403
+ origin: 'env',
404
+ originalValue: fromEnv,
405
+ };
280
406
  }
281
407
  const fromDbEnv = buildSourceConnectionFromDbEnv(sourceDriver);
282
408
  if (fromDbEnv !== undefined && fromDbEnv.trim().length > 0) {
283
- return fromDbEnv;
409
+ return {
410
+ value: normalizeSourceConnectionString(fromDbEnv, sourceDriver),
411
+ origin: 'db-env',
412
+ originalValue: fromDbEnv,
413
+ };
284
414
  }
285
415
  throw ErrorFactory.createValidationError('Source connection is required. Use --source-connection or set MIGRATE_TO_D1_SOURCE_CONNECTION (or DB_* variables)');
286
416
  };
@@ -314,7 +444,7 @@ const resolveTargetDatabase = (options) => {
314
444
  };
315
445
  const resolveMigrationConfig = (options) => {
316
446
  const sourceDriver = resolveSourceDriver(options);
317
- const sourceConnection = resolveSourceConnection(options, sourceDriver);
447
+ const sourceConnectionResolution = resolveSourceConnection(options, sourceDriver);
318
448
  const targetDatabase = resolveTargetDatabase(options);
319
449
  const targetType = resolveTargetType(options);
320
450
  const dryRun = resolveFlag(options, ['dry-run', 'dryRun'], ['MIGRATE_TO_D1_DRY_RUN', 'D1_MIGRATOR_DRY_RUN']);
@@ -328,7 +458,7 @@ const resolveMigrationConfig = (options) => {
328
458
  }
329
459
  return {
330
460
  config: {
331
- sourceConnection,
461
+ sourceConnection: sourceConnectionResolution.value,
332
462
  sourceDriver,
333
463
  targetDatabase,
334
464
  targetType,
@@ -339,6 +469,8 @@ const resolveMigrationConfig = (options) => {
339
469
  migrationId,
340
470
  },
341
471
  schemaOnly,
472
+ sourceConnectionOrigin: sourceConnectionResolution.origin,
473
+ originalSourceConnection: sourceConnectionResolution.originalValue,
342
474
  };
343
475
  };
344
476
  /**
@@ -366,7 +498,8 @@ export const MigrateToD1Command = BaseCommand.create({
366
498
  execute: async (options) => {
367
499
  try {
368
500
  Logger.info('Starting D1 migration process...');
369
- const { config, schemaOnly } = resolveMigrationConfig(options);
501
+ const { config, schemaOnly, sourceConnectionOrigin, originalSourceConnection } = resolveMigrationConfig(options);
502
+ logSourceConnectionDiagnostics(config.sourceDriver, config.sourceConnection, sourceConnectionOrigin, originalSourceConnection);
370
503
  const configValidation = validateConfig(config);
371
504
  if (!configValidation.valid) {
372
505
  throw ErrorFactory.createValidationError(`Invalid migration configuration: ${configValidation.errors.join(', ')}`);
@@ -419,8 +552,10 @@ export const MigrateToD1Command = BaseCommand.create({
419
552
  Logger.info('D1 migration completed successfully');
420
553
  }
421
554
  catch (error) {
422
- Logger.error('Migration failed:', error);
423
- throw ErrorFactory.createValidationError(`Migration failed: ${error}`);
555
+ const errorChain = getErrorChainMessages(error);
556
+ Logger.error(`Migration failed: ${errorChain.join(' -> ')}`);
557
+ Logger.error('Migration failure details:', error);
558
+ throw ErrorFactory.createValidationError(`Migration failed: ${errorChain[0] ?? getErrorMessage(error)}`, error);
424
559
  }
425
560
  },
426
561
  });
@@ -1 +1 @@
1
- {"version":3,"file":"SchemaAnalyzer.d.ts","sourceRoot":"","sources":["../../src/cli/SchemaAnalyzer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SchemaAnalyzer.d.ts","sourceRoot":"","sources":["../../src/cli/SchemaAnalyzer.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,42 @@ import { MySQLAdapter } from '@zintrust/db-mysql';
7
7
  import { PostgreSQLAdapter } from '@zintrust/db-postgres';
8
8
  import { SQLiteAdapter } from '@zintrust/db-sqlite';
9
9
  import { SQLServerAdapter } from '@zintrust/db-sqlserver';
10
+ const redactConnectionString = (connectionString) => {
11
+ try {
12
+ const parsed = new URL(connectionString);
13
+ if (parsed.password.trim() !== '') {
14
+ parsed.password = '***';
15
+ }
16
+ return parsed.toString();
17
+ }
18
+ catch {
19
+ return connectionString;
20
+ }
21
+ };
22
+ const getErrorCause = (error) => {
23
+ if (error === null || typeof error !== 'object') {
24
+ return undefined;
25
+ }
26
+ return error.cause;
27
+ };
28
+ const getErrorMessage = (error) => {
29
+ if (error instanceof Error) {
30
+ return error.message;
31
+ }
32
+ return String(error);
33
+ };
34
+ const getErrorChainMessages = (error) => {
35
+ const messages = [];
36
+ let current = error;
37
+ while (current !== undefined) {
38
+ const message = getErrorMessage(current);
39
+ if (message.trim() !== '') {
40
+ messages.push(message);
41
+ }
42
+ current = getErrorCause(current);
43
+ }
44
+ return [...new Set(messages)];
45
+ };
10
46
  /**
11
47
  * SchemaAnalyzer - Sealed namespace for schema analysis
12
48
  * Provides database schema analysis and compatibility checking
@@ -40,6 +76,7 @@ export const SchemaAnalyzer = Object.freeze({
40
76
  */
41
77
  async extractTables(connection) {
42
78
  Logger.info(`Extracting tables from ${connection.driver} database...`);
79
+ Logger.info(`[SchemaAnalyzer] Source connection (redacted): ${redactConnectionString(connection.connectionString)}`);
43
80
  try {
44
81
  // Create appropriate adapter based on driver
45
82
  let adapter;
@@ -79,8 +116,10 @@ export const SchemaAnalyzer = Object.freeze({
79
116
  return tableSchemas;
80
117
  }
81
118
  catch (error) {
82
- Logger.error('Failed to extract database tables:', error);
83
- throw ErrorFactory.createTryCatchError('Schema extraction failed', error);
119
+ const errorChain = getErrorChainMessages(error);
120
+ Logger.error(`Failed to extract database tables: ${errorChain.join(' -> ')}`);
121
+ Logger.error('Schema extraction failure details:', error);
122
+ throw ErrorFactory.createTryCatchError(`Schema extraction failed: ${errorChain[0] ?? getErrorMessage(error)}`, error);
84
123
  }
85
124
  },
86
125
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/d1-migrator",
3
- "version": "1.8.1",
3
+ "version": "1.8.2",
4
4
  "description": "Resumable database migration toolkit for moving data to Cloudflare D1 with ZinTrust.",
5
5
  "private": false,
6
6
  "type": "module",