@nestledjs/upgrades 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/package.json +18 -0
- package/src/bin/nestled-update.d.ts +2 -0
- package/src/bin/nestled-update.js +6 -0
- package/src/bin/nestled-update.js.map +1 -0
- package/src/index.d.ts +7 -0
- package/src/index.js +13 -0
- package/src/index.js.map +1 -0
- package/src/lib/apply.d.ts +52 -0
- package/src/lib/apply.js +326 -0
- package/src/lib/apply.js.map +1 -0
- package/src/lib/baseline.d.ts +93 -0
- package/src/lib/baseline.js +115 -0
- package/src/lib/baseline.js.map +1 -0
- package/src/lib/cli.d.ts +1 -0
- package/src/lib/cli.js +192 -0
- package/src/lib/cli.js.map +1 -0
- package/src/lib/feed.d.ts +25 -0
- package/src/lib/feed.js +75 -0
- package/src/lib/feed.js.map +1 -0
- package/src/lib/git.d.ts +40 -0
- package/src/lib/git.js +105 -0
- package/src/lib/git.js.map +1 -0
- package/src/lib/manifest.d.ts +57 -0
- package/src/lib/manifest.js +57 -0
- package/src/lib/manifest.js.map +1 -0
- package/src/lib/pending.d.ts +25 -0
- package/src/lib/pending.js +39 -0
- package/src/lib/pending.js.map +1 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The published upgrade feed. A single manifest lists every release in order,
|
|
3
|
+
* plus a pointer per channel naming the newest release that channel should
|
|
4
|
+
* have. A consumer on channel C applies every release with
|
|
5
|
+
* `baseline < release.id <= channels[C]`.
|
|
6
|
+
*
|
|
7
|
+
* See docs/DISTRIBUTION-SPEC.md in the nestled-upgrader repo for the full model.
|
|
8
|
+
*/
|
|
9
|
+
export type DeliveryType = 'code-patch' | 'package-release' | 'hybrid';
|
|
10
|
+
export interface PackageRelease {
|
|
11
|
+
name: string;
|
|
12
|
+
/** Target version to install; absent (with no versionRange) means pending. */
|
|
13
|
+
targetVersion?: string;
|
|
14
|
+
versionRange?: string;
|
|
15
|
+
/** Optional explicit manifest paths (relative to the project) to update. */
|
|
16
|
+
manifests?: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface UpgradeNote {
|
|
19
|
+
id: string;
|
|
20
|
+
title: string;
|
|
21
|
+
delivery: DeliveryType;
|
|
22
|
+
/** Human/agent-facing description of the change to make. */
|
|
23
|
+
intent: string;
|
|
24
|
+
/** Coarse subsystem tag (auth, billing, database, …) for forked-area gating. */
|
|
25
|
+
area?: string;
|
|
26
|
+
/** Hints only — not an authoritative file list. */
|
|
27
|
+
affectedPaths?: string[];
|
|
28
|
+
/** Repo path of the `.diff` within the template feed, for `code-patch`/`hybrid`. */
|
|
29
|
+
patch?: string;
|
|
30
|
+
/** For `package-release` and `hybrid`. */
|
|
31
|
+
packageReleases?: PackageRelease[];
|
|
32
|
+
}
|
|
33
|
+
export interface Release {
|
|
34
|
+
/** Sortable id, date-based recommended, e.g. "2026.07.1". */
|
|
35
|
+
id: string;
|
|
36
|
+
date?: string;
|
|
37
|
+
title?: string;
|
|
38
|
+
/** nestled-template commit this release corresponds to. */
|
|
39
|
+
templateCommit?: string;
|
|
40
|
+
notes: UpgradeNote[];
|
|
41
|
+
}
|
|
42
|
+
export interface Manifest {
|
|
43
|
+
schemaVersion: number;
|
|
44
|
+
generatedAt?: string;
|
|
45
|
+
/** channel name -> newest release id that channel should have. */
|
|
46
|
+
channels: Record<string, string>;
|
|
47
|
+
releases: Release[];
|
|
48
|
+
}
|
|
49
|
+
export declare const SUPPORTED_SCHEMA_VERSION = 1;
|
|
50
|
+
export declare function parseManifest(text: string): Manifest;
|
|
51
|
+
export declare function loadManifestFromFile(filePath: string): Manifest;
|
|
52
|
+
/**
|
|
53
|
+
* Compare two release ids by numeric segments so that "2026.07.10" sorts after
|
|
54
|
+
* "2026.07.2" (plain string compare would get that wrong). Non-digit runs are
|
|
55
|
+
* treated as separators. Returns -1, 0, or 1.
|
|
56
|
+
*/
|
|
57
|
+
export declare function compareReleaseId(a: string, b: string): number;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUPPORTED_SCHEMA_VERSION = void 0;
|
|
4
|
+
exports.parseManifest = parseManifest;
|
|
5
|
+
exports.loadManifestFromFile = loadManifestFromFile;
|
|
6
|
+
exports.compareReleaseId = compareReleaseId;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const yaml_1 = require("yaml");
|
|
9
|
+
exports.SUPPORTED_SCHEMA_VERSION = 1;
|
|
10
|
+
function parseManifest(text) {
|
|
11
|
+
var _a;
|
|
12
|
+
const raw = (0, yaml_1.parse)(text);
|
|
13
|
+
if (!raw || typeof raw !== 'object') {
|
|
14
|
+
throw new Error('Manifest is empty or not an object.');
|
|
15
|
+
}
|
|
16
|
+
if (raw.schemaVersion !== exports.SUPPORTED_SCHEMA_VERSION) {
|
|
17
|
+
throw new Error(`Unsupported manifest schemaVersion ${String(raw.schemaVersion)} (expected ${exports.SUPPORTED_SCHEMA_VERSION}).`);
|
|
18
|
+
}
|
|
19
|
+
if (!raw.channels || typeof raw.channels !== 'object') {
|
|
20
|
+
throw new Error('Manifest is missing a `channels` map.');
|
|
21
|
+
}
|
|
22
|
+
if (!Array.isArray(raw.releases)) {
|
|
23
|
+
throw new Error('Manifest is missing a `releases` array.');
|
|
24
|
+
}
|
|
25
|
+
for (const release of raw.releases) {
|
|
26
|
+
if (!release || typeof release.id !== 'string') {
|
|
27
|
+
throw new Error('Every release must have a string `id`.');
|
|
28
|
+
}
|
|
29
|
+
if (release.notes != null && !Array.isArray(release.notes)) {
|
|
30
|
+
throw new Error(`Release ${release.id} has a non-array \`notes\`.`);
|
|
31
|
+
}
|
|
32
|
+
release.notes = (_a = release.notes) !== null && _a !== void 0 ? _a : [];
|
|
33
|
+
}
|
|
34
|
+
return raw;
|
|
35
|
+
}
|
|
36
|
+
function loadManifestFromFile(filePath) {
|
|
37
|
+
return parseManifest((0, node_fs_1.readFileSync)(filePath, 'utf8'));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Compare two release ids by numeric segments so that "2026.07.10" sorts after
|
|
41
|
+
* "2026.07.2" (plain string compare would get that wrong). Non-digit runs are
|
|
42
|
+
* treated as separators. Returns -1, 0, or 1.
|
|
43
|
+
*/
|
|
44
|
+
function compareReleaseId(a, b) {
|
|
45
|
+
var _a, _b;
|
|
46
|
+
const segsA = a.split(/[^0-9]+/).filter(Boolean).map(Number);
|
|
47
|
+
const segsB = b.split(/[^0-9]+/).filter(Boolean).map(Number);
|
|
48
|
+
const len = Math.max(segsA.length, segsB.length);
|
|
49
|
+
for (let i = 0; i < len; i++) {
|
|
50
|
+
const x = (_a = segsA[i]) !== null && _a !== void 0 ? _a : 0;
|
|
51
|
+
const y = (_b = segsB[i]) !== null && _b !== void 0 ? _b : 0;
|
|
52
|
+
if (x !== y)
|
|
53
|
+
return x < y ? -1 : 1;
|
|
54
|
+
}
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../upgrades/src/lib/manifest.ts"],"names":[],"mappings":";;;AA2DA,sCA0BC;AAED,oDAEC;AAOD,4CAUC;AA1GD,qCAAuC;AACvC,+BAA6B;AAwDhB,QAAA,wBAAwB,GAAG,CAAC,CAAC;AAE1C,SAAgB,aAAa,CAAC,IAAY;;IACxC,MAAM,GAAG,GAAG,IAAA,YAAK,EAAC,IAAI,CAA6B,CAAC;IACpD,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,GAAG,CAAC,aAAa,KAAK,gCAAwB,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,sCAAsC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,cAAc,gCAAwB,IAAI,CAC1G,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CAAC,WAAW,OAAO,CAAC,EAAE,6BAA6B,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,CAAC,KAAK,GAAG,MAAA,OAAO,CAAC,KAAK,mCAAI,EAAE,CAAC;IACtC,CAAC;IACD,OAAO,GAAe,CAAC;AACzB,CAAC;AAED,SAAgB,oBAAoB,CAAC,QAAgB;IACnD,OAAO,aAAa,CAAC,IAAA,sBAAY,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,CAAS,EAAE,CAAS;;IACnD,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,MAAA,KAAK,CAAC,CAAC,CAAC,mCAAI,CAAC,CAAC;QACxB,MAAM,CAAC,GAAG,MAAA,KAAK,CAAC,CAAC,CAAC,mCAAI,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Manifest, Release, UpgradeNote } from './manifest';
|
|
2
|
+
import { Outcome, UpgradeLog } from './baseline';
|
|
3
|
+
export interface PendingNote extends UpgradeNote {
|
|
4
|
+
releaseId: string;
|
|
5
|
+
/** Prior recorded outcome, if this note was seen before (e.g. `blocked`). */
|
|
6
|
+
status?: Outcome;
|
|
7
|
+
}
|
|
8
|
+
export interface PendingResult {
|
|
9
|
+
channel: string;
|
|
10
|
+
/** The channel pointer from the manifest (undefined if the channel is unknown). */
|
|
11
|
+
ceiling?: string;
|
|
12
|
+
/** The clone's current baseline release (undefined if never initialised). */
|
|
13
|
+
baseline?: string;
|
|
14
|
+
/** Releases in `(baseline, ceiling]`, ascending. */
|
|
15
|
+
releases: Release[];
|
|
16
|
+
/** Flattened notes from those releases that are not already terminal. */
|
|
17
|
+
notes: PendingNote[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Compute what a clone still needs on its channel:
|
|
21
|
+
* pending = releases where baseline < id <= channels[channel]
|
|
22
|
+
* A missing channel pointer means nothing has been published to that channel,
|
|
23
|
+
* so nothing is pending (fail safe, never apply into the unknown).
|
|
24
|
+
*/
|
|
25
|
+
export declare function computePending(manifest: Manifest, log: UpgradeLog): PendingResult;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computePending = computePending;
|
|
4
|
+
const manifest_1 = require("./manifest");
|
|
5
|
+
const baseline_1 = require("./baseline");
|
|
6
|
+
/**
|
|
7
|
+
* Compute what a clone still needs on its channel:
|
|
8
|
+
* pending = releases where baseline < id <= channels[channel]
|
|
9
|
+
* A missing channel pointer means nothing has been published to that channel,
|
|
10
|
+
* so nothing is pending (fail safe, never apply into the unknown).
|
|
11
|
+
*/
|
|
12
|
+
function computePending(manifest, log) {
|
|
13
|
+
var _a, _b, _c, _d, _e;
|
|
14
|
+
const channel = ((_a = log.template) === null || _a === void 0 ? void 0 : _a.channel) || baseline_1.DEFAULT_CHANNEL;
|
|
15
|
+
const ceiling = (_b = manifest.channels) === null || _b === void 0 ? void 0 : _b[channel];
|
|
16
|
+
const baseline = (_c = log.template) === null || _c === void 0 ? void 0 : _c.baselineRelease;
|
|
17
|
+
const applied = (_d = log.upgrades) !== null && _d !== void 0 ? _d : {};
|
|
18
|
+
if (!ceiling) {
|
|
19
|
+
return { channel, ceiling: undefined, baseline, releases: [], notes: [] };
|
|
20
|
+
}
|
|
21
|
+
const releases = manifest.releases
|
|
22
|
+
.filter((release) => {
|
|
23
|
+
const aboveBaseline = !baseline || (0, manifest_1.compareReleaseId)(release.id, baseline) > 0;
|
|
24
|
+
const withinCeiling = (0, manifest_1.compareReleaseId)(release.id, ceiling) <= 0;
|
|
25
|
+
return aboveBaseline && withinCeiling;
|
|
26
|
+
})
|
|
27
|
+
.sort((a, b) => (0, manifest_1.compareReleaseId)(a.id, b.id));
|
|
28
|
+
const notes = [];
|
|
29
|
+
for (const release of releases) {
|
|
30
|
+
for (const note of (_e = release.notes) !== null && _e !== void 0 ? _e : []) {
|
|
31
|
+
const status = applied[note.id];
|
|
32
|
+
if (status && baseline_1.TERMINAL_OUTCOMES.has(status))
|
|
33
|
+
continue;
|
|
34
|
+
notes.push(Object.assign(Object.assign({}, note), { releaseId: release.id, status }));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { channel, ceiling, baseline, releases, notes };
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=pending.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending.js","sourceRoot":"","sources":["../../../../upgrades/src/lib/pending.ts"],"names":[],"mappings":";;AA2BA,wCA4BC;AAvDD,yCAA8E;AAC9E,yCAAqF;AAoBrF;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,QAAkB,EAAE,GAAe;;IAChE,MAAM,OAAO,GAAG,CAAA,MAAA,GAAG,CAAC,QAAQ,0CAAE,OAAO,KAAI,0BAAe,CAAC;IACzD,MAAM,OAAO,GAAG,MAAA,QAAQ,CAAC,QAAQ,0CAAG,OAAO,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAA,GAAG,CAAC,QAAQ,0CAAE,eAAe,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAA,GAAG,CAAC,QAAQ,mCAAI,EAAE,CAAC;IAEnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC5E,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ;SAC/B,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QAClB,MAAM,aAAa,GAAG,CAAC,QAAQ,IAAI,IAAA,2BAAgB,EAAC,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC9E,MAAM,aAAa,GAAG,IAAA,2BAAgB,EAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACjE,OAAO,aAAa,IAAI,aAAa,CAAC;IACxC,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAA,2BAAgB,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEhD,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,MAAA,OAAO,CAAC,KAAK,mCAAI,EAAE,EAAE,CAAC;YACvC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAChC,IAAI,MAAM,IAAI,4BAAiB,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,SAAS;YACtD,KAAK,CAAC,IAAI,iCAAM,IAAI,KAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,IAAG,CAAC;QACzD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AACzD,CAAC"}
|