@pipeline-builder/pipeline-data 4.3.10 → 4.3.12

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.
@@ -0,0 +1,199 @@
1
+ /**
2
+ * THE resolver for the managed toolchain (docs/plans/bootstrap-image-versioning.md
3
+ * §2). `pipeline-bootstrap@V` and `cdk-synth@V` are two SYSTEM-ORG plugin rows
4
+ * that share one release version `V`; every path that can resolve a managed
5
+ * name answers from here and nothing else may:
6
+ *
7
+ * release pin given → that release, if it EXISTS (yanked / deprecated /
8
+ * never-promoted still resolve, with a warning; deleted ⇒ 404)
9
+ * else org default → the NEAREST `org_toolchain_default` walking caller → … → root
10
+ * else canary → the NEAREST `toolchain_rollout` membership, served only
11
+ * while it passes the scan + metadata guards
12
+ * else platform → `toolchain_platform_default`
13
+ * else → 409 TOOLCHAIN_NO_DEFAULT (never "highest version", D11)
14
+ *
15
+ * - Reads are ELEVATED (`runWithTenantContext({ isSuperAdmin: true })`, as
16
+ * `versionReferences` does) and touch SYSTEM-ORG plugin rows only: the owner
17
+ * rank of `pluginResolutionOrderBy` is never consulted, so a same-named row in
18
+ * any other org is never a candidate.
19
+ * - Eligibility (D15) is a SET-time rule ({@link isEligibleRelease}); at resolve
20
+ * time a pin / org default only has to exist.
21
+ * - Both halves always come from ONE release (`TOOLCHAIN_PAIR_MISMATCH` otherwise).
22
+ * - The answer carries `resolvedVia` and nothing about any other org: no
23
+ * rollout membership, no ancestor's settings.
24
+ */
25
+ import { AppError, ErrorCode, type GetParentOrgId, type ManagedToolchainPlugin, type PluginToolchain } from '@pipeline-builder/api-core';
26
+ import type { CrudTx } from './crud-service.js';
27
+ import type { ResolutionRefusal } from './plugin-resolution.js';
28
+ import { type OrgToolchainDefault, type Plugin, type ToolchainRelease } from '../database/drizzle-schema.js';
29
+ /** How a resolution chose its release. Never names the org it came from. */
30
+ export type ToolchainResolvedVia = 'pin' | 'org-default' | 'canary' | 'default';
31
+ /** A non-fatal note on a resolved release (synth prints it). */
32
+ export interface ManagedToolchainWarning {
33
+ code: string;
34
+ message: string;
35
+ severity: 'info' | 'warning' | 'error';
36
+ }
37
+ /** One release, both halves. */
38
+ export interface ManagedToolchainResolution {
39
+ releaseVersion: string;
40
+ resolvedVia: ToolchainResolvedVia;
41
+ bootstrap: Plugin;
42
+ synth: Plugin;
43
+ warnings: ManagedToolchainWarning[];
44
+ }
45
+ /** A resolver refusal: `code` is TOOLCHAIN_NO_DEFAULT, NOT_FOUND, TOOLCHAIN_PAIR_MISMATCH or VALIDATION_ERROR. */
46
+ export declare class ManagedToolchainError extends AppError {
47
+ constructor(code: ErrorCode, message: string, details?: Record<string, unknown>);
48
+ }
49
+ /** The caller a resolution runs for. */
50
+ export interface ManagedToolchainCaller {
51
+ orgId: string;
52
+ }
53
+ /** Whether `version` is a release version (`MAJOR.MINOR.PATCH`). */
54
+ export declare function isToolchainReleaseVersion(version: unknown): version is string;
55
+ /** What the resolver reads with: a drizzle transaction (or any drizzle database in tests). */
56
+ export type ToolchainDb = Pick<CrudTx, 'select'>;
57
+ /** How the resolver reads and walks the org tree (injectable for tests). */
58
+ export interface ManagedToolchainDeps {
59
+ /** Run `fn` with ELEVATED reads. */
60
+ read<T>(fn: (db: ToolchainDb) => Promise<T>): Promise<T>;
61
+ /** An org's direct parent, or undefined for a root. Throws when it can't tell. */
62
+ getParent: GetParentOrgId;
63
+ }
64
+ /** Both halves of one release as stored, with the release row. */
65
+ export interface ReleaseHalves {
66
+ releaseVersion: string;
67
+ release: ToolchainRelease | null;
68
+ bootstrap: Plugin | null;
69
+ synth: Plugin | null;
70
+ }
71
+ /** The release row and both SYSTEM-ORG halves of `releaseVersion` (deleted rows excluded). */
72
+ export declare function loadReleaseHalves(db: ToolchainDb, releaseVersion: string): Promise<ReleaseHalves>;
73
+ /**
74
+ * The caller's chain, own org first, lowercased: `[self, parent, …, root]`.
75
+ * The same parent walk as `org-reachability.ts` (platform's
76
+ * `GET /organization/:id/parent`), cycle-safe and capped at `MAX_ORG_DEPTH` like
77
+ * `reporting-retention.ts` — but FAIL-CLOSED: a lookup failure, a cycle or an
78
+ * over-deep chain throws rather than resolving the wrong org's toolchain.
79
+ */
80
+ export declare function toolchainOrgChain(orgId: string, getParent: GetParentOrgId): Promise<string[]>;
81
+ /** Test hook: drop cached parent lookups. */
82
+ export declare function clearToolchainParentCacheForTests(): void;
83
+ /** Test hook: replace the resolver's reads and hierarchy (null restores production). */
84
+ export declare function setManagedToolchainDepsForTests(deps: ManagedToolchainDeps | null): void;
85
+ /** Why a stored release is not LIVE (empty = live: both halves present, active, unyanked, not deprecated). */
86
+ export type ReleaseLifecycleProblem = 'missing' | 'inactive' | 'yanked' | 'deprecated';
87
+ /** Whether both halves are present (the release EXISTS). */
88
+ export declare function releaseExists(h: ReleaseHalves): h is ReleaseHalves & {
89
+ bootstrap: Plugin;
90
+ synth: Plugin;
91
+ };
92
+ export declare function releaseLifecycleProblems(h: ReleaseHalves): ReleaseLifecycleProblem[];
93
+ /**
94
+ * The bootstrap half's toolchain metadata (`pipelineManager`, `awsCdk`, …), or
95
+ * null when it carries no complete, valid one. Upload persists it on the row's
96
+ * `metadata` as flat `toolchain.<field>` keys (api-core `toolchainMetadata`).
97
+ */
98
+ export declare function bootstrapToolchainOf(row: Plugin | null | undefined): PluginToolchain | null;
99
+ /**
100
+ * The §8 candidate guards (pair, scan, metadata) a release fails, as their
101
+ * error codes — empty when it passes. The canary gate and concurrency are the
102
+ * platform-default service's; a canary is served only while this is empty.
103
+ */
104
+ export declare function toolchainCandidateProblems(h: ReleaseHalves): ErrorCode[];
105
+ /** {@link resolveManagedToolchain} with injected reads and hierarchy (tests). */
106
+ export declare function resolveManagedToolchainWith(deps: ManagedToolchainDeps, caller: ManagedToolchainCaller, opts?: {
107
+ releasePin?: string;
108
+ }): Promise<ManagedToolchainResolution>;
109
+ /**
110
+ * Resolve the managed toolchain release for `caller` (see the module doc).
111
+ * Throws {@link ManagedToolchainError}: TOOLCHAIN_NO_DEFAULT (409, no platform
112
+ * default), NOT_FOUND (404, a missing / deleted pin), TOOLCHAIN_PAIR_MISMATCH
113
+ * (500), VALIDATION_ERROR (400, a malformed pin).
114
+ */
115
+ export declare function resolveManagedToolchain(caller: ManagedToolchainCaller, opts?: {
116
+ releasePin?: string;
117
+ }): Promise<ManagedToolchainResolution>;
118
+ /** {@link isEligibleRelease} with injected reads and hierarchy (tests). */
119
+ export declare function isEligibleReleaseWith(deps: ManagedToolchainDeps, orgId: string, releaseVersion: string): Promise<boolean>;
120
+ /**
121
+ * D15: whether `orgId` may SET `releaseVersion` as a pipeline pin or its org
122
+ * default — both halves live (active, unyanked, not deprecated) AND either it
123
+ * has been the platform default or it is the caller's canary (nearest
124
+ * membership on its chain).
125
+ */
126
+ export declare function isEligibleRelease(orgId: string, releaseVersion: string): Promise<boolean>;
127
+ /**
128
+ * What the org-default panel shows a caller about ITS OWN org: never another
129
+ * org's choice, and of the ancestors only which one's default applies.
130
+ */
131
+ export interface OrgToolchainOverview {
132
+ /** The caller's chain, own org first (lowercased). */
133
+ chain: string[];
134
+ /** What the org's UNPINNED pipelines resolve to now. */
135
+ effective: {
136
+ releaseVersion: string;
137
+ resolvedVia: ToolchainResolvedVia;
138
+ warnings: ManagedToolchainWarning[];
139
+ };
140
+ /** The caller org's own `org_toolchain_default` row, if it set one. */
141
+ ownDefault: OrgToolchainDefault | null;
142
+ /** The ancestor whose org default applies, when the org set none of its own. */
143
+ inheritedFrom: {
144
+ orgId: string;
145
+ releaseVersion: string;
146
+ } | null;
147
+ /** The caller's canary release (its NEAREST membership on the chain), or null. */
148
+ canaryRelease: string | null;
149
+ platformDefault: string | null;
150
+ }
151
+ /** {@link readOrgToolchainOverview} with injected reads and hierarchy (tests). */
152
+ export declare function readOrgToolchainOverviewWith(deps: ManagedToolchainDeps, orgId: string): Promise<OrgToolchainOverview>;
153
+ /**
154
+ * The caller org's toolchain overview (elevated reads, the same chain walk and
155
+ * precedence as {@link resolveManagedToolchain}). Throws what the resolver
156
+ * throws — TOOLCHAIN_NO_DEFAULT (409) when nothing resolves at all.
157
+ */
158
+ export declare function readOrgToolchainOverview(orgId: string): Promise<OrgToolchainOverview>;
159
+ /** One release the caller may pin or set (D15), with what the selectors show. */
160
+ export interface EligibleToolchainRelease {
161
+ releaseVersion: string;
162
+ release: ToolchainRelease;
163
+ bootstrap: Plugin;
164
+ synth: Plugin;
165
+ /** THE platform default now. */
166
+ isPlatformDefault: boolean;
167
+ /** The caller's canary release (nearest membership). */
168
+ isCanary: boolean;
169
+ }
170
+ /** {@link listEligibleReleases} with injected reads and hierarchy (tests). */
171
+ export declare function listEligibleReleasesWith(deps: ManagedToolchainDeps, orgId: string): Promise<{
172
+ platformDefault: string | null;
173
+ releases: EligibleToolchainRelease[];
174
+ }>;
175
+ /**
176
+ * Every release `orgId` may SET as a pipeline pin or its org default (D15, the
177
+ * same rule as {@link isEligibleRelease}), newest first. Never another org's
178
+ * data: a canary appears only when it is the caller's own (nearest) membership.
179
+ */
180
+ export declare function listEligibleReleases(orgId: string): Promise<{
181
+ platformDefault: string | null;
182
+ releases: EligibleToolchainRelease[];
183
+ }>;
184
+ /** The resolver's error as the refusal shape step resolution reports (contract check, declared side, facts). */
185
+ export declare function managedToolchainRefusal(err: ManagedToolchainError): ResolutionRefusal;
186
+ /**
187
+ * Resolve ONE managed half for a step: the plugin row plus the resolution, or
188
+ * the refusal. Any non-resolver error (a database or hierarchy failure)
189
+ * propagates.
190
+ */
191
+ export declare function resolveManagedToolchainHalf(caller: ManagedToolchainCaller, name: ManagedToolchainPlugin, opts?: {
192
+ releasePin?: string;
193
+ }): Promise<{
194
+ plugin: Plugin;
195
+ resolution: ManagedToolchainResolution;
196
+ } | {
197
+ refusal: ResolutionRefusal;
198
+ error: ManagedToolchainError;
199
+ }>;