@opencrvs/toolkit 2.0.0-rc.fc7f7fc → 2.0.0-rc.fef9d21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/cli.js +1383 -142
  2. package/dist/commons/api/router.d.ts +42 -63
  3. package/dist/migrations/v2.0/add-birth-certificate-issuance-flag.d.ts.map +1 -1
  4. package/dist/migrations/v2.0/add-birth-certificate-issuance-flag.js +3 -4
  5. package/dist/migrations/v2.0/add-resend-invite-notification.d.ts +3 -0
  6. package/dist/migrations/v2.0/add-resend-invite-notification.d.ts.map +1 -0
  7. package/dist/migrations/v2.0/add-resend-invite-notification.js +373 -0
  8. package/dist/migrations/v2.0/checkout-upstream-files.d.ts +19 -0
  9. package/dist/migrations/v2.0/checkout-upstream-files.d.ts.map +1 -1
  10. package/dist/migrations/v2.0/checkout-upstream-files.js +17 -13
  11. package/dist/migrations/v2.0/convert-config-files-to-ts.d.ts.map +1 -1
  12. package/dist/migrations/v2.0/convert-config-files-to-ts.js +4 -5
  13. package/dist/migrations/v2.0/convert-paragraph-to-heading.d.ts.map +1 -1
  14. package/dist/migrations/v2.0/convert-paragraph-to-heading.js +4 -5
  15. package/dist/migrations/v2.0/create-events-index.d.ts.map +1 -1
  16. package/dist/migrations/v2.0/create-events-index.js +1 -2
  17. package/dist/migrations/v2.0/delete-infrastructure-directory.d.ts +3 -0
  18. package/dist/migrations/v2.0/delete-infrastructure-directory.d.ts.map +1 -0
  19. package/dist/migrations/v2.0/delete-infrastructure-directory.js +77 -0
  20. package/dist/migrations/v2.0/index.d.ts +8 -4
  21. package/dist/migrations/v2.0/index.d.ts.map +1 -1
  22. package/dist/migrations/v2.0/index.js +1351 -139
  23. package/dist/migrations/v2.0/make-built-in-validate-actions-custom.d.ts.map +1 -1
  24. package/dist/migrations/v2.0/make-built-in-validate-actions-custom.js +5 -6
  25. package/dist/migrations/v2.0/merge-infrastructure-directory.d.ts +3 -0
  26. package/dist/migrations/v2.0/merge-infrastructure-directory.d.ts.map +1 -0
  27. package/dist/migrations/v2.0/merge-infrastructure-directory.js +221 -0
  28. package/dist/migrations/v2.0/migrate-application-config-url.d.ts +3 -0
  29. package/dist/migrations/v2.0/migrate-application-config-url.d.ts.map +1 -0
  30. package/dist/migrations/v2.0/migrate-application-config-url.js +342 -0
  31. package/dist/migrations/v2.0/migrate-scopes.d.ts.map +1 -1
  32. package/dist/migrations/v2.0/migrate-scopes.js +6 -7
  33. package/dist/migrations/v2.0/migrate-validated-workqueue-status-to-flag.d.ts.map +1 -1
  34. package/dist/migrations/v2.0/migrate-validated-workqueue-status-to-flag.js +3 -4
  35. package/dist/migrations/v2.0/migrate-workqueue-configs.d.ts.map +1 -1
  36. package/dist/migrations/v2.0/migrate-workqueue-configs.js +3 -4
  37. package/dist/migrations/v2.0/remove-delete-actions.d.ts.map +1 -1
  38. package/dist/migrations/v2.0/remove-delete-actions.js +3 -4
  39. package/dist/migrations/v2.0/remove-demo-scope.d.ts.map +1 -1
  40. package/dist/migrations/v2.0/remove-demo-scope.js +2 -3
  41. package/dist/migrations/v2.0/remove-deprecated-imports.d.ts.map +1 -1
  42. package/dist/migrations/v2.0/remove-deprecated-imports.js +3 -4
  43. package/dist/migrations/v2.0/remove-fhir-url-helpers.d.ts +3 -0
  44. package/dist/migrations/v2.0/remove-fhir-url-helpers.d.ts.map +1 -0
  45. package/dist/migrations/v2.0/remove-fhir-url-helpers.js +163 -0
  46. package/dist/migrations/v2.0/remove-hearth-migrations.d.ts.map +1 -1
  47. package/dist/migrations/v2.0/remove-hearth-migrations.js +1 -2
  48. package/dist/migrations/v2.0/remove-old-statistics-service.d.ts +3 -0
  49. package/dist/migrations/v2.0/remove-old-statistics-service.d.ts.map +1 -0
  50. package/dist/migrations/v2.0/remove-old-statistics-service.js +356 -0
  51. package/dist/migrations/v2.0/remove-pending-certification-flag.d.ts.map +1 -1
  52. package/dist/migrations/v2.0/remove-pending-certification-flag.js +3 -4
  53. package/dist/migrations/v2.0/remove-review-from-register-action.d.ts.map +1 -1
  54. package/dist/migrations/v2.0/remove-review-from-register-action.js +3 -4
  55. package/dist/migrations/v2.0/remove-unused-environment-variables.d.ts +3 -0
  56. package/dist/migrations/v2.0/remove-unused-environment-variables.d.ts.map +1 -0
  57. package/dist/migrations/v2.0/remove-unused-environment-variables.js +186 -0
  58. package/dist/migrations/v2.0/rename-api-paths.d.ts.map +1 -1
  59. package/dist/migrations/v2.0/rename-api-paths.js +3 -4
  60. package/dist/migrations/v2.0/rename-location-parent-id.d.ts.map +1 -1
  61. package/dist/migrations/v2.0/rename-location-parent-id.js +3 -4
  62. package/dist/migrations/v2.0/simplify-analytics-precalculations.d.ts.map +1 -1
  63. package/dist/migrations/v2.0/simplify-analytics-precalculations.js +1 -2
  64. package/dist/migrations/v2.0/update-package-json.d.ts +3 -0
  65. package/dist/migrations/v2.0/update-package-json.d.ts.map +1 -0
  66. package/dist/migrations/v2.0/update-package-json.js +105 -0
  67. package/opencrvs-toolkit-2.0.0-rc.fef9d21.tgz +0 -0
  68. package/package.json +1 -1
  69. package/tsconfig.tsbuildinfo +1 -1
  70. package/opencrvs-toolkit-2.0.0-rc.fc7f7fc.tgz +0 -0
@@ -31,7 +31,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/migrations/v2.0/index.ts
32
32
  var v2_exports = {};
33
33
  __export(v2_exports, {
34
- getCwd: () => getCwd,
35
34
  runUpgrade: () => runUpgrade
36
35
  });
37
36
  module.exports = __toCommonJS(v2_exports);
@@ -104,7 +103,7 @@ function processFile(filePath, project) {
104
103
  if (wasRemoved) {
105
104
  removedCount++;
106
105
  console.log(
107
- ` [${import_path.default.relative(getCwd(), filePath)}] Removed 'review' from REGISTER action`
106
+ ` [${import_path.default.relative(process.cwd(), filePath)}] Removed 'review' from REGISTER action`
108
107
  );
109
108
  }
110
109
  }
@@ -112,7 +111,7 @@ function processFile(filePath, project) {
112
111
  return removedCount;
113
112
  }
