@codedrifters/configulator 0.0.94 → 0.0.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,6 +14,7 @@ A library of [Projen](https://projen.io/) components used by CodeDrifters to man
14
14
  - [Configuration Options](#configuration-options)
15
15
  - [Turbo Repo](#turbo-repo)
16
16
  - [PNPM Workspace](#pnpm-workspace)
17
+ - [Updating VERSION constants](#updating-version-constants)
17
18
  - [File Management Rules](#file-management-rules)
18
19
  - [Workflow Tips](#workflow-tips)
19
20
  - [API Reference](#api-reference)
@@ -472,6 +473,39 @@ deps: ['react@catalog:react']
472
473
  deps: ['react@catalog:frontend/react']
473
474
  ```
474
475
 
476
+ ### Updating VERSION constants
477
+
478
+ The catalog versions (e.g. `VERSION.PROJEN_VERSION`, `VERSION.TURBO_VERSION`) in `src/versions.ts` can be updated automatically so they stay in sync with npm releases while respecting the PNPM workspace `minimumReleaseAge` (so only versions published long enough ago are considered).
479
+
480
+ **What it does**
481
+
482
+ - A script (`scripts/update-versions.ts` at monorepo root) fetches the latest eligible version for each npm-backed constant from the npm registry using the `time` field.
483
+ - Only versions that have been published for at least `minimumReleaseAge` minutes (from the PNPM workspace) are considered.
484
+ - The script runs as part of the **upgrade** task, so when the upgrade workflow runs (e.g. nightly or `workflow_dispatch`), version updates are included in the same PR as dependency upgrades.
485
+
486
+ **How to run**
487
+
488
+ From the monorepo root:
489
+
490
+ - **Propose only** (print suggested changes, do not edit files):
491
+ ```bash
492
+ pnpm run update-versions
493
+ ```
494
+ - **Apply locally** (update `versions.ts` and run `npx projen`):
495
+ ```bash
496
+ pnpm run update-versions -- --apply
497
+ ```
498
+ - **In CI**: When run from the upgrade workflow, the script auto-applies when there are updates so changes are included in the upgrade PR.
499
+
500
+ **Adding a new npm-backed constant**
501
+
502
+ 1. Add the constant to `src/versions.ts` (e.g. `MY_PACKAGE_VERSION: "1.0.0"`).
503
+ 2. Add an entry to `VERSION_NPM_PACKAGES` in `src/version-package-map.ts`:
504
+ ```typescript
505
+ { key: "MY_PACKAGE_VERSION", npmPackage: "my-package" },
506
+ ```
507
+ Constants not listed in `VERSION_NPM_PACKAGES` (e.g. `NODE_WORKFLOWS`) are skipped by the update script.
508
+
475
509
  ### Turborepo Integration
476
510
 
477
511
  When you create a `MonorepoProject` with `turbo: true` (the default), Turborepo is automatically configured. Sub-projects created with `TypeScriptProject` automatically get Turborepo task configuration if their parent has Turborepo enabled.
package/lib/index.d.mts CHANGED
@@ -347,6 +347,25 @@ interface AwsOrganization {
347
347
  accounts: Array<AwsAccount>;
348
348
  }
349
349
 
350
+ /**
351
+ * Returns the latest full-release version of an npm package that has been
352
+ * published for at least `minimumReleaseAgeMinutes` minutes. Prefers the
353
+ * version indicated by the registry's "latest" dist-tag when it is a full
354
+ * release: if that version's publish time is in the registry and old enough,
355
+ * it is used; if it is not in the registry's "time" object (e.g. truncated
356
+ * for large packages), the dist-tag is still used so npm's "latest" is
357
+ * followed. When the dist-tag version is too new (in time but not old enough),
358
+ * we fall back to the highest full-release version that is old enough and
359
+ * ≤ latest (e.g. latest 2.x that's old enough, not 3.0.0). Prerelease
360
+ * versions are excluded. Returns null if `time` is missing or no version is
361
+ * eligible.
362
+ *
363
+ * @param packageName - npm package name (e.g. "projen").
364
+ * @param minimumReleaseAgeMinutes - minimum age in minutes (e.g. 1440 for 24h).
365
+ * @returns The latest eligible version string, or null.
366
+ */
367
+ declare function getLatestEligibleVersion(packageName: string, minimumReleaseAgeMinutes: number): Promise<string | null>;
368
+
350
369
  declare const VERSION: {
351
370
  /**
352
371
  * CDK CLI for workflows and command line operations.
@@ -382,6 +401,27 @@ declare const VERSION: {
382
401
  readonly TURBO_VERSION: "2.8.3";
383
402
  };
384
403
 
404
+ /**
405
+ * Keys of the VERSION object in versions.ts.
406
+ */
407
+ type VersionKey = keyof typeof VERSION;
408
+ /**
409
+ * Mapping of VERSION keys that are backed by an npm package and eligible
410
+ * for auto-update. Only these keys should be updated by version-update
411
+ * automation; others (e.g. NODE_WORKFLOWS) are skipped.
412
+ *
413
+ * @see {@link VERSION_KEYS_SKIP} for keys that must not be auto-updated.
414
+ */
415
+ declare const VERSION_NPM_PACKAGES: ReadonlyArray<{
416
+ key: VersionKey;
417
+ npmPackage: string;
418
+ }>;
419
+ /**
420
+ * VERSION keys that are not backed by npm and must be skipped by
421
+ * auto-update (e.g. runtime versions like Node.js).
422
+ */
423
+ declare const VERSION_KEYS_SKIP: ReadonlyArray<VersionKey>;
424
+
385
425
  /**
386
426
  * The FQNs for the base classes and options used by Jsii.
387
427
  *
@@ -1344,4 +1384,4 @@ declare class AwsDeployWorkflow extends Component {
1344
1384
  preSynthesize(): void;
1345
1385
  }
1346
1386
 
1347
- export { type AwsAccount, AwsDeployWorkflow, AwsDeploymentConfig, AwsDeploymentTarget, type AwsDeploymentTargetOptions, type AwsLocalDeploymentConfig, type AwsOrganization, type AwsRegion, type CiDeploymentConfig, type ClassTypeOptions, type DeployWorkflowOptions, type GitBranch, type IDependencyResolver, JsiiFaker, MIMIMUM_RELEASE_AGE, MonorepoProject, type MonorepoProjectOptions, PROD_DEPLOY_NAME, PnpmWorkspace, type PnpmWorkspaceOptions, ROOT_CI_TASK_NAME, ROOT_TURBO_TASK_NAME, type RemoteCacheOptions, ResetTask, type ResetTaskOptions, TurboRepo, type TurboRepoOptions, TurboRepoTask, type TurboRepoTaskOptions, TypeScriptConfig, TypeScriptProject, type TypeScriptProjectOptions, VERSION, VSCodeConfig };
1387
+ export { type AwsAccount, AwsDeployWorkflow, AwsDeploymentConfig, AwsDeploymentTarget, type AwsDeploymentTargetOptions, type AwsLocalDeploymentConfig, type AwsOrganization, type AwsRegion, type CiDeploymentConfig, type ClassTypeOptions, type DeployWorkflowOptions, type GitBranch, type IDependencyResolver, JsiiFaker, MIMIMUM_RELEASE_AGE, MonorepoProject, type MonorepoProjectOptions, PROD_DEPLOY_NAME, PnpmWorkspace, type PnpmWorkspaceOptions, ROOT_CI_TASK_NAME, ROOT_TURBO_TASK_NAME, type RemoteCacheOptions, ResetTask, type ResetTaskOptions, TurboRepo, type TurboRepoOptions, TurboRepoTask, type TurboRepoTaskOptions, TypeScriptConfig, TypeScriptProject, type TypeScriptProjectOptions, VERSION, VERSION_KEYS_SKIP, VERSION_NPM_PACKAGES, VSCodeConfig, type VersionKey, getLatestEligibleVersion };
package/lib/index.d.ts CHANGED
@@ -396,6 +396,25 @@ interface AwsOrganization {
396
396
  accounts: Array<AwsAccount>;
397
397
  }
398
398
 
399
+ /**
400
+ * Returns the latest full-release version of an npm package that has been
401
+ * published for at least `minimumReleaseAgeMinutes` minutes. Prefers the
402
+ * version indicated by the registry's "latest" dist-tag when it is a full
403
+ * release: if that version's publish time is in the registry and old enough,
404
+ * it is used; if it is not in the registry's "time" object (e.g. truncated
405
+ * for large packages), the dist-tag is still used so npm's "latest" is
406
+ * followed. When the dist-tag version is too new (in time but not old enough),
407
+ * we fall back to the highest full-release version that is old enough and
408
+ * ≤ latest (e.g. latest 2.x that's old enough, not 3.0.0). Prerelease
409
+ * versions are excluded. Returns null if `time` is missing or no version is
410
+ * eligible.
411
+ *
412
+ * @param packageName - npm package name (e.g. "projen").
413
+ * @param minimumReleaseAgeMinutes - minimum age in minutes (e.g. 1440 for 24h).
414
+ * @returns The latest eligible version string, or null.
415
+ */
416
+ declare function getLatestEligibleVersion(packageName: string, minimumReleaseAgeMinutes: number): Promise<string | null>;
417
+
399
418
  declare const VERSION: {
400
419
  /**
401
420
  * CDK CLI for workflows and command line operations.
@@ -431,6 +450,27 @@ declare const VERSION: {
431
450
  readonly TURBO_VERSION: "2.8.3";
432
451
  };
433
452
 
453
+ /**
454
+ * Keys of the VERSION object in versions.ts.
455
+ */
456
+ type VersionKey = keyof typeof VERSION;
457
+ /**
458
+ * Mapping of VERSION keys that are backed by an npm package and eligible
459
+ * for auto-update. Only these keys should be updated by version-update
460
+ * automation; others (e.g. NODE_WORKFLOWS) are skipped.
461
+ *
462
+ * @see {@link VERSION_KEYS_SKIP} for keys that must not be auto-updated.
463
+ */
464
+ declare const VERSION_NPM_PACKAGES: ReadonlyArray<{
465
+ key: VersionKey;
466
+ npmPackage: string;
467
+ }>;
468
+ /**
469
+ * VERSION keys that are not backed by npm and must be skipped by
470
+ * auto-update (e.g. runtime versions like Node.js).
471
+ */
472
+ declare const VERSION_KEYS_SKIP: ReadonlyArray<VersionKey>;
473
+
434
474
  /**
435
475
  * The FQNs for the base classes and options used by Jsii.
436
476
  *
@@ -1393,5 +1433,5 @@ declare class AwsDeployWorkflow extends Component {
1393
1433
  preSynthesize(): void;
1394
1434
  }
1395
1435
 
1396
- export { AwsDeployWorkflow, AwsDeploymentConfig, AwsDeploymentTarget, JsiiFaker, MIMIMUM_RELEASE_AGE, MonorepoProject, PROD_DEPLOY_NAME, PnpmWorkspace, ROOT_CI_TASK_NAME, ROOT_TURBO_TASK_NAME, ResetTask, TurboRepo, TurboRepoTask, TypeScriptConfig, TypeScriptProject, VERSION, VSCodeConfig };
1397
- export type { AwsAccount, AwsDeploymentTargetOptions, AwsLocalDeploymentConfig, AwsOrganization, AwsRegion, CiDeploymentConfig, ClassTypeOptions, DeployWorkflowOptions, GitBranch, IDependencyResolver, MonorepoProjectOptions, PnpmWorkspaceOptions, RemoteCacheOptions, ResetTaskOptions, TurboRepoOptions, TurboRepoTaskOptions, TypeScriptProjectOptions };
1436
+ export { AwsDeployWorkflow, AwsDeploymentConfig, AwsDeploymentTarget, JsiiFaker, MIMIMUM_RELEASE_AGE, MonorepoProject, PROD_DEPLOY_NAME, PnpmWorkspace, ROOT_CI_TASK_NAME, ROOT_TURBO_TASK_NAME, ResetTask, TurboRepo, TurboRepoTask, TypeScriptConfig, TypeScriptProject, VERSION, VERSION_KEYS_SKIP, VERSION_NPM_PACKAGES, VSCodeConfig, getLatestEligibleVersion };
1437
+ export type { AwsAccount, AwsDeploymentTargetOptions, AwsLocalDeploymentConfig, AwsOrganization, AwsRegion, CiDeploymentConfig, ClassTypeOptions, DeployWorkflowOptions, GitBranch, IDependencyResolver, MonorepoProjectOptions, PnpmWorkspaceOptions, RemoteCacheOptions, ResetTaskOptions, TurboRepoOptions, TurboRepoTaskOptions, TypeScriptProjectOptions, VersionKey };
package/lib/index.js CHANGED
@@ -191,7 +191,10 @@ __export(index_exports, {
191
191
  TypeScriptConfig: () => TypeScriptConfig,
192
192
  TypeScriptProject: () => TypeScriptProject,
193
193
  VERSION: () => VERSION,
194
- VSCodeConfig: () => VSCodeConfig
194
+ VERSION_KEYS_SKIP: () => VERSION_KEYS_SKIP,
195
+ VERSION_NPM_PACKAGES: () => VERSION_NPM_PACKAGES,
196
+ VSCodeConfig: () => VSCodeConfig,
197
+ getLatestEligibleVersion: () => getLatestEligibleVersion
195
198
  });
196
199
  module.exports = __toCommonJS(index_exports);
197
200
 
@@ -667,6 +670,99 @@ var AwsDeploymentTarget = class _AwsDeploymentTarget extends import_projen2.Comp
667
670
  }
668
671
  };
669
672
 
673
+ // src/latest-eligible-version.ts
674
+ var NPM_REGISTRY = "https://registry.npmjs.org";
675
+ function isPrerelease(version) {
676
+ const v = version.replace(/^v/, "");
677
+ return /^\d+\.\d+\.\d+-/.test(v);
678
+ }
679
+ function compareVersions(a, b) {
680
+ const parse = (v) => {
681
+ const parts = v.replace(/^v/, "").split(/[-+]/)[0].split(".");
682
+ return parts.map((p) => {
683
+ const n = parseInt(p, 10);
684
+ return Number.isNaN(n) ? 0 : n;
685
+ });
686
+ };
687
+ const pa = parse(a);
688
+ const pb = parse(b);
689
+ const len = Math.max(pa.length, pb.length);
690
+ for (let i = 0; i < len; i++) {
691
+ const na = pa[i] ?? 0;
692
+ const nb = pb[i] ?? 0;
693
+ if (na !== nb) return na - nb;
694
+ }
695
+ return 0;
696
+ }
697
+ async function getLatestEligibleVersion(packageName, minimumReleaseAgeMinutes) {
698
+ const url = `${NPM_REGISTRY}/${encodeURIComponent(packageName)}`;
699
+ let res;
700
+ try {
701
+ res = await fetch(url, {
702
+ headers: { Accept: "application/json" }
703
+ });
704
+ } catch {
705
+ return null;
706
+ }
707
+ if (!res.ok) return null;
708
+ let data;
709
+ try {
710
+ data = await res.json();
711
+ } catch {
712
+ return null;
713
+ }
714
+ const time = data.time;
715
+ if (!time || typeof time !== "object") return null;
716
+ const nowMs = Date.now();
717
+ const minAgeMs = minimumReleaseAgeMinutes * 60 * 1e3;
718
+ const distTagLatest = data["dist-tags"]?.latest;
719
+ if (distTagLatest && !isPrerelease(distTagLatest)) {
720
+ const publishedAtStr = time[distTagLatest];
721
+ if (typeof publishedAtStr === "string") {
722
+ const publishedAt = Date.parse(publishedAtStr);
723
+ if (!Number.isNaN(publishedAt) && nowMs - publishedAt >= minAgeMs) {
724
+ return distTagLatest;
725
+ }
726
+ } else {
727
+ return distTagLatest;
728
+ }
729
+ }
730
+ const versionTimestamps = [];
731
+ for (const [key, value] of Object.entries(time)) {
732
+ if (key === "created" || key === "modified" || typeof value !== "string") {
733
+ continue;
734
+ }
735
+ if (isPrerelease(key)) continue;
736
+ const publishedAt = Date.parse(value);
737
+ if (Number.isNaN(publishedAt)) continue;
738
+ const ageMs = nowMs - publishedAt;
739
+ if (ageMs >= minAgeMs) {
740
+ versionTimestamps.push({ version: key, publishedAt });
741
+ }
742
+ }
743
+ if (versionTimestamps.length === 0) return null;
744
+ let candidates = versionTimestamps;
745
+ if (distTagLatest && !isPrerelease(distTagLatest)) {
746
+ candidates = versionTimestamps.filter(
747
+ (e) => compareVersions(e.version, distTagLatest) <= 0
748
+ );
749
+ }
750
+ if (candidates.length === 0) return null;
751
+ candidates.sort((a, b) => compareVersions(b.version, a.version));
752
+ return candidates[0].version;
753
+ }
754
+
755
+ // src/version-package-map.ts
756
+ var VERSION_NPM_PACKAGES = [
757
+ { key: "AWS_CDK_CLI_VERSION", npmPackage: "aws-cdk" },
758
+ { key: "AWS_CDK_LIB_VERSION", npmPackage: "aws-cdk-lib" },
759
+ { key: "AWS_CONSTRUCTS_VERSION", npmPackage: "constructs" },
760
+ { key: "PNPM_VERSION", npmPackage: "pnpm" },
761
+ { key: "PROJEN_VERSION", npmPackage: "projen" },
762
+ { key: "TURBO_VERSION", npmPackage: "turbo" }
763
+ ];
764
+ var VERSION_KEYS_SKIP = ["NODE_WORKFLOWS"];
765
+
670
766
  // src/versions.ts
671
767
  var VERSION = {
672
768
  /**
@@ -790,7 +886,7 @@ var PnpmWorkspace = class _PnpmWorkspace extends import_projen4.Component {
790
886
  super(project);
791
887
  project.tryFindObjectFile("package.json")?.addDeletionOverride("pnpm");
792
888
  this.fileName = options.fileName ?? "pnpm-workspace.yaml";
793
- this.minimumReleaseAge = options.minimumReleaseAge ? options.minimumReleaseAge : MIMIMUM_RELEASE_AGE.ONE_DAY;
889
+ this.minimumReleaseAge = options.minimumReleaseAge ?? MIMIMUM_RELEASE_AGE.ONE_DAY;
794
890
  this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude ? ["@codedrifters/*", ...options.minimumReleaseAgeExclude] : ["@codedrifters/*"];
795
891
  this.onlyBuiltDependencies = options.onlyBuiltDependencies ? options.onlyBuiltDependencies : [];
796
892
  this.ignoredBuiltDependencies = options.ignoredBuiltDependencies ? options.ignoredBuiltDependencies : [];
@@ -1169,7 +1265,7 @@ var MonorepoProject = class extends import_typescript.TypeScriptAppProject {
1169
1265
  depsUpgrade: true,
1170
1266
  depsUpgradeOptions: {
1171
1267
  workflowOptions: {
1172
- schedule: import_javascript2.UpgradeDependenciesSchedule.WEEKLY
1268
+ schedule: import_javascript2.UpgradeDependenciesSchedule.expressions(["0 23 * * *"])
1173
1269
  },
1174
1270
  cooldown: 1
1175
1271
  },
@@ -1625,6 +1721,9 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen9.Componen
1625
1721
  TypeScriptConfig,
1626
1722
  TypeScriptProject,
1627
1723
  VERSION,
1628
- VSCodeConfig
1724
+ VERSION_KEYS_SKIP,
1725
+ VERSION_NPM_PACKAGES,
1726
+ VSCodeConfig,
1727
+ getLatestEligibleVersion
1629
1728
  });
1630
1729
  //# sourceMappingURL=index.js.map