Goal
Turn the v2 extension API surface from something described in prose into something CI
checks: a git-tracked API report, plus a mechanical gate against the class of defect
found in #2365.
Depends on #2363 — API Extractor has to be running first. Split out of it so this value
does not hide inside a build-fix issue; the two have different urgency and different
readers.
Why prose is not enough here
#2304 is meant to produce the normative specification of the extension API, and one of
its open contract items is "namespace enumeration" — what each of Common / Main /
Renderer actually provides. Written by hand, that list is stale the first time someone
adds an export.
The audit in #2360 and the gap in #2365 both came out of reading the surface manually.
That does not scale, and more importantly it does not repeat: nothing stops the next
export from reintroducing the same problem.
There is a structural reason this matters more for v2 than it would for a normal library.
Workspace packages are private and inlined into the bundled .d.ts (39 entries; the
runtime half is a four-line shim over globalThis.FreelensExtensionApi). With that model,
a symbol the API namespace does not re-export is unreachable by any means — there is no
package left for an author to install. Completeness of the re-export is therefore a
correctness property of the packaging model, not a convenience.
What API Extractor gives us
1. ae-forgotten-export — the mechanical check for #2365
Reported when an exported API references a declaration that is not itself exported from
the entry point. That is exactly the defect #2365 documents by hand:
| Exported by the API |
Its signature needs |
Nameable by an extension? |
KubeApi |
KubeApiOptions & ExternalKubeApiOptions |
ExternalKubeApiOptions yes, KubeApiOptions no |
PodsApi, NodesApi, … |
DerivedKubeApiOptions |
no |
KubeObjectStore |
KubeObjectStoreOptions |
no |
By default this message goes to the report file rather than the console, so intentional
exceptions stay documented and reviewable instead of being silenced.
2. The .api.md report — a diffable contract
A git-tracked file containing the public API surface. From the API Extractor docs: "The
report file should be tracked by Git, so that changes to an API signature will appear as
diffs when a pull request (PR) is created."
This is the artifact #2304 actually wants. Instead of a hand-maintained namespace
enumeration that drifts, the enumeration is the checked-in file, and any change to it
shows up in review. The rushstack repository gates this with .github/CODEOWNERS so API
changes need a specific approval; worth considering once the report settles.
3. Release tags for the versioning contract
@public / @beta / @internal TSDoc tags plus trimmed rollup variants
(publicTrimmedFilePath, betaTrimmedFilePath) give a concrete mechanism for #2304's
"Versioning & compatibility policy" item — a way to ship something as unstable on purpose
rather than by omission.
Tasks
Risk notes
Depends on #2363. Closes the mechanical half of #2365. Feeds #2304. Carries the
external-import list left over from #2360.
Goal
Turn the v2 extension API surface from something described in prose into something CI
checks: a git-tracked API report, plus a mechanical gate against the class of defect
found in #2365.
Depends on #2363 — API Extractor has to be running first. Split out of it so this value
does not hide inside a build-fix issue; the two have different urgency and different
readers.
Why prose is not enough here
#2304 is meant to produce the normative specification of the extension API, and one of
its open contract items is "namespace enumeration" — what each of
Common/Main/Rendereractually provides. Written by hand, that list is stale the first time someoneadds an export.
The audit in #2360 and the gap in #2365 both came out of reading the surface manually.
That does not scale, and more importantly it does not repeat: nothing stops the next
export from reintroducing the same problem.
There is a structural reason this matters more for v2 than it would for a normal library.
Workspace packages are private and inlined into the bundled
.d.ts(39 entries; theruntime half is a four-line shim over
globalThis.FreelensExtensionApi). With that model,a symbol the API namespace does not re-export is unreachable by any means — there is no
package left for an author to install. Completeness of the re-export is therefore a
correctness property of the packaging model, not a convenience.
What API Extractor gives us
1.
ae-forgotten-export— the mechanical check for #2365Reported when an exported API references a declaration that is not itself exported from
the entry point. That is exactly the defect #2365 documents by hand:
KubeApiKubeApiOptions & ExternalKubeApiOptionsExternalKubeApiOptionsyes,KubeApiOptionsnoPodsApi,NodesApi, …DerivedKubeApiOptionsKubeObjectStoreKubeObjectStoreOptionsBy default this message goes to the report file rather than the console, so intentional
exceptions stay documented and reviewable instead of being silenced.
2. The
.api.mdreport — a diffable contractA git-tracked file containing the public API surface. From the API Extractor docs: "The
report file should be tracked by Git, so that changes to an API signature will appear as
diffs when a pull request (PR) is created."
This is the artifact #2304 actually wants. Instead of a hand-maintained namespace
enumeration that drifts, the enumeration is the checked-in file, and any change to it
shows up in review. The rushstack repository gates this with
.github/CODEOWNERSso APIchanges need a specific approval; worth considering once the report settles.
3. Release tags for the versioning contract
@public/@beta/@internalTSDoc tags plus trimmed rollup variants(
publicTrimmedFilePath,betaTrimmedFilePath) give a concrete mechanism for #2304's"Versioning & compatibility policy" item — a way to ship something as unstable on purpose
rather than by omission.
Tasks
Enable
apiReportand commit the initial.api.md. Expect the first one to belarge; that is the point — it is the first complete enumeration of the surface.
Review the initial report as a deliverable in its own right: it is the first chance
to see everything the API promises in one place, and to remove anything that should
never have been public.
Turn
ae-forgotten-exportinto a build failure (or a reviewed report entry) andresolve the existing occurrences — this closes Re-export the private workspace type surfaces (kube-object, kube-api) through the extension API #2365 mechanically rather than by
inspection.
Wire the report check into CI so a PR that changes the API surface without updating
.api.mdfails.Decide whether to adopt release tags now or defer, and record the decision in Extensions API v2 specification (contracts + v1 to v2 migration howto) #2304.
Feed the resulting enumeration into Extensions API v2 specification (contracts + v1 to v2 migration howto) #2304 instead of hand-writing it.
Record the external-import list of the bundled
extension-api.d.ts— thethird-party packages an extension author is forced to resolve — and paste it into
Extensions API v2 specification (contracts + v1 to v2 migration howto) #2304 as the reference point for its "Third-party bundled libraries" contract item.
This is the complement of the
.api.mdreport, not a subset of it: the reportenumerates what the API exports, while this is what the API imports and
therefore imposes. Prune the @freelensapp/extensions dependency surface before the v2 spec freezes it #2360 pruned that list from 21 catalog entries to 17 but could
only approximate it by grepping the emitted
dist-types/tree, since the bundleddeclaration does not build (@freelensapp/extensions build:dist is broken: TypeScript 7 removed the JS compiler API #2363). Once it does:
Risk notes
Trimming them is a breaking change for extension authors and must ride the
@freelensapp/extensionsmajor announced in React 19 extension-facing break: announce @freelensapp/extensions major + update v2 docs #2301, not a patch.ae-forgotten-exportwill fire on more than the cases catalogued in Re-export the private workspace type surfaces (kube-object, kube-api) through the extension API #2365. Triage beforemaking it a hard failure, or the gate lands red and gets disabled.
becomes a merge-conflict tax people route around.
Depends on #2363. Closes the mechanical half of #2365. Feeds #2304. Carries the
external-import list left over from #2360.