114
113
  async function main() {
115
- const srcDir = import_path.default.join(getCwd(), "src");
114
+ const srcDir = import_path.default.join(process.cwd(), "src");
116
115
  console.log(`Scanning for defineConfig calls in: ${srcDir}
117
116
  `);
118
117
  const project = new import_ts_morph.Project({
@@ -148,7 +147,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
148
147
  for (const filePath of modifiedFiles) {
149
148
  const sourceFile = project.getSourceFileOrThrow(filePath);
150
149
  await sourceFile.save();
151
- console.log(` Saved: ${import_path.default.relative(getCwd(), filePath)}`);
150
+ console.log(` Saved: ${import_path.default.relative(process.cwd(), filePath)}`);
152
151
  }
153
152
  console.log(
154
153
  `
@@ -351,7 +350,7 @@ function processFile2(filePath, project) {
351
350
  const eventType = resolveEventType(configArg);
352
351
  if (!eventType) {
353
352
  console.warn(
354
- ` [${import_path2.default.relative(getCwd(), configArg.getSourceFile().getFilePath())}] Could not resolve root 'type' from defineConfig \u2014 skipping auditHistoryLabel id generation`
353
+ ` [${import_path2.default.relative(process.cwd(), configArg.getSourceFile().getFilePath())}] Could not resolve root 'type' from defineConfig \u2014 skipping auditHistoryLabel id generation`
355
354
  );
356
355
  }
357
356
  let fileNeedsImports = false;
@@ -367,7 +366,7 @@ function processFile2(filePath, project) {
367
366
  fileNeedsImports = true;
368
367
  configHadValidateAction = true;
369
368
  console.log(
370
- ` [${import_path2.default.relative(getCwd(), filePath)}] Transformed VALIDATE action to CUSTOM with customActionType: '${VALIDATE_DECLARATION_VALUE}'`
369
+ ` [${import_path2.default.relative(process.cwd(), filePath)}] Transformed VALIDATE action to CUSTOM with customActionType: '${VALIDATE_DECLARATION_VALUE}'`
371
370
  );
372
371
  }
373
372
  }
@@ -388,7 +387,7 @@ function processFile2(filePath, project) {
388
387
  ]`
389
388
  });
390
389
  console.log(
391
- ` [${import_path2.default.relative(getCwd(), filePath)}] Added top-level 'flags' array to defineConfig`
390
+ ` [${import_path2.default.relative(process.cwd(), filePath)}] Added top-level 'flags' array to defineConfig`
392
391
  );
393
392
  }
394
393
  if (fileNeedsImports) {
@@ -398,7 +397,7 @@ function processFile2(filePath, project) {
398
397
  return transformedCount;
399
398
  }
400
399
  async function main2() {
401
- const srcDir = import_path2.default.join(getCwd(), "src");
400
+ const srcDir = import_path2.default.join(process.cwd(), "src");
402
401
  console.log(`Scanning for defineConfig calls in: ${srcDir}
403
402
  `);
404
403
  const project = new import_ts_morph2.Project({
@@ -433,7 +432,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
433
432
  for (const filePath of modifiedFiles) {
434
433
  const sourceFile = project.getSourceFileOrThrow(filePath);
435
434
  await sourceFile.save();
436
- console.log(` Saved: ${import_path2.default.relative(getCwd(), filePath)}`);
435
+ console.log(` Saved: ${import_path2.default.relative(process.cwd(), filePath)}`);
437
436
  }
438
437
  console.log(
439
438
  `
@@ -504,14 +503,14 @@ function processFile3(filePath, project) {
504
503
  actionsInitializer.removeElement(index);
505
504
  removedCount++;
506
505
  console.log(
507
- ` [${import_path3.default.relative(getCwd(), filePath)}] Removed DELETE action at index ${index}`
506
+ ` [${import_path3.default.relative(process.cwd(), filePath)}] Removed DELETE action at index ${index}`
508
507
  );
509
508
  }
510
509
  }
511
510
  return removedCount;
512
511
  }
513
512
  async function main3() {
514
- const srcDir = import_path3.default.join(getCwd(), "src");
513
+ const srcDir = import_path3.default.join(process.cwd(), "src");
515
514
  console.log(`Scanning for defineConfig calls in: ${srcDir}
516
515
  `);
517
516
  const project = new import_ts_morph3.Project({
@@ -546,7 +545,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
546
545
  for (const filePath of modifiedFiles) {
547
546
  const sourceFile = project.getSourceFileOrThrow(filePath);
548
547
  await sourceFile.save();
549
- console.log(` Saved: ${import_path3.default.relative(getCwd(), filePath)}`);
548
+ console.log(` Saved: ${import_path3.default.relative(process.cwd(), filePath)}`);
550
549
  }
551
550
  console.log(
552
551
  `
@@ -620,19 +619,19 @@ function processFile4(filePath, project) {
620
619
  if (result === "converted-to-heading") {
621
620
  changedCount++;
622
621
  console.log(
623
- ` [${import_path4.default.relative(getCwd(), filePath)}] Converted PARAGRAPH with heading fontVariant to HEADING`
622
+ ` [${import_path4.default.relative(process.cwd(), filePath)}] Converted PARAGRAPH with heading fontVariant to HEADING`
624
623
  );
625
624
  } else if (result === "removed-font-variant") {
626
625
  changedCount++;
627
626
  console.log(
628
- ` [${import_path4.default.relative(getCwd(), filePath)}] Removed non-heading fontVariant from PARAGRAPH`
627
+ ` [${import_path4.default.relative(process.cwd(), filePath)}] Removed non-heading fontVariant from PARAGRAPH`
629
628
  );
630
629
  }
631
630
  }
632
631
  return changedCount;
633
632
  }
634
633
  async function main4() {
635
- const srcDir = import_path4.default.join(getCwd(), "src");
634
+ const srcDir = import_path4.default.join(process.cwd(), "src");
636
635
  console.log(`Scanning for FieldType.PARAGRAPH fields in: ${srcDir}
637
636
  `);
638
637
  const project = new import_ts_morph4.Project({
@@ -666,7 +665,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
666
665
  for (const filePath of modifiedFiles) {
667
666
  const sourceFile = project.getSourceFileOrThrow(filePath);
668
667
  await sourceFile.save();
669
- console.log(` Saved: ${import_path4.default.relative(getCwd(), filePath)}`);
668
+ console.log(` Saved: ${import_path4.default.relative(process.cwd(), filePath)}`);
670
669
  }
671
670
  console.log(`
672
671
  Done. Processed ${totalChanged} FieldType.PARAGRAPH field(s).`);
@@ -816,7 +815,7 @@ function processFile5(filePath, project) {
816
815
  if (changed > 0) {
817
816
  migratedCount += changed;
818
817
  console.log(
819
- ` [${import_path5.default.relative(getCwd(), filePath)}] Migrated ${changed} clause(s): VALIDATED status \u2192 flags.anyOf`
818
+ ` [${import_path5.default.relative(process.cwd(), filePath)}] Migrated ${changed} clause(s): VALIDATED status \u2192 flags.anyOf`
820
819
  );
821
820
  }
822
821
  }
@@ -824,7 +823,7 @@ function processFile5(filePath, project) {
824
823
  return migratedCount;
825
824
  }
826
825
  async function main5() {
827
- const srcDir = import_path5.default.join(getCwd(), "src");
826
+ const srcDir = import_path5.default.join(process.cwd(), "src");
828
827
  console.log(`Scanning for defineWorkqueues calls in: ${srcDir}
829
828
  `);
830
829
  const project = new import_ts_morph5.Project({
@@ -858,7 +857,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
858
857
  for (const filePath of modifiedFiles) {
859
858
  const sourceFile = project.getSourceFileOrThrow(filePath);
860
859
  await sourceFile.save();
861
- console.log(` Saved: ${import_path5.default.relative(getCwd(), filePath)}`);
860
+ console.log(` Saved: ${import_path5.default.relative(process.cwd(), filePath)}`);
862
861
  }
863
862
  console.log(
864
863
  `
@@ -1076,7 +1075,7 @@ function processFile6(filePath, project) {
1076
1075
  const sourceFile = project.getSourceFile(filePath);
1077
1076
  if (!sourceFile) return 0;
1078
1077
  let totalChanges = 0;
1079
- const relPath = import_path6.default.relative(getCwd(), filePath);
1078
+ const relPath = import_path6.default.relative(process.cwd(), filePath);
1080
1079
  const callExpressions = sourceFile.getDescendantsOfKind(
1081
1080
  import_ts_morph6.SyntaxKind.CallExpression
1082
1081
  );
@@ -1117,7 +1116,7 @@ function processFile6(filePath, project) {
1117
1116
  return totalChanges;
1118
1117
  }
1119
1118
  async function main6() {
1120
- const srcDir = import_path6.default.join(getCwd(), "src");
1119
+ const srcDir = import_path6.default.join(process.cwd(), "src");
1121
1120
  console.log(
1122
1121
  `Scanning for birth defineConfig and PRINT_CERTIFICATE workqueues in: ${srcDir}
1123
1122
  `
@@ -1153,7 +1152,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
1153
1152
  for (const filePath of modifiedFiles) {
1154
1153
  const sourceFile = project.getSourceFileOrThrow(filePath);
1155
1154
  await sourceFile.save();
1156
- console.log(` Saved: ${import_path6.default.relative(getCwd(), filePath)}`);
1155
+ console.log(` Saved: ${import_path6.default.relative(process.cwd(), filePath)}`);
1157
1156
  }
1158
1157
  console.log(
1159
1158
  `
@@ -1190,14 +1189,14 @@ function processFile7(filePath, project) {
1190
1189
  array3.removeElement(index);
1191
1190
  removedCount++;
1192
1191
  console.log(
1193
- ` [${import_path7.default.relative(getCwd(), filePath)}] Removed InherentFlags.PENDING_CERTIFICATION from array`
1192
+ ` [${import_path7.default.relative(process.cwd(), filePath)}] Removed InherentFlags.PENDING_CERTIFICATION from array`
1194
1193
  );
1195
1194
  }
1196
1195
  }
1197
1196
  return removedCount;
1198
1197
  }
1199
1198
  async function main7() {
1200
- const srcDir = import_path7.default.join(getCwd(), "src");
1199
+ const srcDir = import_path7.default.join(process.cwd(), "src");
1201
1200
  console.log(
1202
1201
  `Scanning for InherentFlags.PENDING_CERTIFICATION array elements in: ${srcDir}
1203
1202
  `
@@ -1233,7 +1232,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
1233
1232
  for (const filePath of modifiedFiles) {
1234
1233
  const sourceFile = project.getSourceFileOrThrow(filePath);
1235
1234
  await sourceFile.save();
1236
- console.log(` Saved: ${import_path7.default.relative(getCwd(), filePath)}`);
1235
+ console.log(` Saved: ${import_path7.default.relative(process.cwd(), filePath)}`);
1237
1236
  }
1238
1237
  console.log(
1239
1238
  `
@@ -1291,13 +1290,13 @@ function processFile8(filePath, project) {
1291
1290
  propAccess.getNameNode().replaceWithText(NEW_PROPERTY_NAME);
1292
1291
  renamedCount++;
1293
1292
  console.log(
1294
- ` [${import_path8.default.relative(getCwd(), filePath)}] Renamed Location.${OLD_PROPERTY_NAME} \u2192 Location.${NEW_PROPERTY_NAME}`
1293
+ ` [${import_path8.default.relative(process.cwd(), filePath)}] Renamed Location.${OLD_PROPERTY_NAME} \u2192 Location.${NEW_PROPERTY_NAME}`
1295
1294
  );
1296
1295
  }
1297
1296
  return renamedCount;
1298
1297
  }
1299
1298
  async function main8() {
1300
- const srcDir = import_path8.default.join(getCwd(), "src");
1299
+ const srcDir = import_path8.default.join(process.cwd(), "src");
1301
1300
  console.log(
1302
1301
  `Scanning for Location.${OLD_PROPERTY_NAME} references in: ${srcDir}
1303
1302
  `
@@ -1333,7 +1332,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
1333
1332
  for (const filePath of modifiedFiles) {
1334
1333
  const sourceFile = project.getSourceFileOrThrow(filePath);
1335
1334
  await sourceFile.save();
1336
- console.log(` Saved: ${import_path8.default.relative(getCwd(), filePath)}`);
1335
+ console.log(` Saved: ${import_path8.default.relative(process.cwd(), filePath)}`);
1337
1336
  }
1338
1337
  console.log(
1339
1338
  `
@@ -1400,7 +1399,7 @@ function processFile9(filePath, project) {
1400
1399
  const sourceFile = project.getSourceFile(filePath);
1401
1400
  if (!sourceFile) return 0;
1402
1401
  let renamedCount = 0;
1403
- const relPath = import_path9.default.relative(getCwd(), filePath);
1402
+ const relPath = import_path9.default.relative(process.cwd(), filePath);
1404
1403
  const candidates = sourceFile.getDescendantsOfKind(
1405
1404
  import_ts_morph9.SyntaxKind.ObjectLiteralExpression
1406
1405
  );
@@ -1415,7 +1414,7 @@ function processFile9(filePath, project) {
1415
1414
  return renamedCount;
1416
1415
  }
1417
1416
  async function main9() {
1418
- const srcDir = import_path9.default.join(getCwd(), "src");
1417
+ const srcDir = import_path9.default.join(process.cwd(), "src");
1419
1418
  console.log(`Scanning for Hapi route configs in: ${srcDir}
1420
1419
  `);
1421
1420
  console.log("Active path renames:");
@@ -1452,7 +1451,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
1452
1451
  for (const filePath of modifiedFiles) {
1453
1452
  const sourceFile = project.getSourceFileOrThrow(filePath);
1454
1453
  await sourceFile.save();
1455
- console.log(` Saved: ${import_path9.default.relative(getCwd(), filePath)}`);
1454
+ console.log(` Saved: ${import_path9.default.relative(process.cwd(), filePath)}`);
1456
1455
  }
1457
1456
  console.log(`
1458
1457
  Done. Renamed ${totalRenamed} route path(s).`);
@@ -1826,9 +1825,9 @@ function updateRouteHandlers(sourceFiles, group, srcDir, relCwd) {
1826
1825
  }
1827
1826
  return replacedCount;
1828
1827
  }
1829
- function resolveConfigChain(configObj, path17) {
1828
+ function resolveConfigChain(configObj, path23) {
1830
1829
  let current = configObj;
1831
- for (const key of path17) {
1830
+ for (const key of path23) {
1832
1831
  if (!import_ts_morph10.Node.isObjectLiteralExpression(current)) return null;
1833
1832
  const prop = current.getProperty(key);
1834
1833
  if (!prop || !import_ts_morph10.Node.isPropertyAssignment(prop)) return null;
@@ -1873,8 +1872,8 @@ function ensureJoinImport(sf) {
1873
1872
  });
1874
1873
  }
1875
1874
  async function main10() {
1876
- const srcDir = import_path10.default.join(getCwd(), "src");
1877
- const relCwd = (fp) => import_path10.default.relative(getCwd(), fp);
1875
+ const srcDir = import_path10.default.join(process.cwd(), "src");
1876
+ const relCwd = (fp) => import_path10.default.relative(process.cwd(), fp);
1878
1877
  console.log("Phase 1: Converting JS config files to TypeScript...\n");
1879
1878
  let convertedCount = 0;
1880
1879
  for (const group of CONFIG_GROUPS) {
@@ -1962,7 +1961,7 @@ async function main10() {
1962
1961
  ensureJoinImport(sf);
1963
1962
  }
1964
1963
  console.log(
1965
- ` Inlined applicationConfig.${accessPath.join(".")} \u2192 ${adjustedValue} in ${import_path10.default.relative(getCwd(), sf.getFilePath())}`
1964
+ ` Inlined applicationConfig.${accessPath.join(".")} \u2192 ${adjustedValue} in ${import_path10.default.relative(process.cwd(), sf.getFilePath())}`
1966
1965
  );
1967
1966
  filesToSaveAfterInlining.add(sf);
1968
1967
  madeReplacement = true;
@@ -1974,7 +1973,7 @@ async function main10() {
1974
1973
  for (const sf of Array.from(filesToSaveAfterInlining)) {
1975
1974
  await sf.save();
1976
1975
  console.log(
1977
- ` Saved (inlined): ${import_path10.default.relative(getCwd(), sf.getFilePath())}`
1976
+ ` Saved (inlined): ${import_path10.default.relative(process.cwd(), sf.getFilePath())}`
1978
1977
  );
1979
1978
  }
1980
1979
  for (const prop of [...propsToRemove].reverse()) {
@@ -2591,7 +2590,7 @@ function migrateScopesArrays(rolesFilePath, project) {
2591
2590
  const scopeKey = resolveScopeKeyFromElementAccess(element);
2592
2591
  if (scopeKey && !(scopeKey in SCOPES)) {
2593
2592
  console.warn(
2594
- ` [${import_path11.default.relative(getCwd(), rolesFilePath)}] Removing unknown scope reference: SCOPES.${scopeKey}`
2593
+ ` [${import_path11.default.relative(process.cwd(), rolesFilePath)}] Removing unknown scope reference: SCOPES.${scopeKey}`
2595
2594
  );
2596
2595
  initializer.removeElement(index);
2597
2596
  removedCount++;
@@ -2600,7 +2599,7 @@ function migrateScopesArrays(rolesFilePath, project) {
2600
2599
  const legacyScope = resolveLegacyScopeFromElement(element);
2601
2600
  if (!legacyScope) {
2602
2601
  console.warn(
2603
- ` [${import_path11.default.relative(getCwd(), rolesFilePath)}] Skipping non-literal scope expression: ${element.getText()}`
2602
+ ` [${import_path11.default.relative(process.cwd(), rolesFilePath)}] Skipping non-literal scope expression: ${element.getText()}`
2604
2603
  );
2605
2604
  continue;
2606
2605
  }
@@ -2609,7 +2608,7 @@ function migrateScopesArrays(rolesFilePath, project) {
2609
2608
  const scope = decodeScope(migratedScope);
2610
2609
  if (!scope) {
2611
2610
  console.warn(
2612
- ` [${import_path11.default.relative(getCwd(), rolesFilePath)}] Could not decode migrated scope '${migratedScope}'.`
2611
+ ` [${import_path11.default.relative(process.cwd(), rolesFilePath)}] Could not decode migrated scope '${migratedScope}'.`
2613
2612
  );
2614
2613
  continue;
2615
2614
  }
@@ -2617,14 +2616,14 @@ function migrateScopesArrays(rolesFilePath, project) {
2617
2616
  migratedCount++;
2618
2617
  } catch (error) {
2619
2618
  console.warn(
2620
- ` [${import_path11.default.relative(getCwd(), rolesFilePath)}] Could not migrate scope '${legacyScope}': ${error}`
2619
+ ` [${import_path11.default.relative(process.cwd(), rolesFilePath)}] Could not migrate scope '${legacyScope}': ${error}`
2621
2620
  );
2622
2621
  }
2623
2622
  }
2624
2623
  }
2625
2624
  if (removedCount > 0) {
2626
2625
  console.log(
2627
- ` Removed ${removedCount} unknown SCOPES reference(s) from '${import_path11.default.relative(getCwd(), rolesFilePath)}'.`
2626
+ ` Removed ${removedCount} unknown SCOPES reference(s) from '${import_path11.default.relative(process.cwd(), rolesFilePath)}'.`
2628
2627
  );
2629
2628
  }
2630
2629
  return { migratedCount, removedCount };
@@ -2746,9 +2745,9 @@ function removeRoleTypeDefinitionAndUnusedImports(rolesFilePath, project) {
2746
2745
  return removed;
2747
2746
  }
2748
2747
  async function main11() {
2749
- const cwd2 = getCwd();
2750
- const srcDir = import_path11.default.join(cwd2, "src");
2751
- const rolesFilePath = import_path11.default.join(cwd2, ROLES_FILE_RELATIVE_PATH);
2748
+ const cwd = process.cwd();
2749
+ const srcDir = import_path11.default.join(cwd, "src");
2750
+ const rolesFilePath = import_path11.default.join(cwd, ROLES_FILE_RELATIVE_PATH);
2752
2751
  console.log(`Scanning roles scopes in: ${rolesFilePath}`);
2753
2752
  const project = new import_ts_morph11.Project({
2754
2753
  tsConfigFilePath: import_path11.default.resolve(srcDir, "../tsconfig.json"),
@@ -2812,13 +2811,13 @@ function processFile10(filePath, project) {
2812
2811
  decl.remove();
2813
2812
  }
2814
2813
  console.log(
2815
- ` [${import_path12.default.relative(getCwd(), filePath)}] Removed ${matchingNamedImports.length} deprecated '${DEPRECATED_IMPORT}' import(s) from '${decl.getModuleSpecifierValue()}'`
2814
+ ` [${import_path12.default.relative(process.cwd(), filePath)}] Removed ${matchingNamedImports.length} deprecated '${DEPRECATED_IMPORT}' import(s) from '${decl.getModuleSpecifierValue()}'`
2816
2815
  );
2817
2816
  }
2818
2817
  return removedCount;
2819
2818
  }
2820
2819
  async function main12() {
2821
- const srcDir = import_path12.default.join(getCwd(), "src");
2820
+ const srcDir = import_path12.default.join(process.cwd(), "src");
2822
2821
  console.log(`Scanning for deprecated imports in: ${srcDir}
2823
2822
  `);
2824
2823
  const project = new import_ts_morph12.Project({
@@ -2849,15 +2848,738 @@ async function main12() {
2849
2848
  Saving ${modifiedFiles.length} modified file(s)...`);
2850
2849
  for (const filePath of modifiedFiles) {
2851
2850
  await project.getSourceFileOrThrow(filePath).save();
2852
- console.log(` Saved: ${import_path12.default.relative(getCwd(), filePath)}`);
2851
+ console.log(` Saved: ${import_path12.default.relative(process.cwd(), filePath)}`);
2853
2852
  }
2854
2853
  console.log(`
2855
2854
  Done. Removed ${totalRemoved} deprecated import(s).`);
2856
2855
  }
2857
2856
 
2858
- // src/migrations/v2.0/migrate-workqueue-configs.ts
2859
- var import_ts_morph13 = require("ts-morph");
2857
+ // src/migrations/v2.0/remove-unused-environment-variables.ts
2860
2858
  var import_path13 = __toESM(require("path"));
2859
+ var import_ts_morph13 = require("ts-morph");
2860
+ var UNUSED_ENV_VARS = /* @__PURE__ */ new Set([
2861
+ "APPLICATION_CONFIG_URL",
2862
+ "FHIR_URL",
2863
+ "CONFIRM_REGISTRATION_URL"
2864
+ ]);
2865
+ var ENVIRONMENT_FILE_RELATIVE = "src/environment.ts";
2866
+ var CONSTANTS_FILE_RELATIVE = "src/constants.ts";
2867
+ function cleanEnvironmentFile(project, filePath) {
2868
+ const sourceFile = project.getSourceFile(filePath);
2869
+ if (!sourceFile) return [];
2870
+ const removed = [];
2871
+ const cleanEnvCall = sourceFile.getDescendantsOfKind(import_ts_morph13.SyntaxKind.CallExpression).find((call) => {
2872
+ const expr = call.getExpression();
2873
+ return import_ts_morph13.Node.isIdentifier(expr) && expr.getText() === "cleanEnv";
2874
+ });
2875
+ if (!cleanEnvCall) return removed;
2876
+ const schemaArg = cleanEnvCall.getArguments()[1]?.asKind(import_ts_morph13.SyntaxKind.ObjectLiteralExpression);
2877
+ if (!schemaArg) return removed;
2878
+ for (const name of UNUSED_ENV_VARS) {
2879
+ const prop = schemaArg.getProperty(name);
2880
+ if (!prop) continue;
2881
+ if (prop.isKind(import_ts_morph13.SyntaxKind.PropertyAssignment) || prop.isKind(import_ts_morph13.SyntaxKind.ShorthandPropertyAssignment)) {
2882
+ prop.remove();
2883
+ removed.push(name);
2884
+ }
2885
+ }
2886
+ return removed;
2887
+ }
2888
+ function extractEnvAccess(initText) {
2889
+ if (!initText) return null;
2890
+ const match = /\benv\.([A-Z][A-Z0-9_]*)\b/.exec(initText);
2891
+ return match ? match[1] : null;
2892
+ }
2893
+ function cleanConstantsFile(project, filePath) {
2894
+ const sourceFile = project.getSourceFile(filePath);
2895
+ if (!sourceFile) return [];
2896
+ const removed = [];
2897
+ for (const stmt of [...sourceFile.getVariableStatements()]) {
2898
+ const declarations = [...stmt.getDeclarations()];
2899
+ const declarationsToRemove = declarations.filter((decl) => {
2900
+ const name = decl.getName();
2901
+ const accessedEnvVar = extractEnvAccess(decl.getInitializer()?.getText());
2902
+ return UNUSED_ENV_VARS.has(name) || accessedEnvVar !== null && UNUSED_ENV_VARS.has(accessedEnvVar);
2903
+ });
2904
+ if (declarationsToRemove.length === 0) continue;
2905
+ const namesToRemove = declarationsToRemove.map((decl) => decl.getName());
2906
+ removed.push(...namesToRemove);
2907
+ if (declarationsToRemove.length === declarations.length) {
2908
+ stmt.remove();
2909
+ } else {
2910
+ for (const decl of declarationsToRemove) {
2911
+ decl.remove();
2912
+ }
2913
+ }
2914
+ }
2915
+ return removed;
2916
+ }
2917
+ async function main13() {
2918
+ const project = new import_ts_morph13.Project({
2919
+ tsConfigFilePath: import_path13.default.resolve(process.cwd(), "tsconfig.json"),
2920
+ skipAddingFilesFromTsConfig: false
2921
+ });
2922
+ console.log(
2923
+ `Removing unused environment variable(s) (${[...UNUSED_ENV_VARS].join(", ")})...
2924
+ `
2925
+ );
2926
+ const envFilePath = import_path13.default.join(process.cwd(), ENVIRONMENT_FILE_RELATIVE);
2927
+ const constsFilePath = import_path13.default.join(process.cwd(), CONSTANTS_FILE_RELATIVE);
2928
+ const envRemoved = cleanEnvironmentFile(project, envFilePath);
2929
+ if (envRemoved.length > 0) {
2930
+ await project.getSourceFileOrThrow(envFilePath).save();
2931
+ console.log(
2932
+ ` [${ENVIRONMENT_FILE_RELATIVE}] Removed schema entr${envRemoved.length === 1 ? "y" : "ies"}: ${envRemoved.join(", ")}`
2933
+ );
2934
+ } else if (project.getSourceFile(envFilePath)) {
2935
+ console.log(
2936
+ ` [${ENVIRONMENT_FILE_RELATIVE}] No matching schema entries \u2014 nothing to remove.`
2937
+ );
2938
+ } else {
2939
+ console.log(
2940
+ ` [${ENVIRONMENT_FILE_RELATIVE}] File not found \u2014 skipping.`
2941
+ );
2942
+ }
2943
+ const constsRemoved = cleanConstantsFile(project, constsFilePath);
2944
+ if (constsRemoved.length > 0) {
2945
+ await project.getSourceFileOrThrow(constsFilePath).save();
2946
+ console.log(
2947
+ ` [${CONSTANTS_FILE_RELATIVE}] Removed declaration(s): ${constsRemoved.join(", ")}`
2948
+ );
2949
+ } else if (project.getSourceFile(constsFilePath)) {
2950
+ console.log(
2951
+ ` [${CONSTANTS_FILE_RELATIVE}] No matching declarations \u2014 nothing to remove.`
2952
+ );
2953
+ } else {
2954
+ console.log(` [${CONSTANTS_FILE_RELATIVE}] File not found \u2014 skipping.`);
2955
+ }
2956
+ if (envRemoved.length === 0 && constsRemoved.length === 0) {
2957
+ console.log("\nNothing to do.");
2958
+ return;
2959
+ }
2960
+ console.log(
2961
+ `
2962
+ Done. NOTE: usages of these constants elsewhere in 'src/' may now produce TypeScript errors and need manual review.`
2963
+ );
2964
+ }
2965
+
2966
+ // src/migrations/v2.0/remove-fhir-url-helpers.ts
2967
+ var import_path14 = __toESM(require("path"));
2968
+ var import_ts_morph14 = require("ts-morph");
2969
+ var FHIR_IMPORT = "FHIR_URL";
2970
+ var HELPER_NAMES = /* @__PURE__ */ new Set([
2971
+ "getFromFhir",
2972
+ "updateResourceFromHearth",
2973
+ "updateResourceInHearth"
2974
+ ]);
2975
+ function removeHelpers(sourceFilePath, project) {
2976
+ const sourceFile = project.getSourceFile(sourceFilePath);
2977
+ if (!sourceFile) {
2978
+ return {
2979
+ removedHelpers: [],
2980
+ removedImportCount: 0,
2981
+ remainingFhirReferences: 0
2982
+ };
2983
+ }
2984
+ const removedHelpers = [];
2985
+ let removedImportCount = 0;
2986
+ for (const fn of sourceFile.getFunctions()) {
2987
+ const name = fn.getName();
2988
+ if (!name || !HELPER_NAMES.has(name)) continue;
2989
+ removedHelpers.push(name);
2990
+ fn.remove();
2991
+ }
2992
+ for (const stmt of [...sourceFile.getVariableStatements()]) {
2993
+ const declarations = [...stmt.getDeclarations()];
2994
+ const toRemove = declarations.filter((decl) => HELPER_NAMES.has(decl.getName()));
2995
+ if (toRemove.length === 0) continue;
2996
+ removedHelpers.push(...toRemove.map((decl) => decl.getName()));
2997
+ if (toRemove.length === declarations.length) {
2998
+ stmt.remove();
2999
+ } else {
3000
+ for (const decl of toRemove) decl.remove();
3001
+ }
3002
+ }
3003
+ for (const decl of sourceFile.getImportDeclarations()) {
3004
+ const matches = decl.getNamedImports().filter((ni) => ni.getName() === FHIR_IMPORT);
3005
+ if (matches.length === 0) continue;
3006
+ for (const named of matches) {
3007
+ named.remove();
3008
+ removedImportCount++;
3009
+ }
3010
+ const hasAnyNamedImportsLeft = decl.getNamedImports().length > 0;
3011
+ const hasDefaultImport = !!decl.getDefaultImport();
3012
+ const hasNamespaceImport = !!decl.getNamespaceImport();
3013
+ if (!hasAnyNamedImportsLeft && !hasDefaultImport && !hasNamespaceImport) {
3014
+ decl.remove();
3015
+ }
3016
+ }
3017
+ const remainingFhirReferences = sourceFile.getDescendantsOfKind(import_ts_morph14.SyntaxKind.Identifier).filter((id) => id.getText() === FHIR_IMPORT).filter((id) => !id.getFirstAncestorByKind(import_ts_morph14.SyntaxKind.ImportDeclaration)).length;
3018
+ return { removedHelpers, removedImportCount, remainingFhirReferences };
3019
+ }
3020
+ async function main14() {
3021
+ const project = new import_ts_morph14.Project({
3022
+ tsConfigFilePath: import_path14.default.resolve(process.cwd(), "tsconfig.json"),
3023
+ skipAddingFilesFromTsConfig: false
3024
+ });
3025
+ const sourceFiles = project.getSourceFiles().filter((sf) => {
3026
+ const fp = sf.getFilePath();
3027
+ return fp.includes("/src/") && !fp.includes("/node_modules/");
3028
+ });
3029
+ console.log(`Removing legacy FHIR_URL helpers in ${sourceFiles.length} source file(s)...
3030
+ `);
3031
+ let totalRemovedImports = 0;
3032
+ let totalRemovedHelpers = 0;
3033
+ const modifiedFiles = [];
3034
+ const warnings = [];
3035
+ for (const sourceFile of sourceFiles) {
3036
+ const filePath = sourceFile.getFilePath();
3037
+ const rel = import_path14.default.relative(process.cwd(), filePath);
3038
+ const result = removeHelpers(filePath, project);
3039
+ const changed = result.removedImportCount > 0 || result.removedHelpers.length > 0;
3040
+ if (changed) {
3041
+ modifiedFiles.push(filePath);
3042
+ totalRemovedImports += result.removedImportCount;
3043
+ totalRemovedHelpers += result.removedHelpers.length;
3044
+ if (result.removedHelpers.length > 0) {
3045
+ console.log(
3046
+ ` [${rel}] Removed helper(s): ${result.removedHelpers.join(", ")}`
3047
+ );
3048
+ }
3049
+ if (result.removedImportCount > 0) {
3050
+ console.log(
3051
+ ` [${rel}] Removed ${result.removedImportCount} '${FHIR_IMPORT}' import(s)`
3052
+ );
3053
+ }
3054
+ }
3055
+ if (result.remainingFhirReferences > 0) {
3056
+ warnings.push(
3057
+ `${rel}: ${result.remainingFhirReferences} remaining '${FHIR_IMPORT}' reference(s)`
3058
+ );
3059
+ }
3060
+ }
3061
+ if (modifiedFiles.length === 0 && warnings.length === 0) {
3062
+ console.log("No FHIR_URL imports/helpers found. Nothing to do.");
3063
+ return;
3064
+ }
3065
+ if (modifiedFiles.length > 0) {
3066
+ console.log(`
3067
+ Saving ${modifiedFiles.length} modified file(s)...`);
3068
+ for (const filePath of modifiedFiles) {
3069
+ await project.getSourceFileOrThrow(filePath).save();
3070
+ console.log(` Saved: ${import_path14.default.relative(process.cwd(), filePath)}`);
3071
+ }
3072
+ }
3073
+ if (warnings.length > 0) {
3074
+ console.warn(
3075
+ `
3076
+ WARNING: Some '${FHIR_IMPORT}' usages remain and need manual cleanup:
3077
+ ` + warnings.map((line) => ` - ${line}`).join("\n")
3078
+ );
3079
+ }
3080
+ console.log(
3081
+ `
3082
+ Done. Removed ${totalRemovedHelpers} helper declaration(s) and ${totalRemovedImports} '${FHIR_IMPORT}' import(s).`
3083
+ );
3084
+ }
3085
+
3086
+ // src/migrations/v2.0/migrate-application-config-url.ts
3087
+ var import_path15 = __toESM(require("path"));
3088
+ var import_ts_morph15 = require("ts-morph");
3089
+ var TARGET_IDENTIFIER = "APPLICATION_CONFIG_URL";
3090
+ var REPLACEMENT_IDENTIFIER = "applicationConfig";
3091
+ var REPLACEMENT_MODULE = "@countryconfig/api/application/application-config";
3092
+ var FUNCTION_LIKE_KINDS = [
3093
+ import_ts_morph15.SyntaxKind.FunctionDeclaration,
3094
+ import_ts_morph15.SyntaxKind.FunctionExpression,
3095
+ import_ts_morph15.SyntaxKind.ArrowFunction,
3096
+ import_ts_morph15.SyntaxKind.MethodDeclaration
3097
+ ];
3098
+ function describeFunction(node) {
3099
+ if (import_ts_morph15.Node.isFunctionDeclaration(node) || import_ts_morph15.Node.isMethodDeclaration(node)) {
3100
+ return node.getName() ?? "<anonymous>";
3101
+ }
3102
+ const parent = node.getParent();
3103
+ if (parent && import_ts_morph15.Node.isVariableDeclaration(parent)) {
3104
+ return parent.getName();
3105
+ }
3106
+ if (parent && import_ts_morph15.Node.isPropertyAssignment(parent)) {
3107
+ return parent.getName();
3108
+ }
3109
+ if (import_ts_morph15.Node.isFunctionExpression(node) && node.getNameNode() !== void 0) {
3110
+ return node.getNameNode()?.getText() ?? "<anonymous>";
3111
+ }
3112
+ return "<anonymous>";
3113
+ }
3114
+ function hasBlockBody(node) {
3115
+ if (import_ts_morph15.Node.isFunctionDeclaration(node) || import_ts_morph15.Node.isFunctionExpression(node) || import_ts_morph15.Node.isMethodDeclaration(node)) {
3116
+ return node.getBody() !== void 0;
3117
+ }
3118
+ if (import_ts_morph15.Node.isArrowFunction(node)) {
3119
+ return node.getBody().getKind() === import_ts_morph15.SyntaxKind.Block;
3120
+ }
3121
+ return false;
3122
+ }
3123
+ function isConfigFetcher(node) {
3124
+ let referencesTarget = false;
3125
+ let callsFetch = false;
3126
+ for (const id of node.getDescendantsOfKind(import_ts_morph15.SyntaxKind.Identifier)) {
3127
+ const text = id.getText();
3128
+ if (!referencesTarget && text === TARGET_IDENTIFIER) referencesTarget = true;
3129
+ if (!callsFetch && text === "fetch") {
3130
+ const parent = id.getParent();
3131
+ if (import_ts_morph15.Node.isCallExpression(parent) && parent.getExpression() === id) {
3132
+ callsFetch = true;
3133
+ }
3134
+ }
3135
+ if (referencesTarget && callsFetch) return true;
3136
+ }
3137
+ return false;
3138
+ }
3139
+ function processFile11(sourceFile) {
3140
+ const importsWithTarget = sourceFile.getImportDeclarations().filter(
3141
+ (decl) => decl.getNamedImports().some((ni) => ni.getName() === TARGET_IDENTIFIER)
3142
+ );
3143
+ if (importsWithTarget.length === 0) {
3144
+ return { changed: false, rewrittenFunctions: [], renamedReferences: 0 };
3145
+ }
3146
+ const collidingLocals = sourceFile.getDescendantsOfKind(import_ts_morph15.SyntaxKind.Identifier).filter((id) => id.getText() === REPLACEMENT_IDENTIFIER).filter((id) => {
3147
+ const parent = id.getParent();
3148
+ const kind = parent.getKind();
3149
+ return kind === import_ts_morph15.SyntaxKind.VariableDeclaration || kind === import_ts_morph15.SyntaxKind.FunctionDeclaration || kind === import_ts_morph15.SyntaxKind.ClassDeclaration || kind === import_ts_morph15.SyntaxKind.Parameter;
3150
+ });
3151
+ if (collidingLocals.length > 0) {
3152
+ return {
3153
+ changed: false,
3154
+ rewrittenFunctions: [],
3155
+ renamedReferences: 0,
3156
+ skippedReason: `local declaration named '${REPLACEMENT_IDENTIFIER}' would collide`
3157
+ };
3158
+ }
3159
+ const candidateFunctions = FUNCTION_LIKE_KINDS.flatMap(
3160
+ (kind) => sourceFile.getDescendantsOfKind(kind)
3161
+ );
3162
+ candidateFunctions.sort((a, b) => a.getStart() - b.getStart());
3163
+ const rewrittenFunctions = [];
3164
+ const rewrittenSet = /* @__PURE__ */ new Set();
3165
+ for (const fn of candidateFunctions) {
3166
+ if (!hasBlockBody(fn)) continue;
3167
+ if (!isConfigFetcher(fn)) continue;
3168
+ let inRewrittenAncestor = false;
3169
+ let cursor = fn.getParent();
3170
+ while (cursor) {
3171
+ if (rewrittenSet.has(cursor)) {
3172
+ inRewrittenAncestor = true;
3173
+ break;
3174
+ }
3175
+ cursor = cursor.getParent();
3176
+ }
3177
+ if (inRewrittenAncestor) continue;
3178
+ const start = fn.getStart();
3179
+ const line = sourceFile.getLineAndColumnAtPos(start).line;
3180
+ const name = describeFunction(fn);
3181
+ if (import_ts_morph15.Node.isFunctionDeclaration(fn) || import_ts_morph15.Node.isFunctionExpression(fn) || import_ts_morph15.Node.isMethodDeclaration(fn) || import_ts_morph15.Node.isArrowFunction(fn)) {
3182
+ fn.setBodyText(`return ${REPLACEMENT_IDENTIFIER}`);
3183
+ }
3184
+ rewrittenFunctions.push({ name, line });
3185
+ rewrittenSet.add(fn);
3186
+ }
3187
+ for (const decl of importsWithTarget) {
3188
+ const targetNamed = decl.getNamedImports().find((ni) => ni.getName() === TARGET_IDENTIFIER);
3189
+ targetNamed?.remove();
3190
+ const isNowEmpty = decl.getNamedImports().length === 0 && !decl.getDefaultImport() && !decl.getNamespaceImport();
3191
+ if (isNowEmpty) decl.remove();
3192
+ }
3193
+ const existing = sourceFile.getImportDeclaration(
3194
+ (decl) => decl.getModuleSpecifierValue() === REPLACEMENT_MODULE
3195
+ );
3196
+ if (existing) {
3197
+ const alreadyImported = existing.getNamedImports().some((ni) => ni.getName() === REPLACEMENT_IDENTIFIER);
3198
+ if (!alreadyImported) existing.addNamedImport(REPLACEMENT_IDENTIFIER);
3199
+ } else {
3200
+ sourceFile.addImportDeclaration({
3201
+ moduleSpecifier: REPLACEMENT_MODULE,
3202
+ namedImports: [REPLACEMENT_IDENTIFIER]
3203
+ });
3204
+ }
3205
+ const renameTargets = sourceFile.getDescendantsOfKind(import_ts_morph15.SyntaxKind.Identifier).filter((id) => id.getText() === TARGET_IDENTIFIER).filter((id) => !id.getFirstAncestorByKind(import_ts_morph15.SyntaxKind.ImportDeclaration)).filter((id) => {
3206
+ const parent = id.getParent();
3207
+ const parentKind = parent.getKind();
3208
+ if (parentKind === import_ts_morph15.SyntaxKind.PropertyAccessExpression) {
3209
+ const pae = parent.asKind(import_ts_morph15.SyntaxKind.PropertyAccessExpression);
3210
+ if (pae.getNameNode() === id) return false;
3211
+ }
3212
+ if (parentKind === import_ts_morph15.SyntaxKind.PropertyAssignment) {
3213
+ const pa = parent.asKind(import_ts_morph15.SyntaxKind.PropertyAssignment);
3214
+ if (pa.getNameNode() === id) return false;
3215
+ }
3216
+ if (parentKind === import_ts_morph15.SyntaxKind.ShorthandPropertyAssignment) {
3217
+ return false;
3218
+ }
3219
+ return true;
3220
+ }).sort((a, b) => b.getPos() - a.getPos());
3221
+ for (const id of renameTargets) {
3222
+ id.replaceWithText(REPLACEMENT_IDENTIFIER);
3223
+ }
3224
+ return {
3225
+ changed: true,
3226
+ rewrittenFunctions,
3227
+ renamedReferences: renameTargets.length
3228
+ };
3229
+ }
3230
+ async function main15() {
3231
+ const project = new import_ts_morph15.Project({
3232
+ tsConfigFilePath: import_path15.default.resolve(process.cwd(), "tsconfig.json"),
3233
+ skipAddingFilesFromTsConfig: false
3234
+ });
3235
+ const sourceFiles = project.getSourceFiles().filter((sf) => {
3236
+ const fp = sf.getFilePath();
3237
+ return fp.includes("/src/") && !fp.includes("/node_modules/");
3238
+ });
3239
+ console.log(
3240
+ `Migrating '${TARGET_IDENTIFIER}' \u2192 '${REPLACEMENT_IDENTIFIER}' across ${sourceFiles.length} source file(s)...
3241
+ `
3242
+ );
3243
+ let changedFiles = 0;
3244
+ let totalRewrittenFunctions = 0;
3245
+ let totalRenamedReferences = 0;
3246
+ const skipped = [];
3247
+ for (const sourceFile of sourceFiles) {
3248
+ const filePath = sourceFile.getFilePath();
3249
+ const rel = import_path15.default.relative(process.cwd(), filePath);
3250
+ const result = processFile11(sourceFile);
3251
+ if (result.skippedReason) {
3252
+ skipped.push(`${rel} (${result.skippedReason})`);
3253
+ continue;
3254
+ }
3255
+ if (!result.changed) continue;
3256
+ await sourceFile.save();
3257
+ changedFiles++;
3258
+ totalRewrittenFunctions += result.rewrittenFunctions.length;
3259
+ totalRenamedReferences += result.renamedReferences;
3260
+ for (const fn of result.rewrittenFunctions) {
3261
+ console.log(
3262
+ ` [${rel}:${fn.line}] Rewrote '${fn.name}' body \u2192 'return ${REPLACEMENT_IDENTIFIER}' (config fetch eliminated)`
3263
+ );
3264
+ }
3265
+ if (result.renamedReferences > 0) {
3266
+ console.log(
3267
+ ` [${rel}] Renamed ${result.renamedReferences} stray reference(s) ${TARGET_IDENTIFIER} \u2192 ${REPLACEMENT_IDENTIFIER}`
3268
+ );
3269
+ }
3270
+ }
3271
+ if (skipped.length > 0) {
3272
+ console.warn(
3273
+ `
3274
+ ${skipped.length} file(s) skipped:
3275
+ ` + skipped.map((s) => ` - ${s}`).join("\n")
3276
+ );
3277
+ }
3278
+ if (changedFiles === 0) {
3279
+ console.log(`
3280
+ No files reference '${TARGET_IDENTIFIER}'. Nothing to do.`);
3281
+ return;
3282
+ }
3283
+ console.log(
3284
+ `
3285
+ Done. Updated ${changedFiles} file(s): ${totalRewrittenFunctions} fetch function(s) rewritten, ${totalRenamedReferences} bare reference(s) renamed.`
3286
+ );
3287
+ if (totalRewrittenFunctions > 0) {
3288
+ console.log(
3289
+ `NOTE: rewriting fetch functions discards any custom logic that lived inside them. Review the diff and re-apply any country-specific adjustments on top of '${REPLACEMENT_IDENTIFIER}'.`
3290
+ );
3291
+ }
3292
+ }
3293
+
3294
+ // src/migrations/v2.0/remove-old-statistics-service.ts
3295
+ var import_path16 = __toESM(require("path"));
3296
+ var import_ts_morph16 = require("ts-morph");
3297
+ var ROUTE_PATH = "/statistics";
3298
+ var HANDLER_NAME = "statisticsHandler";
3299
+ function isStatisticsRouteObject(obj) {
3300
+ const pathProp = obj.getProperty("path");
3301
+ if (!pathProp || !import_ts_morph16.Node.isPropertyAssignment(pathProp)) return false;
3302
+ const init = pathProp.getInitializer();
3303
+ if (!init) return false;
3304
+ if (import_ts_morph16.Node.isStringLiteral(init) || import_ts_morph16.Node.isNoSubstitutionTemplateLiteral(init)) {
3305
+ return init.getLiteralValue() === ROUTE_PATH;
3306
+ }
3307
+ return false;
3308
+ }
3309
+ function removeStatisticsRoutes(sourceFile) {
3310
+ let removed = 0;
3311
+ const callExpressions = [
3312
+ ...sourceFile.getDescendantsOfKind(import_ts_morph16.SyntaxKind.CallExpression)
3313
+ ];
3314
+ for (const call of callExpressions) {
3315
+ if (call.wasForgotten()) continue;
3316
+ const expr = call.getExpression();
3317
+ if (!import_ts_morph16.Node.isPropertyAccessExpression(expr)) continue;
3318
+ if (expr.getName() !== "route") continue;
3319
+ const args = call.getArguments();
3320
+ if (args.length === 0) continue;
3321
+ const firstArg = args[0];
3322
+ if (import_ts_morph16.Node.isObjectLiteralExpression(firstArg)) {
3323
+ if (!isStatisticsRouteObject(firstArg)) continue;
3324
+ const stmt = call.getFirstAncestorByKind(import_ts_morph16.SyntaxKind.ExpressionStatement);
3325
+ if (stmt) {
3326
+ stmt.remove();
3327
+ removed++;
3328
+ } else {
3329
+ call.replaceWithText("");
3330
+ removed++;
3331
+ }
3332
+ continue;
3333
+ }
3334
+ if (import_ts_morph16.Node.isArrayLiteralExpression(firstArg)) {
3335
+ const matchingIndexes = firstArg.getElements().map((el, idx) => ({ el, idx })).filter(
3336
+ ({ el }) => import_ts_morph16.Node.isObjectLiteralExpression(el) && isStatisticsRouteObject(el)
3337
+ ).map(({ idx }) => idx);
3338
+ matchingIndexes.sort((a, b) => b - a).forEach((idx) => {
3339
+ firstArg.removeElement(idx);
3340
+ removed++;
3341
+ });
3342
+ }
3343
+ }
3344
+ return removed;
3345
+ }
3346
+ function removeStatisticsHandlerImports(sourceFile) {
3347
+ let changed = false;
3348
+ for (const decl of sourceFile.getImportDeclarations()) {
3349
+ const targetNamed = decl.getNamedImports().find((ni) => ni.getName() === HANDLER_NAME);
3350
+ if (!targetNamed) continue;
3351
+ targetNamed.remove();
3352
+ changed = true;
3353
+ const isNowEmpty = decl.getNamedImports().length === 0 && !decl.getDefaultImport() && !decl.getNamespaceImport();
3354
+ if (isNowEmpty) decl.remove();
3355
+ }
3356
+ return changed;
3357
+ }
3358
+ function processFile12(sourceFile) {
3359
+ const routesRemoved = removeStatisticsRoutes(sourceFile);
3360
+ const importsCleaned = removeStatisticsHandlerImports(sourceFile);
3361
+ return { routesRemoved, importsCleaned };
3362
+ }
3363
+ function collectLocalImportsInSubtree(sourceFile, subtreeRoot) {
3364
+ const result = [];
3365
+ for (const decl of sourceFile.getImportDeclarations()) {
3366
+ const moduleSf = decl.getModuleSpecifierSourceFile();
3367
+ if (!moduleSf) continue;
3368
+ const fp = moduleSf.getFilePath();
3369
+ if (!fp.startsWith(subtreeRoot)) continue;
3370
+ result.push(fp);
3371
+ }
3372
+ return result;
3373
+ }
3374
+ function deleteOrphanedDescendants(project, startingFile, subtreeRoot) {
3375
+ const initialCandidates = collectLocalImportsInSubtree(
3376
+ startingFile,
3377
+ subtreeRoot
3378
+ );
3379
+ const startingPath = startingFile.getFilePath();
3380
+ const deleted = /* @__PURE__ */ new Set([startingPath]);
3381
+ const seen = /* @__PURE__ */ new Set();
3382
+ const worklist = [...initialCandidates];
3383
+ const orphans = [];
3384
+ while (worklist.length > 0) {
3385
+ const candidate = worklist.shift();
3386
+ if (seen.has(candidate)) continue;
3387
+ seen.add(candidate);
3388
+ if (deleted.has(candidate)) continue;
3389
+ if (!candidate.startsWith(subtreeRoot)) continue;
3390
+ const candidateSf = project.getSourceFile(candidate);
3391
+ if (!candidateSf) continue;
3392
+ const stillImported = project.getSourceFiles().some((sf) => {
3393
+ const sfPath = sf.getFilePath();
3394
+ if (deleted.has(sfPath)) return false;
3395
+ if (sfPath === candidate) return false;
3396
+ return sf.getImportDeclarations().some(
3397
+ (decl) => decl.getModuleSpecifierSourceFile()?.getFilePath() === candidate
3398
+ );
3399
+ });
3400
+ if (stillImported) continue;
3401
+ const next = collectLocalImportsInSubtree(candidateSf, subtreeRoot);
3402
+ worklist.push(...next);
3403
+ candidateSf.delete();
3404
+ deleted.add(candidate);
3405
+ orphans.push(candidate);
3406
+ }
3407
+ return orphans;
3408
+ }
3409
+ function processHandlerFile(project) {
3410
+ const sourceFiles = project.getSourceFiles().filter((sf) => {
3411
+ const fp = sf.getFilePath();
3412
+ return fp.includes("/src/") && !fp.includes("/node_modules/");
3413
+ });
3414
+ for (const sf of sourceFiles) {
3415
+ const fn = sf.getFunction(HANDLER_NAME);
3416
+ if (!fn) continue;
3417
+ const filePath = sf.getFilePath();
3418
+ const exportsByName = [...sf.getExportedDeclarations().keys()];
3419
+ const otherExports = exportsByName.filter((name) => name !== HANDLER_NAME);
3420
+ if (otherExports.length === 0) {
3421
+ const subtreeRoot = import_path16.default.dirname(filePath) + import_path16.default.sep;
3422
+ const orphansDeleted = deleteOrphanedDescendants(
3423
+ project,
3424
+ sf,
3425
+ subtreeRoot
3426
+ );
3427
+ sf.delete();
3428
+ return { filePath, action: "deleted", orphansDeleted };
3429
+ }
3430
+ fn.remove();
3431
+ return {
3432
+ filePath,
3433
+ action: "function-removed",
3434
+ remainingExports: otherExports,
3435
+ orphansDeleted: []
3436
+ };
3437
+ }
3438
+ return { filePath: "", action: "not-found", orphansDeleted: [] };
3439
+ }
3440
+ async function main16() {
3441
+ const project = new import_ts_morph16.Project({
3442
+ tsConfigFilePath: import_path16.default.resolve(process.cwd(), "tsconfig.json"),
3443
+ skipAddingFilesFromTsConfig: false
3444
+ });
3445
+ const sourceFiles = project.getSourceFiles().filter((sf) => {
3446
+ const fp = sf.getFilePath();
3447
+ return fp.includes("/src/") && !fp.includes("/node_modules/");
3448
+ });
3449
+ console.log(
3450
+ `Removing legacy 'GET ${ROUTE_PATH}' route and '${HANDLER_NAME}' across ${sourceFiles.length} source file(s)...
3451
+ `
3452
+ );
3453
+ let totalRoutesRemoved = 0;
3454
+ let totalFilesWithImportsCleaned = 0;
3455
+ let totalFilesWithRoutesRemoved = 0;
3456
+ for (const sourceFile of sourceFiles) {
3457
+ const filePath = sourceFile.getFilePath();
3458
+ const rel = import_path16.default.relative(process.cwd(), filePath);
3459
+ const result = processFile12(sourceFile);
3460
+ if (result.routesRemoved > 0) {
3461
+ console.log(
3462
+ ` [${rel}] Removed ${result.routesRemoved} '${ROUTE_PATH}' route(s)`
3463
+ );
3464
+ totalRoutesRemoved += result.routesRemoved;
3465
+ totalFilesWithRoutesRemoved++;
3466
+ }
3467
+ if (result.importsCleaned) {
3468
+ console.log(` [${rel}] Cleaned up '${HANDLER_NAME}' import`);
3469
+ totalFilesWithImportsCleaned++;
3470
+ }
3471
+ if (result.routesRemoved > 0 || result.importsCleaned) {
3472
+ await sourceFile.save();
3473
+ }
3474
+ }
3475
+ const handlerResult = processHandlerFile(project);
3476
+ switch (handlerResult.action) {
3477
+ case "deleted": {
3478
+ const rel = import_path16.default.relative(process.cwd(), handlerResult.filePath);
3479
+ console.log(
3480
+ ` [${rel}] Deleted handler file ('${HANDLER_NAME}' was the sole export).`
3481
+ );
3482
+ for (const orphanPath of handlerResult.orphansDeleted) {
3483
+ const orphanRel = import_path16.default.relative(process.cwd(), orphanPath);
3484
+ console.log(
3485
+ ` [${orphanRel}] Deleted (no remaining importers in the project after handler removal).`
3486
+ );
3487
+ }
3488
+ await project.save();
3489
+ break;
3490
+ }
3491
+ case "function-removed": {
3492
+ const rel = import_path16.default.relative(process.cwd(), handlerResult.filePath);
3493
+ console.warn(
3494
+ ` [${rel}] Removed '${HANDLER_NAME}' function but kept the file (other exports remain: ${handlerResult.remainingExports?.join(", ")}). Review whether the file is still needed.`
3495
+ );
3496
+ const sf = project.getSourceFile(handlerResult.filePath);
3497
+ if (sf) await sf.save();
3498
+ break;
3499
+ }
3500
+ case "not-found":
3501
+ break;
3502
+ }
3503
+ if (totalRoutesRemoved === 0 && totalFilesWithImportsCleaned === 0 && handlerResult.action === "not-found") {
3504
+ console.log(`
3505
+ No legacy '${ROUTE_PATH}' route or handler found. Nothing to do.`);
3506
+ return;
3507
+ }
3508
+ const orphansSummary = handlerResult.orphansDeleted.length > 0 ? ` and ${handlerResult.orphansDeleted.length} orphaned helper file(s)` : "";
3509
+ console.log(
3510
+ `
3511
+ Done. Removed ${totalRoutesRemoved} route(s) across ${totalFilesWithRoutesRemoved} file(s); cleaned ${HANDLER_NAME} import in ${totalFilesWithImportsCleaned} file(s)${orphansSummary}.`
3512
+ );
3513
+ }
3514
+
3515
+ // src/migrations/v2.0/update-package-json.ts
3516
+ var import_fs = require("fs");
3517
+ var import_path17 = __toESM(require("path"));
3518
+ var PACKAGE_JSON_RELATIVE = "package.json";
3519
+ var TARGET_VERSION = "2.0.0";
3520
+ var TARGET_ZOD_RANGE = "^4.2.1";
3521
+ async function main17() {
3522
+ const packageJsonPath = import_path17.default.join(process.cwd(), PACKAGE_JSON_RELATIVE);
3523
+ if (!(0, import_fs.existsSync)(packageJsonPath)) {
3524
+ console.log(`'${PACKAGE_JSON_RELATIVE}' not found in ${process.cwd()} \u2014 skipping.`);
3525
+ return;
3526
+ }
3527
+ const raw = (0, import_fs.readFileSync)(packageJsonPath, "utf8");
3528
+ let parsed;
3529
+ try {
3530
+ parsed = JSON.parse(raw);
3531
+ } catch (error) {
3532
+ console.warn(
3533
+ ` [${PACKAGE_JSON_RELATIVE}] Failed to parse JSON \u2014 skipping update. ${error.message}`
3534
+ );
3535
+ return;
3536
+ }
3537
+ console.log(`Updating '${PACKAGE_JSON_RELATIVE}'...`);
3538
+ const previousVersion = parsed.version;
3539
+ const versionChanged = previousVersion !== TARGET_VERSION;
3540
+ parsed.version = TARGET_VERSION;
3541
+ if (versionChanged) {
3542
+ console.log(
3543
+ ` Set version: ${previousVersion ?? "<unset>"} \u2192 ${TARGET_VERSION}`
3544
+ );
3545
+ } else {
3546
+ console.log(` Version already ${TARGET_VERSION} \u2014 no change.`);
3547
+ }
3548
+ let zodBucket = "dependencies";
3549
+ if (parsed.devDependencies && "zod" in parsed.devDependencies) {
3550
+ zodBucket = "devDependencies";
3551
+ }
3552
+ if (!parsed[zodBucket]) {
3553
+ parsed[zodBucket] = {};
3554
+ }
3555
+ const bucket = parsed[zodBucket];
3556
+ const previousZod = bucket.zod;
3557
+ const zodChanged = previousZod !== TARGET_ZOD_RANGE;
3558
+ bucket.zod = TARGET_ZOD_RANGE;
3559
+ if (zodChanged) {
3560
+ console.log(
3561
+ ` Set ${zodBucket}.zod: ${previousZod ?? "<absent>"} \u2192 ${TARGET_ZOD_RANGE}`
3562
+ );
3563
+ } else {
3564
+ console.log(` ${zodBucket}.zod already ${TARGET_ZOD_RANGE} \u2014 no change.`);
3565
+ }
3566
+ const trailingNewline = raw.endsWith("\n") ? "\n" : "";
3567
+ const next = JSON.stringify(parsed, null, 2) + trailingNewline;
3568
+ if (next === raw) {
3569
+ console.log("\n No changes to write.");
3570
+ return;
3571
+ }
3572
+ (0, import_fs.writeFileSync)(packageJsonPath, next, "utf8");
3573
+ console.log(`
3574
+ Saved '${PACKAGE_JSON_RELATIVE}'.`);
3575
+ console.log(
3576
+ ` NOTE: run \`yarn install\` (or your package manager equivalent) to install the updated dependency versions.`
3577
+ );
3578
+ }
3579
+
3580
+ // src/migrations/v2.0/migrate-workqueue-configs.ts
3581
+ var import_ts_morph17 = require("ts-morph");
3582
+ var import_path18 = __toESM(require("path"));
2861
3583
  var DEFINE_WORKQUEUES_NAME3 = "defineWorkqueues";
2862
3584
  var ACTIONS_PROPERTY_NAME5 = "actions";
2863
3585
  var ACTION_PROPERTY_NAME2 = "action";
@@ -2878,28 +3600,28 @@ var SUPPORTED_WORKQUEUE_ACTION_TYPES = /* @__PURE__ */ new Set([
2878
3600
  ]);
2879
3601
  function getWorkqueueLabel(workqueue) {
2880
3602
  const slugProperty = workqueue.getProperty(SLUG_PROPERTY_NAME);
2881
- if (!slugProperty || !import_ts_morph13.Node.isPropertyAssignment(slugProperty)) {
3603
+ if (!slugProperty || !import_ts_morph17.Node.isPropertyAssignment(slugProperty)) {
2882
3604
  return "(unknown slug)";
2883
3605
  }
2884
3606
  const slugInitializer = slugProperty.getInitializer();
2885
- if (!slugInitializer || !import_ts_morph13.Node.isStringLiteral(slugInitializer)) {
3607
+ if (!slugInitializer || !import_ts_morph17.Node.isStringLiteral(slugInitializer)) {
2886
3608
  return "(unknown slug)";
2887
3609
  }
2888
3610
  return slugInitializer.getLiteralValue();
2889
3611
  }
2890
3612
  function getActionTypeName(action) {
2891
3613
  const typeProperty = action.getProperty(TYPE_PROPERTY_NAME7);
2892
- if (!typeProperty || !import_ts_morph13.Node.isPropertyAssignment(typeProperty)) {
3614
+ if (!typeProperty || !import_ts_morph17.Node.isPropertyAssignment(typeProperty)) {
2893
3615
  return null;
2894
3616
  }
2895
3617
  const typeInitializer = typeProperty.getInitializer();
2896
3618
  if (!typeInitializer) {
2897
3619
  return null;
2898
3620
  }
2899
- if (import_ts_morph13.Node.isStringLiteral(typeInitializer)) {
3621
+ if (import_ts_morph17.Node.isStringLiteral(typeInitializer)) {
2900
3622
  return typeInitializer.getLiteralValue();
2901
3623
  }
2902
- if (import_ts_morph13.Node.isPropertyAccessExpression(typeInitializer)) {
3624
+ if (import_ts_morph17.Node.isPropertyAccessExpression(typeInitializer)) {
2903
3625
  return typeInitializer.getName();
2904
3626
  }
2905
3627
  return null;
@@ -2913,19 +3635,19 @@ function isUnsupportedActionType(action) {
2913
3635
  }
2914
3636
  function migrateWorkqueueActions(workqueue, relPath) {
2915
3637
  const actionsProperty = workqueue.getProperty(ACTIONS_PROPERTY_NAME5);
2916
- if (!actionsProperty || !import_ts_morph13.Node.isPropertyAssignment(actionsProperty)) {
3638
+ if (!actionsProperty || !import_ts_morph17.Node.isPropertyAssignment(actionsProperty)) {
2917
3639
  return 0;
2918
3640
  }
2919
3641
  const actionsInitializer = actionsProperty.getInitializer();
2920
- if (!actionsInitializer || !import_ts_morph13.Node.isArrayLiteralExpression(actionsInitializer)) {
3642
+ if (!actionsInitializer || !import_ts_morph17.Node.isArrayLiteralExpression(actionsInitializer)) {
2921
3643
  return 0;
2922
3644
  }
2923
3645
  const workqueueLabel = getWorkqueueLabel(workqueue);
2924
3646
  const existingActionProperty = workqueue.getProperty(ACTION_PROPERTY_NAME2);
2925
3647
  if (existingActionProperty) {
2926
- if (import_ts_morph13.Node.isPropertyAssignment(existingActionProperty)) {
3648
+ if (import_ts_morph17.Node.isPropertyAssignment(existingActionProperty)) {
2927
3649
  const existingActionInitializer = existingActionProperty.getInitializer();
2928
- if (existingActionInitializer && import_ts_morph13.Node.isObjectLiteralExpression(existingActionInitializer)) {
3650
+ if (existingActionInitializer && import_ts_morph17.Node.isObjectLiteralExpression(existingActionInitializer)) {
2929
3651
  const conditionalsProperty2 = existingActionInitializer.getProperty(
2930
3652
  CONDITIONALS_PROPERTY_NAME
2931
3653
  );
@@ -2950,7 +3672,7 @@ function migrateWorkqueueActions(workqueue, relPath) {
2950
3672
  return 1;
2951
3673
  }
2952
3674
  const actionCandidates = actionsInitializer.getElements().filter(
2953
- (element) => import_ts_morph13.Node.isObjectLiteralExpression(element)
3675
+ (element) => import_ts_morph17.Node.isObjectLiteralExpression(element)
2954
3676
  );
2955
3677
  if (actionCandidates.length === 0) {
2956
3678
  actionsProperty.remove();
@@ -2992,36 +3714,36 @@ function migrateWorkqueueActions(workqueue, relPath) {
2992
3714
  );
2993
3715
  return 1;
2994
3716
  }
2995
- function processFile11(filePath, project) {
3717
+ function processFile13(filePath, project) {
2996
3718
  const sourceFile = project.getSourceFile(filePath);
2997
3719
  if (!sourceFile) return 0;
2998
3720
  let migratedWorkqueues = 0;
2999
- const relPath = import_path13.default.relative(getCwd(), filePath);
3721
+ const relPath = import_path18.default.relative(process.cwd(), filePath);
3000
3722
  const callExpressions = sourceFile.getDescendantsOfKind(
3001
- import_ts_morph13.SyntaxKind.CallExpression
3723
+ import_ts_morph17.SyntaxKind.CallExpression
3002
3724
  );
3003
3725
  for (const call of callExpressions) {
3004
3726
  const expression = call.getExpression();
3005
- if (!import_ts_morph13.Node.isIdentifier(expression) || expression.getText() !== DEFINE_WORKQUEUES_NAME3) {
3727
+ if (!import_ts_morph17.Node.isIdentifier(expression) || expression.getText() !== DEFINE_WORKQUEUES_NAME3) {
3006
3728
  continue;
3007
3729
  }
3008
3730
  const args = call.getArguments();
3009
3731
  if (args.length === 0) continue;
3010
3732
  const workqueuesArg = args[0];
3011
- if (!import_ts_morph13.Node.isArrayLiteralExpression(workqueuesArg)) continue;
3733
+ if (!import_ts_morph17.Node.isArrayLiteralExpression(workqueuesArg)) continue;
3012
3734
  for (const element of workqueuesArg.getElements()) {
3013
- if (!import_ts_morph13.Node.isObjectLiteralExpression(element)) continue;
3735
+ if (!import_ts_morph17.Node.isObjectLiteralExpression(element)) continue;
3014
3736
  migratedWorkqueues += migrateWorkqueueActions(element, relPath);
3015
3737
  }
3016
3738
  }
3017
3739
  return migratedWorkqueues;
3018
3740
  }
3019
- async function main13() {
3020
- const srcDir = import_path13.default.join(getCwd(), "src");
3741
+ async function main18() {
3742
+ const srcDir = import_path18.default.join(process.cwd(), "src");
3021
3743
  console.log(`Scanning for defineWorkqueues calls in: ${srcDir}
3022
3744
  `);
3023
- const project = new import_ts_morph13.Project({
3024
- tsConfigFilePath: import_path13.default.resolve(srcDir, "../tsconfig.json"),
3745
+ const project = new import_ts_morph17.Project({
3746
+ tsConfigFilePath: import_path18.default.resolve(srcDir, "../tsconfig.json"),
3025
3747
  skipAddingFilesFromTsConfig: false
3026
3748
  });
3027
3749
  const sourceFiles = project.getSourceFiles().filter((sf) => {
@@ -3034,7 +3756,7 @@ async function main13() {
3034
3756
  const modifiedFiles = [];
3035
3757
  for (const sourceFile of sourceFiles) {
3036
3758
  const filePath = sourceFile.getFilePath();
3037
- const migrated = processFile11(filePath, project);
3759
+ const migrated = processFile13(filePath, project);
3038
3760
  if (migrated > 0) {
3039
3761
  totalMigrated += migrated;
3040
3762
  modifiedFiles.push(filePath);
@@ -3051,7 +3773,7 @@ Saving ${modifiedFiles.length} modified file(s)...`);
3051
3773
  for (const filePath of modifiedFiles) {
3052
3774
  const sourceFile = project.getSourceFileOrThrow(filePath);
3053
3775
  await sourceFile.save();
3054
- console.log(` Saved: ${import_path13.default.relative(getCwd(), filePath)}`);
3776
+ console.log(` Saved: ${import_path18.default.relative(process.cwd(), filePath)}`);
3055
3777
  }
3056
3778
  console.log(
3057
3779
  `
@@ -3060,13 +3782,13 @@ Done. Migrated ${totalMigrated} deprecated workqueue 'actions' definition(s) to
3060
3782
  }
3061
3783
 
3062
3784
  // src/migrations/v2.0/remove-demo-scope.ts
3063
- var import_path14 = __toESM(require("path"));
3064
- var import_ts_morph14 = require("ts-morph");
3785
+ var import_path19 = __toESM(require("path"));
3786
+ var import_ts_morph18 = require("ts-morph");
3065
3787
  var ROLES_HANDLER_RELATIVE_PATH = "src/data-seeding/roles/handler.ts";
3066
- async function main14() {
3067
- const rolesHandlerPath = import_path14.default.join(getCwd(), ROLES_HANDLER_RELATIVE_PATH);
3068
- const project = new import_ts_morph14.Project({
3069
- tsConfigFilePath: import_path14.default.resolve(getCwd(), "tsconfig.json"),
3788
+ async function main19() {
3789
+ const rolesHandlerPath = import_path19.default.join(process.cwd(), ROLES_HANDLER_RELATIVE_PATH);
3790
+ const project = new import_ts_morph18.Project({
3791
+ tsConfigFilePath: import_path19.default.resolve(process.cwd(), "tsconfig.json"),
3070
3792
  skipAddingFilesFromTsConfig: false
3071
3793
  });
3072
3794
  const sourceFile = project.getSourceFile(rolesHandlerPath);
@@ -3115,7 +3837,7 @@ async function main14() {
3115
3837
 
3116
3838
  // src/migrations/v2.0/remove-hearth-migrations.ts
3117
3839
  var fs2 = __toESM(require("fs"));
3118
- var import_path15 = __toESM(require("path"));
3840
+ var import_path20 = __toESM(require("path"));
3119
3841
  var PATHS_TO_REMOVE = [
3120
3842
  {
3121
3843
  relativePath: "src/migrations/hearth",
@@ -3127,9 +3849,9 @@ var PATHS_TO_REMOVE = [
3127
3849
  },
3128
3850
  { relativePath: "src/utils/hearth-helpers.ts", label: "Hearth helpers file" }
3129
3851
  ];
3130
- async function main15() {
3852
+ async function main20() {
3131
3853
  for (const { relativePath, label } of PATHS_TO_REMOVE) {
3132
- const absolutePath = import_path15.default.join(getCwd(), relativePath);
3854
+ const absolutePath = import_path20.default.join(process.cwd(), relativePath);
3133
3855
  if (fs2.existsSync(absolutePath)) {
3134
3856
  fs2.rmSync(absolutePath, { recursive: true, force: true });
3135
3857
  console.log(`Removed ${label} '${relativePath}'.`);
@@ -3140,9 +3862,9 @@ async function main15() {
3140
3862
  }
3141
3863
 
3142
3864
  // src/migrations/v2.0/create-events-index.ts
3143
- var import_ts_morph15 = require("ts-morph");
3144
- var import_fs = __toESM(require("fs"));
3145
- var import_path16 = __toESM(require("path"));
3865
+ var import_ts_morph19 = require("ts-morph");
3866
+ var import_fs2 = __toESM(require("fs"));
3867
+ var import_path21 = __toESM(require("path"));
3146
3868
  var DEFINE_CONFIG_NAME5 = "defineConfig";
3147
3869
  var HANDLER_FUNCTION_NAMES = /* @__PURE__ */ new Set([
3148
3870
  "getCustomEventsHandler",
@@ -3164,7 +3886,7 @@ var LICENSE_HEADER = `/*
3164
3886
  `;
3165
3887
  function findEventConfigExports(project, srcDir) {
3166
3888
  const found = [];
3167
- const eventsIndexAbs = import_path16.default.join(srcDir, "events", "index.ts");
3889
+ const eventsIndexAbs = import_path21.default.join(srcDir, "events", "index.ts");
3168
3890
  for (const sourceFile of project.getSourceFiles()) {
3169
3891
  const filePath = sourceFile.getFilePath();
3170
3892
  if (!filePath.startsWith(srcDir) || filePath.includes("/node_modules/")) {
@@ -3176,10 +3898,10 @@ function findEventConfigExports(project, srcDir) {
3176
3898
  for (const decl of statement.getDeclarations()) {
3177
3899
  const initializer = decl.getInitializer();
3178
3900
  if (!initializer) continue;
3179
- const unwrapped = import_ts_morph15.Node.isAsExpression(initializer) ? initializer.getExpression() : initializer;
3180
- if (!import_ts_morph15.Node.isCallExpression(unwrapped)) continue;
3901
+ const unwrapped = import_ts_morph19.Node.isAsExpression(initializer) ? initializer.getExpression() : initializer;
3902
+ if (!import_ts_morph19.Node.isCallExpression(unwrapped)) continue;
3181
3903
  const callee = unwrapped.getExpression();
3182
- if (!import_ts_morph15.Node.isIdentifier(callee)) continue;
3904
+ if (!import_ts_morph19.Node.isIdentifier(callee)) continue;
3183
3905
  if (callee.getText() !== DEFINE_CONFIG_NAME5) continue;
3184
3906
  found.push({ name: decl.getName(), filePath });
3185
3907
  }
@@ -3188,8 +3910,8 @@ function findEventConfigExports(project, srcDir) {
3188
3910
  return found;
3189
3911
  }
3190
3912
  function buildIndexImportSpecifier(eventConfigFilePath, srcDir) {
3191
- const eventsIndexDir = import_path16.default.join(srcDir, "events");
3192
- let rel = import_path16.default.relative(eventsIndexDir, eventConfigFilePath).split(import_path16.default.sep).join("/");
3913
+ const eventsIndexDir = import_path21.default.join(srcDir, "events");
3914
+ let rel = import_path21.default.relative(eventsIndexDir, eventConfigFilePath).split(import_path21.default.sep).join("/");
3193
3915
  if (rel.endsWith(".ts")) rel = rel.slice(0, -".ts".length);
3194
3916
  if (rel.endsWith("/index")) rel = rel.slice(0, -"/index".length);
3195
3917
  if (!rel.startsWith(".")) rel = "./" + rel;
@@ -3266,17 +3988,17 @@ function modifyHandler(sourceFile, exportNames) {
3266
3988
  );
3267
3989
  }
3268
3990
  for (const call of sourceFile.getDescendantsOfKind(
3269
- import_ts_morph15.SyntaxKind.CallExpression
3991
+ import_ts_morph19.SyntaxKind.CallExpression
3270
3992
  )) {
3271
3993
  const callee = call.getExpression();
3272
- if (!import_ts_morph15.Node.isPropertyAccessExpression(callee)) continue;
3994
+ if (!import_ts_morph19.Node.isPropertyAccessExpression(callee)) continue;
3273
3995
  if (callee.getName() !== RESPONSE_METHOD_NAME) continue;
3274
3996
  const args = call.getArguments();
3275
3997
  if (args.length !== 1) continue;
3276
3998
  const [arg] = args;
3277
- if (!import_ts_morph15.Node.isArrayLiteralExpression(arg)) continue;
3999
+ if (!import_ts_morph19.Node.isArrayLiteralExpression(arg)) continue;
3278
4000
  if (arg.getElements().length === 0) continue;
3279
- if (!arg.getElements().every((el) => import_ts_morph15.Node.isIdentifier(el))) continue;
4001
+ if (!arg.getElements().every((el) => import_ts_morph19.Node.isIdentifier(el))) continue;
3280
4002
  arg.replaceWithText(EVENT_CONFIGS_IDENTIFIER);
3281
4003
  changes.push(
3282
4004
  `rewrote h.response([...]) \u2192 h.response(${EVENT_CONFIGS_IDENTIFIER})`
@@ -3284,13 +4006,13 @@ function modifyHandler(sourceFile, exportNames) {
3284
4006
  }
3285
4007
  return changes;
3286
4008
  }
3287
- async function main16() {
3288
- const cwd2 = getCwd();
3289
- const srcDir = import_path16.default.join(cwd2, "src");
4009
+ async function main21() {
4010
+ const cwd = process.cwd();
4011
+ const srcDir = import_path21.default.join(cwd, "src");
3290
4012
  console.log(`Scanning for defineConfig event exports in: ${srcDir}
3291
4013
  `);
3292
- const project = new import_ts_morph15.Project({
3293
- tsConfigFilePath: import_path16.default.resolve(srcDir, "../tsconfig.json"),
4014
+ const project = new import_ts_morph19.Project({
4015
+ tsConfigFilePath: import_path21.default.resolve(srcDir, "../tsconfig.json"),
3294
4016
  skipAddingFilesFromTsConfig: false
3295
4017
  });
3296
4018
  const eventConfigExports = findEventConfigExports(project, srcDir);
@@ -3302,15 +4024,15 @@ async function main16() {
3302
4024
  }
3303
4025
  console.log(`Found ${eventConfigExports.length} event config export(s):`);
3304
4026
  for (const e of eventConfigExports) {
3305
- console.log(` ${e.name} \u2190 ${import_path16.default.relative(cwd2, e.filePath)}`);
4027
+ console.log(` ${e.name} \u2190 ${import_path21.default.relative(cwd, e.filePath)}`);
3306
4028
  }
3307
- const eventsIndexAbs = import_path16.default.join(srcDir, "events", "index.ts");
3308
- const eventsIndexRel = import_path16.default.relative(cwd2, eventsIndexAbs);
3309
- if (import_fs.default.existsSync(eventsIndexAbs)) {
4029
+ const eventsIndexAbs = import_path21.default.join(srcDir, "events", "index.ts");
4030
+ const eventsIndexRel = import_path21.default.relative(cwd, eventsIndexAbs);
4031
+ if (import_fs2.default.existsSync(eventsIndexAbs)) {
3310
4032
  console.log(`
3311
4033
  [${eventsIndexRel}] already exists \u2014 leaving untouched.`);
3312
4034
  } else {
3313
- import_fs.default.mkdirSync(import_path16.default.dirname(eventsIndexAbs), { recursive: true });
4035
+ import_fs2.default.mkdirSync(import_path21.default.dirname(eventsIndexAbs), { recursive: true });
3314
4036
  const source = buildEventsIndexSource(eventConfigExports, srcDir);
3315
4037
  const eventsIndexFile = project.createSourceFile(eventsIndexAbs, source, {
3316
4038
  overwrite: false
@@ -3331,7 +4053,7 @@ No event-config handler file found (looked for exported function(s): ${Array.fro
3331
4053
  );
3332
4054
  return;
3333
4055
  }
3334
- const handlerRelPath = import_path16.default.relative(cwd2, handler.getFilePath());
4056
+ const handlerRelPath = import_path21.default.relative(cwd, handler.getFilePath());
3335
4057
  const exportNameSet = new Set(eventConfigExports.map((e) => e.name));
3336
4058
  const changes = modifyHandler(handler, exportNameSet);
3337
4059
  if (changes.length === 0) {
@@ -3351,12 +4073,13 @@ var UPSTREAM_URL = "https://github.com/opencrvs/opencrvs-countryconfig.git";
3351
4073
  var UPSTREAM_BRANCH = "develop";
3352
4074
  var TEMP_REMOTE = "opencrvs-upgrade-v19-v20-codemod";
3353
4075
  var FILES_TO_CHECKOUT = [
3354
- "infrastructure/postgres/setup-analytics.sh",
3355
- "src/analytics/analytics.ts"
4076
+ "src/analytics/analytics.ts",
4077
+ "Dockerfile",
4078
+ "Dockerfile.assets"
3356
4079
  ];
3357
4080
  function runGit(args, { silent = false } = {}) {
3358
4081
  return (0, import_child_process.execFileSync)("git", args, {
3359
- cwd: getCwd(),
4082
+ cwd: process.cwd(),
3360
4083
  encoding: "utf8",
3361
4084
  stdio: silent ? ["ignore", "pipe", "pipe"] : ["ignore", "pipe", "inherit"]
3362
4085
  });
@@ -3372,11 +4095,11 @@ function tryGit(args) {
3372
4095
  function assertIsGitRepo() {
3373
4096
  if (!tryGit(["rev-parse", "--is-inside-work-tree"])) {
3374
4097
  throw new Error(
3375
- `checkout-upstream-files: ${getCwd()} is not a git repository. Initialise git (or run the upgrade inside a git checkout) before re-running.`
4098
+ `${process.cwd()} is not a git repository. Initialise git (or run the upgrade inside a git checkout) before re-running.`
3376
4099
  );
3377
4100
  }
3378
4101
  }
3379
- async function main17() {
4102
+ async function main22() {
3380
4103
  console.log(
3381
4104
  `Checking out ${FILES_TO_CHECKOUT.length} file(s) from ${UPSTREAM_URL}@${UPSTREAM_BRANCH}...
3382
4105
  `
@@ -3424,10 +4147,356 @@ async function main17() {
3424
4147
  }
3425
4148
  }
3426
4149
 
4150
+ // src/migrations/v2.0/add-resend-invite-notification.ts
4151
+ var import_fs3 = require("fs");
4152
+ var import_path22 = __toESM(require("path"));
4153
+ var import_ts_morph20 = require("ts-morph");
4154
+ var TS_MORPH_PROJECT_OPTIONS = {
4155
+ skipAddingFilesFromTsConfig: true,
4156
+ manipulationSettings: {
4157
+ indentationText: import_ts_morph20.IndentationText.TwoSpaces
4158
+ }
4159
+ };
4160
+ var EMAIL_TEMPLATES_INDEX = "src/api/notification/email-templates/index.ts";
4161
+ var NOTIFICATION_HANDLER = "src/api/notification/handler.ts";
4162
+ var USER_NOTIFICATION_ROUTES = "src/config/routes/userNotificationRoutes.ts";
4163
+ var SMS_SERVICE = "src/api/notification/sms-service.ts";
4164
+ var NOTIFICATION_CSV = "src/translations/notification.csv";
4165
+ var RESEND_INVITE_HTML = "src/api/notification/email-templates/other/resend-invite.html";
4166
+ var RESEND_INVITE_HTML_CONTENT = `<!doctype html>
4167
+ <html>
4168
+ <head>
4169
+ <link
4170
+ href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;700&display=swap"
4171
+ rel="stylesheet"
4172
+ />
4173
+ <style type="text/css">
4174
+ body {
4175
+ font-family: 'Noto Sans', sans-serif;
4176
+ color: #222;
4177
+ padding: 16px 24px;
4178
+ }
4179
+
4180
+ h1 {
4181
+ font-size: 21px;
4182
+ margin-top: 32px;
4183
+ margin-bottom: 36px;
4184
+ font-weight: 700;
4185
+ }
4186
+
4187
+ p {
4188
+ font-weight: 400;
4189
+ font-size: 16px;
4190
+ line-height: 1.8;
4191
+ margin-bottom: 24px;
4192
+ }
4193
+
4194
+ i {
4195
+ color: #666;
4196
+ font-weight: 400;
4197
+ font-size: 16px;
4198
+ }
4199
+ </style>
4200
+ </head>
4201
+
4202
+ <body>
4203
+ <img
4204
+ src="{{countryLogo}}"
4205
+ alt="country_logo"
4206
+ style="max-height: 88px; max-width: 100%"
4207
+ />
4208
+ <h1>Your {{applicationName}} account invitation</h1>
4209
+ <p>Hello {{firstname}},</p>
4210
+ <p>Your account invitation has been resent. Please use the following credentials to access your account:</p>
4211
+ <p>
4212
+ Username: <strong>{{username}}</strong><br />
4213
+ Password: <strong>{{temporaryPassword}}</strong>
4214
+ </p>
4215
+ <p>
4216
+ Please click the link below to complete your account setup and start using
4217
+ {{applicationName}}.
4218
+ </p>
4219
+
4220
+ <div style="margin-top: 32px; margin-bottom: 32px">
4221
+ <a href="{{loginURL}}">Complete setup</a>
4222
+ </div>
4223
+ <br />
4224
+ <p>
4225
+ Best regards, <br />
4226
+ {{applicationName}} Team
4227
+ </p>
4228
+ </body>
4229
+ </html>
4230
+ `;
4231
+ var CSV_ROW = "resendInviteNotification,The SMS message that is sent when a user invitation is resent,Your OpenCRVS account invitation was resent. Please login with your username: {{username}} and temporary password: {{temporaryPassword}},Votre invitation de compte OpenCRVS a \xE9t\xE9 renvoy\xE9e. Veuillez vous connecter avec votre nom d'utilisateur : {{username}} et votre mot de passe temporaire : {{temporaryPassword}}.\n";
4232
+ function getObjectLiteralFromConst(declaration) {
4233
+ if (!declaration) {
4234
+ return;
4235
+ }
4236
+ const initializer = declaration.getInitializer();
4237
+ if (!initializer) {
4238
+ return;
4239
+ }
4240
+ if (import_ts_morph20.Node.isObjectLiteralExpression(initializer)) {
4241
+ return initializer;
4242
+ }
4243
+ if (import_ts_morph20.Node.isAsExpression(initializer)) {
4244
+ const expression = initializer.getExpression();
4245
+ if (import_ts_morph20.Node.isObjectLiteralExpression(expression)) {
4246
+ return expression;
4247
+ }
4248
+ }
4249
+ if (import_ts_morph20.Node.isSatisfiesExpression(initializer)) {
4250
+ const expression = initializer.getExpression();
4251
+ if (import_ts_morph20.Node.isObjectLiteralExpression(expression)) {
4252
+ return expression;
4253
+ }
4254
+ }
4255
+ }
4256
+ function patchEmailTemplatesIndex() {
4257
+ const full = import_path22.default.join(process.cwd(), EMAIL_TEMPLATES_INDEX);
4258
+ if (!(0, import_fs3.existsSync)(full)) {
4259
+ console.log(` '${EMAIL_TEMPLATES_INDEX}' missing \u2014 skipping.`);
4260
+ return false;
4261
+ }
4262
+ const project = new import_ts_morph20.Project(TS_MORPH_PROJECT_OPTIONS);
4263
+ const sourceFile = project.addSourceFileAtPath(full);
4264
+ let changed = false;
4265
+ const triggerVariableObject = getObjectLiteralFromConst(
4266
+ sourceFile.getVariableDeclaration("TriggerVariable")
4267
+ );
4268
+ if (triggerVariableObject) {
4269
+ const hasResendInviteVariable = triggerVariableObject.getProperties().some((prop) => prop.getText().includes("[TriggerEvent.RESEND_INVITE]"));
4270
+ if (!hasResendInviteVariable) {
4271
+ const properties = triggerVariableObject.getProperties();
4272
+ const lastProperty = properties[properties.length - 1];
4273
+ if (lastProperty) {
4274
+ sourceFile.insertText(
4275
+ lastProperty.getEnd(),
4276
+ `,
4277
+ [TriggerEvent.RESEND_INVITE]: z.object({
4278
+ firstname: z.string(),
4279
+ username: z.string(),
4280
+ temporaryPassword: z.string(),
4281
+ completeSetupUrl: z.string(),
4282
+ loginURL: z.string()
4283
+ })`
4284
+ );
4285
+ changed = true;
4286
+ }
4287
+ }
4288
+ }
4289
+ const templatesObject = getObjectLiteralFromConst(
4290
+ sourceFile.getVariableDeclaration("templates")
4291
+ );
4292
+ if (templatesObject) {
4293
+ const hasResendInviteTemplate = templatesObject.getProperties().some(
4294
+ (prop) => prop.getText().includes("readOtherTemplate<TriggerVariable['resend-invite']>")
4295
+ );
4296
+ if (!hasResendInviteTemplate) {
4297
+ const userCreatedProp = templatesObject.getProperties().find((prop) => prop.getText().includes("[TriggerEvent.USER_CREATED]"));
4298
+ const anchor = userCreatedProp ?? templatesObject.getProperties()[templatesObject.getProperties().length - 1];
4299
+ if (anchor) {
4300
+ sourceFile.insertText(
4301
+ anchor.getEnd(),
4302
+ `,
4303
+ [TriggerEvent.RESEND_INVITE]: {
4304
+ type: 'resend-invite',
4305
+ subject: 'Your OpenCRVS account invitation',
4306
+ template:
4307
+ readOtherTemplate<TriggerVariable['resend-invite']>('resend-invite')
4308
+ }`
4309
+ );
4310
+ changed = true;
4311
+ }
4312
+ }
4313
+ }
4314
+ if (changed) {
4315
+ sourceFile.saveSync();
4316
+ }
4317
+ return changed;
4318
+ }
4319
+ function patchNotificationHandler() {
4320
+ const full = import_path22.default.join(process.cwd(), NOTIFICATION_HANDLER);
4321
+ if (!(0, import_fs3.existsSync)(full)) {
4322
+ return false;
4323
+ }
4324
+ const project = new import_ts_morph20.Project(TS_MORPH_PROJECT_OPTIONS);
4325
+ const sourceFile = project.addSourceFileAtPath(full);
4326
+ const convertFn = sourceFile.getFunction("convertPayloadToVariable");
4327
+ if (!convertFn) {
4328
+ return false;
4329
+ }
4330
+ const switchStmt = convertFn.getFirstDescendantByKind(
4331
+ import_ts_morph20.SyntaxKind.SwitchStatement
4332
+ );
4333
+ if (!switchStmt) {
4334
+ return false;
4335
+ }
4336
+ const clauses = switchStmt.getCaseBlock().getClauses();
4337
+ const hasResendInvite = clauses.some(
4338
+ (clause) => import_ts_morph20.Node.isCaseClause(clause) && clause.getExpression().getText() === "TriggerEvent.RESEND_INVITE"
4339
+ );
4340
+ if (hasResendInvite) {
4341
+ return false;
4342
+ }
4343
+ const userCreatedClauseIndex = clauses.findIndex(
4344
+ (clause) => import_ts_morph20.Node.isCaseClause(clause) && clause.getExpression().getText() === "TriggerEvent.USER_CREATED"
4345
+ );
4346
+ if (userCreatedClauseIndex < 0) {
4347
+ return false;
4348
+ }
4349
+ const userCreatedClause = clauses[userCreatedClauseIndex];
4350
+ sourceFile.insertText(
4351
+ userCreatedClause.getEnd(),
4352
+ `
4353
+
4354
+ case TriggerEvent.RESEND_INVITE:
4355
+ return {
4356
+ firstname,
4357
+ username: payload.username,
4358
+ temporaryPassword: payload.temporaryPassword,
4359
+ completeSetupUrl: LOGIN_URL,
4360
+ loginURL: LOGIN_URL
4361
+ }`
4362
+ );
4363
+ sourceFile.saveSync();
4364
+ return true;
4365
+ }
4366
+ function getReturnedArrayLiteral(functionFilePath, fnName) {
4367
+ const project = new import_ts_morph20.Project(TS_MORPH_PROJECT_OPTIONS);
4368
+ const sourceFile = project.addSourceFileAtPath(functionFilePath);
4369
+ const fn = sourceFile.getFunction(fnName);
4370
+ const returnStmt = fn?.getFirstDescendantByKind(import_ts_morph20.SyntaxKind.ReturnStatement);
4371
+ const expr = returnStmt?.getExpression();
4372
+ if (!expr || !import_ts_morph20.Node.isArrayLiteralExpression(expr)) {
4373
+ return { sourceFile, arrayLiteral: void 0 };
4374
+ }
4375
+ return { sourceFile, arrayLiteral: expr };
4376
+ }
4377
+ function patchUserNotificationRoutes() {
4378
+ const full = import_path22.default.join(process.cwd(), USER_NOTIFICATION_ROUTES);
4379
+ if (!(0, import_fs3.existsSync)(full)) {
4380
+ return false;
4381
+ }
4382
+ const { sourceFile, arrayLiteral } = getReturnedArrayLiteral(
4383
+ full,
4384
+ "getUserNotificationRoutes"
4385
+ );
4386
+ if (!arrayLiteral) {
4387
+ return false;
4388
+ }
4389
+ const elements = arrayLiteral.getElements();
4390
+ const routeExists = elements.some(
4391
+ (element) => element.getText().includes(`path: '/triggers/user/resend-invite'`)
4392
+ );
4393
+ if (routeExists) {
4394
+ return false;
4395
+ }
4396
+ const anchor = elements.find(
4397
+ (element) => element.getText().includes(`path: '/triggers/user/user-created'`)
4398
+ ) ?? elements[elements.length - 1];
4399
+ if (!anchor) {
4400
+ return false;
4401
+ }
4402
+ sourceFile.insertText(
4403
+ anchor.getEnd(),
4404
+ `,
4405
+ {
4406
+ method: 'POST',
4407
+ path: '/triggers/user/resend-invite',
4408
+ handler: makeNotificationHandler('resend-invite'),
4409
+ options: {
4410
+ auth: false,
4411
+ tags: ['api'],
4412
+ description: 'Handles notification for resent user invite'
4413
+ }
4414
+ }`
4415
+ );
4416
+ sourceFile.saveSync();
4417
+ return true;
4418
+ }
4419
+ function patchSmsService() {
4420
+ const full = import_path22.default.join(process.cwd(), SMS_SERVICE);
4421
+ if (!(0, import_fs3.existsSync)(full)) {
4422
+ return false;
4423
+ }
4424
+ const project = new import_ts_morph20.Project(TS_MORPH_PROJECT_OPTIONS);
4425
+ const sourceFile = project.addSourceFileAtPath(full);
4426
+ let changed = false;
4427
+ const otherTemplatesObject = getObjectLiteralFromConst(
4428
+ sourceFile.getVariableDeclaration("otherTemplates")
4429
+ );
4430
+ if (otherTemplatesObject) {
4431
+ const hasResendTemplate = otherTemplatesObject.getProperties().some((prop) => prop.getText().includes("resendInviteNotification"));
4432
+ if (!hasResendTemplate) {
4433
+ const userCredentialsIndex = otherTemplatesObject.getProperties().findIndex((prop) => prop.getText().includes("userCredentialsNotification"));
4434
+ otherTemplatesObject.insertPropertyAssignment(
4435
+ userCredentialsIndex >= 0 ? userCredentialsIndex + 1 : otherTemplatesObject.getProperties().length,
4436
+ {
4437
+ name: "resendInviteNotification",
4438
+ initializer: `'resendInviteNotification'`
4439
+ }
4440
+ );
4441
+ changed = true;
4442
+ }
4443
+ }
4444
+ const triggerToSmsTemplateObject = getObjectLiteralFromConst(
4445
+ sourceFile.getVariableDeclaration("TriggerToSMSTemplate")
4446
+ );
4447
+ if (triggerToSmsTemplateObject) {
4448
+ const hasResendInviteMap = triggerToSmsTemplateObject.getProperties().some((prop) => prop.getText().includes(`['resend-invite']`));
4449
+ if (!hasResendInviteMap) {
4450
+ const userCreatedIndex = triggerToSmsTemplateObject.getProperties().findIndex((prop) => prop.getText().includes(`['user-created']`));
4451
+ triggerToSmsTemplateObject.insertPropertyAssignment(
4452
+ userCreatedIndex >= 0 ? userCreatedIndex + 1 : triggerToSmsTemplateObject.getProperties().length,
4453
+ {
4454
+ name: `['resend-invite']`,
4455
+ initializer: `'resendInviteNotification'`
4456
+ }
4457
+ );
4458
+ changed = true;
4459
+ }
4460
+ }
4461
+ if (changed) {
4462
+ sourceFile.saveSync();
4463
+ }
4464
+ return changed;
4465
+ }
4466
+ async function main23() {
4467
+ console.log("Adding RESEND_INVITE notification wiring\u2026");
4468
+ const touched = [];
4469
+ if (patchEmailTemplatesIndex()) touched.push(EMAIL_TEMPLATES_INDEX);
4470
+ if (patchNotificationHandler()) touched.push(NOTIFICATION_HANDLER);
4471
+ if (patchUserNotificationRoutes()) touched.push(USER_NOTIFICATION_ROUTES);
4472
+ if (patchSmsService()) touched.push(SMS_SERVICE);
4473
+ const csvPath = import_path22.default.join(process.cwd(), NOTIFICATION_CSV);
4474
+ if ((0, import_fs3.existsSync)(csvPath)) {
4475
+ let t = (0, import_fs3.readFileSync)(csvPath, "utf8");
4476
+ if (!/^resendInviteNotification,/m.test(t)) {
4477
+ if (!t.endsWith("\n")) t += "\n";
4478
+ (0, import_fs3.writeFileSync)(csvPath, t + CSV_ROW);
4479
+ touched.push(NOTIFICATION_CSV);
4480
+ }
4481
+ }
4482
+ const htmlPath = import_path22.default.join(process.cwd(), RESEND_INVITE_HTML);
4483
+ (0, import_fs3.mkdirSync)(import_path22.default.dirname(htmlPath), { recursive: true });
4484
+ if (!(0, import_fs3.existsSync)(htmlPath)) {
4485
+ (0, import_fs3.writeFileSync)(htmlPath, RESEND_INVITE_HTML_CONTENT);
4486
+ touched.push(RESEND_INVITE_HTML);
4487
+ }
4488
+ if (touched.length === 0) {
4489
+ console.log(" Nothing to update (already present or anchors not found).");
4490
+ return;
4491
+ }
4492
+ console.log(` Updated:
4493
+ ${touched.map((f) => ` - ${f}`).join("\n")}`);
4494
+ }
4495
+
3427
4496
  // src/migrations/v2.0/simplify-analytics-precalculations.ts
3428
- var import_ts_morph16 = require("ts-morph");
3429
- var import_fs2 = __toESM(require("fs"));
3430
- var import_path17 = __toESM(require("path"));
4497
+ var import_ts_morph21 = require("ts-morph");
4498
+ var import_fs4 = __toESM(require("fs"));
4499
+ var import_path23 = __toESM(require("path"));
3431
4500
  var ANALYTICS_FILE_REL = "src/analytics/analytics.ts";
3432
4501
  var FUNCTION_NAME = "precalculateAdditionalAnalytics";
3433
4502
  var IMPORT_NAMES_TO_REMOVE = /* @__PURE__ */ new Set(["Event", "precalculateBirthEvent"]);
@@ -3463,10 +4532,10 @@ function findPrecalculateFunction(sourceFile) {
3463
4532
  return void 0;
3464
4533
  }
3465
4534
  function getFunctionBodyBlock(fn) {
3466
- if (import_ts_morph16.Node.isFunctionDeclaration(fn)) return fn.getBody();
4535
+ if (import_ts_morph21.Node.isFunctionDeclaration(fn)) return fn.getBody();
3467
4536
  const initializer = fn.getInitializer();
3468
4537
  if (!initializer) return void 0;
3469
- if (!import_ts_morph16.Node.isArrowFunction(initializer) && !import_ts_morph16.Node.isFunctionExpression(initializer)) {
4538
+ if (!import_ts_morph21.Node.isArrowFunction(initializer) && !import_ts_morph21.Node.isFunctionExpression(initializer)) {
3470
4539
  return void 0;
3471
4540
  }
3472
4541
  return initializer.getBody();
@@ -3476,9 +4545,9 @@ function simplifyPrecalculateFunction(sourceFile) {
3476
4545
  const fn = findPrecalculateFunction(sourceFile);
3477
4546
  if (!fn) return log;
3478
4547
  const body = getFunctionBodyBlock(fn);
3479
- if (!body || !import_ts_morph16.Node.isBlock(body)) return log;
4548
+ if (!body || !import_ts_morph21.Node.isBlock(body)) return log;
3480
4549
  for (const statement of [...body.getStatements()]) {
3481
- const references = statement.getDescendantsOfKind(import_ts_morph16.SyntaxKind.Identifier).some((id) => IMPORT_NAMES_TO_REMOVE.has(id.getText()));
4550
+ const references = statement.getDescendantsOfKind(import_ts_morph21.SyntaxKind.Identifier).some((id) => IMPORT_NAMES_TO_REMOVE.has(id.getText()));
3482
4551
  if (references) {
3483
4552
  statement.remove();
3484
4553
  log.push(`removed statement in ${FUNCTION_NAME} referencing removed imports`);
@@ -3486,7 +4555,7 @@ function simplifyPrecalculateFunction(sourceFile) {
3486
4555
  }
3487
4556
  const remaining = body.getStatements();
3488
4557
  const last = remaining[remaining.length - 1];
3489
- const alreadyCorrect = last && import_ts_morph16.Node.isReturnStatement(last) && last.getExpression()?.getText() === RETURN_EXPRESSION_TEXT;
4558
+ const alreadyCorrect = last && import_ts_morph21.Node.isReturnStatement(last) && last.getExpression()?.getText() === RETURN_EXPRESSION_TEXT;
3490
4559
  if (!alreadyCorrect) {
3491
4560
  body.addStatements(`return ${RETURN_EXPRESSION_TEXT}`);
3492
4561
  log.push(
@@ -3495,17 +4564,17 @@ function simplifyPrecalculateFunction(sourceFile) {
3495
4564
  }
3496
4565
  return log;
3497
4566
  }
3498
- async function main18() {
3499
- const cwd2 = getCwd();
3500
- const absPath = import_path17.default.join(cwd2, ANALYTICS_FILE_REL);
3501
- if (!import_fs2.default.existsSync(absPath)) {
4567
+ async function main24() {
4568
+ const cwd = process.cwd();
4569
+ const absPath = import_path23.default.join(cwd, ANALYTICS_FILE_REL);
4570
+ if (!import_fs4.default.existsSync(absPath)) {
3502
4571
  console.log(
3503
4572
  `[${ANALYTICS_FILE_REL}] does not exist \u2014 nothing to clean up.`
3504
4573
  );
3505
4574
  return;
3506
4575
  }
3507
- const project = new import_ts_morph16.Project({
3508
- tsConfigFilePath: import_path17.default.resolve(cwd2, "tsconfig.json"),
4576
+ const project = new import_ts_morph21.Project({
4577
+ tsConfigFilePath: import_path23.default.resolve(cwd, "tsconfig.json"),
3509
4578
  skipAddingFilesFromTsConfig: false
3510
4579
  });
3511
4580
  const sourceFile = project.getSourceFile(absPath);
@@ -3532,26 +4601,158 @@ async function main18() {
3532
4601
  Saved ${ANALYTICS_FILE_REL}.`);
3533
4602
  }
3534
4603
 
3535
- // src/migrations/v2.0/index.ts
3536
- var cwd;
3537
- function getCwd() {
3538
- if (!cwd) {
3539
- throw new Error("Country config working directory not set.");
4604
+ // src/migrations/v2.0/merge-infrastructure-directory.ts
4605
+ var import_child_process2 = require("child_process");
4606
+ var import_fs5 = require("fs");
4607
+ var import_os = require("os");
4608
+ var import_path24 = require("path");
4609
+ var TEMP_REMOTE2 = "opencrvs-upgrade-v19-v20-codemod-merge-infra";
4610
+ var INFRASTRUCTURE_DIR = "infrastructure";
4611
+ var BASE_BRANCH = "release-v1.9";
4612
+ function gitShowBytes(ref, path23) {
4613
+ try {
4614
+ const buf = (0, import_child_process2.execFileSync)("git", ["show", `${ref}:${path23}`], {
4615
+ cwd: process.cwd(),
4616
+ stdio: ["ignore", "pipe", "pipe"]
4617
+ });
4618
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
4619
+ } catch {
4620
+ return null;
3540
4621
  }
3541
- return cwd;
3542
4622
  }
3543
- async function runUpgrade(ccwd) {
3544
- if (ccwd) {
3545
- console.log("Country config working directory:", ccwd);
3546
- cwd = ccwd;
4623
+ async function main25() {
4624
+ console.log(
4625
+ `Merging '${INFRASTRUCTURE_DIR}/' from ${UPSTREAM_URL}@${UPSTREAM_BRANCH} (base: ${BASE_BRANCH})...
4626
+ `
4627
+ );
4628
+ assertIsGitRepo();
4629
+ tryGit(["remote", "remove", TEMP_REMOTE2]);
4630
+ try {
4631
+ console.log(` Adding temporary remote '${TEMP_REMOTE2}' \u2192 ${UPSTREAM_URL}`);
4632
+ runGit(["remote", "add", TEMP_REMOTE2, UPSTREAM_URL], { silent: true });
4633
+ console.log(
4634
+ ` Fetching ${TEMP_REMOTE2}/{${UPSTREAM_BRANCH},${BASE_BRANCH}} (depth 1)...`
4635
+ );
4636
+ runGit(["fetch", "--depth=1", TEMP_REMOTE2, UPSTREAM_BRANCH, BASE_BRANCH]);
4637
+ const ref = `${TEMP_REMOTE2}/${UPSTREAM_BRANCH}`;
4638
+ const baseRef = `${TEMP_REMOTE2}/${BASE_BRANCH}`;
4639
+ const upstreamFiles = runGit(
4640
+ [
4641
+ "ls-tree",
4642
+ "-r",
4643
+ "--name-only",
4644
+ "-z",
4645
+ ref,
4646
+ "--",
4647
+ `${INFRASTRUCTURE_DIR}/`
4648
+ ],
4649
+ { silent: true }
4650
+ ).split("\0").filter(Boolean);
4651
+ if (upstreamFiles.length === 0) {
4652
+ console.log(
4653
+ ` No files found under '${INFRASTRUCTURE_DIR}/' on ${ref}. Nothing to merge.`
4654
+ );
4655
+ return;
4656
+ }
4657
+ const tmpDir = (0, import_fs5.mkdtempSync)((0, import_path24.join)((0, import_os.tmpdir)(), "opencrvs-merge-infra-"));
4658
+ const baseTmp = (0, import_path24.join)(tmpDir, "base");
4659
+ const theirsTmp = (0, import_path24.join)(tmpDir, "theirs");
4660
+ let added = 0;
4661
+ let merged = 0;
4662
+ const conflictedFiles = [];
4663
+ for (const file of upstreamFiles) {
4664
+ const fullPath = (0, import_path24.join)(process.cwd(), file);
4665
+ if (!(0, import_fs5.existsSync)(fullPath)) {
4666
+ if (tryGit(["checkout", ref, "--", file])) {
4667
+ console.log(` + ${file} (new from upstream)`);
4668
+ added++;
4669
+ } else {
4670
+ console.warn(` [warn] failed to add new file ${file}`);
4671
+ }
4672
+ continue;
4673
+ }
4674
+ const theirContents = gitShowBytes(ref, file);
4675
+ if (theirContents === null) {
4676
+ console.warn(` [warn] could not read ${file} from ${ref} \u2014 skipping.`);
4677
+ continue;
4678
+ }
4679
+ (0, import_fs5.writeFileSync)(theirsTmp, theirContents);
4680
+ const baseContents = gitShowBytes(baseRef, file);
4681
+ (0, import_fs5.writeFileSync)(baseTmp, baseContents ?? new Uint8Array(0));
4682
+ try {
4683
+ (0, import_child_process2.execFileSync)("git", ["merge-file", fullPath, baseTmp, theirsTmp], {
4684
+ cwd: process.cwd(),
4685
+ stdio: ["ignore", "pipe", "pipe"]
4686
+ });
4687
+ runGit(["add", "--", file], { silent: true });
4688
+ merged++;
4689
+ } catch (err) {
4690
+ const status = err.status;
4691
+ if (typeof status === "number" && status > 0) {
4692
+ conflictedFiles.push(file);
4693
+ console.warn(
4694
+ ` ! ${file} (${status} conflict${status > 1 ? "s" : ""})`
4695
+ );
4696
+ } else {
4697
+ conflictedFiles.push(file);
4698
+ console.warn(
4699
+ ` [warn] merge failed for ${file} (likely binary or unreadable) \u2014 left untouched.`
4700
+ );
4701
+ }
4702
+ }
4703
+ }
4704
+ console.log(
4705
+ `
4706
+ Done. ${added} added, ${merged} merged cleanly, ${conflictedFiles.length} with conflicts.`
4707
+ );
4708
+ if (conflictedFiles.length > 0) {
4709
+ console.warn(
4710
+ `
4711
+ NOTE: ${conflictedFiles.length} file(s) under '${INFRASTRUCTURE_DIR}/' have merge conflicts that you must resolve manually.
4712
+ Look for the standard conflict markers (<<<<<<<, =======, >>>>>>>) in:
4713
+ ` + conflictedFiles.map((f) => ` - ${f}`).join("\n") + `
4714
+ After resolving, stage the fixes with: git add ${INFRASTRUCTURE_DIR}/`
4715
+ );
4716
+ }
4717
+ } finally {
4718
+ if (tryGit(["remote", "remove", TEMP_REMOTE2])) {
4719
+ console.log(` Removed temporary remote '${TEMP_REMOTE2}'.`);
4720
+ }
3547
4721
  }
3548
- if (!ccwd) {
4722
+ }
4723
+
4724
+ // src/migrations/v2.0/delete-infrastructure-directory.ts
4725
+ var import_fs6 = require("fs");
4726
+ var import_path25 = require("path");
4727
+ var INFRASTRUCTURE_DIR2 = "infrastructure";
4728
+ async function main26() {
4729
+ const fullPath = (0, import_path25.join)(process.cwd(), INFRASTRUCTURE_DIR2);
4730
+ if (!(0, import_fs6.existsSync)(fullPath)) {
3549
4731
  console.log(
3550
- "Will use current working directory as country config working directory."
4732
+ `'${INFRASTRUCTURE_DIR2}/' not found in ${process.cwd()} \u2014 nothing to delete.`
3551
4733
  );
3552
- cwd = process.cwd();
4734
+ return;
3553
4735
  }
3554
- await main13();
4736
+ console.log(`Deleting '${INFRASTRUCTURE_DIR2}/'...
4737
+ `);
4738
+ assertIsGitRepo();
4739
+ runGit(["rm", "-rf", "--ignore-unmatch", "--", `${INFRASTRUCTURE_DIR2}/`], {
4740
+ silent: true
4741
+ });
4742
+ console.log(` Staged deletion of tracked files under '${INFRASTRUCTURE_DIR2}/'.`);
4743
+ if ((0, import_fs6.existsSync)(fullPath)) {
4744
+ (0, import_fs6.rmSync)(fullPath, { recursive: true, force: true });
4745
+ console.log(` Removed remaining untracked files under '${INFRASTRUCTURE_DIR2}/'.`);
4746
+ }
4747
+ console.log(
4748
+ `
4749
+ Done. Review the staged deletion with: git diff --cached -- '${INFRASTRUCTURE_DIR2}/'`
4750
+ );
4751
+ }
4752
+
4753
+ // src/migrations/v2.0/index.ts
4754
+ async function runUpgrade(dockerSwarm) {
4755
+ await main18();
3555
4756
  await main();
3556
4757
  await main2();
3557
4758
  await main3();
@@ -3564,9 +4765,20 @@ async function runUpgrade(ccwd) {
3564
4765
  await main10();
3565
4766
  await main11();
3566
4767
  await main12();
4768
+ await main13();
3567
4769
  await main14();
3568
4770
  await main15();
3569
4771
  await main16();
4772
+ await main19();
4773
+ await main20();
4774
+ await main21();
4775
+ await main22();
4776
+ await main23();
4777
+ await main24();
3570
4778
  await main17();
3571
- await main18();
4779
+ if (dockerSwarm) {
4780
+ await main25();
4781
+ } else {
4782
+ await main26();
4783
+ }
3572
4784
  }