feat: add a CDN media-availability manifest and read it across install surfaces (#1737)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Darius Cepulis
2026-06-25 11:20:45 -07:00
committed by GitHub
co-authored by Claude
parent a74b8c0993
commit f1f2129739
20 changed files with 300 additions and 77 deletions
+15 -1
View File
@@ -5,7 +5,13 @@ import type { Framework } from '../utils/config.js';
import { getConfigValue } from '../utils/config.js';
import { docExistsInAnyFramework, readBundledDoc, readLlmsTxt } from '../utils/docs.js';
import { formatInstallationCode } from '../utils/format.js';
import { mapRawSkin, type PartialInstallFlags, promptFramework, promptInstallOptions } from '../utils/prompts.js';
import {
mapRawSkin,
type PartialInstallFlags,
promptFramework,
promptInstallOptions,
supportsCdnInstall,
} from '../utils/prompts.js';
import { replaceMarker, stripOmitMarkers } from '../utils/replace.js';
interface ParsedFlags {
@@ -177,6 +183,14 @@ export async function handleDocs(flags: ParsedFlags, positionals: string[]): Pro
process.exit(1);
}
// The interactive prompt hides CDN for renderers without a CDN build; guard
// the non-interactive flag path so a `--install-method cdn` request for one
// can't emit a broken snippet.
if (opts.installMethod === 'cdn' && !supportsCdnInstall(opts.renderer)) {
console.error('Error: this source type has no CDN build. Install it with npm, pnpm, yarn, or bun.');
process.exit(1);
}
const generated = formatInstallationCode(opts);
const output = stripOmitMarkers(replaceMarker(markdown, 'installation', generated));
printVersionHeader();
+12
View File
@@ -59,3 +59,15 @@ declare module '@/utils/installation/detect-renderer' {
export function detectRenderer(url: string, useCase: UseCase): DetectionResult | null;
}
declare module '@/utils/installation/cdn-code' {
import type { Renderer, Skin, UseCase } from '@/utils/installation/types';
export function generateCdnCode(useCase: UseCase, skin: Skin, renderer: Renderer): string;
export function rendererSupportsCdn(renderer: Renderer, cdnMediaSubpaths: readonly string[]): boolean;
}
declare module '@/content/cdn-media.json' {
const entries: Array<{ id: string }>;
export default entries;
}
+16 -3
View File
@@ -1,10 +1,18 @@
import * as p from '@clack/prompts';
import cdnMedia from '@/content/cdn-media.json';
import { rendererSupportsCdn } from '@/utils/installation/cdn-code';
import type { InstallationOptions } from '@/utils/installation/codegen';
import { detectRenderer } from '@/utils/installation/detect-renderer';
import type { InstallMethod, Renderer, Skin, UseCase } from '@/utils/installation/types';
import { VALID_RENDERERS } from '@/utils/installation/types';
import type { Framework } from './config.js';
const CDN_MEDIA_SUBPATHS = cdnMedia.map((entry) => entry.id);
export function supportsCdnInstall(renderer: Renderer): boolean {
return rendererSupportsCdn(renderer, CDN_MEDIA_SUBPATHS);
}
export async function promptFramework(): Promise<Framework> {
const value = await p.select({
message: 'Which framework?',
@@ -50,14 +58,19 @@ function skinOptionsForUseCase(useCase: UseCase): Array<{ value: Skin; label: st
];
}
function installMethodOptions(framework: Framework): Array<{ value: InstallMethod; label: string }> {
function installMethodOptions(
framework: Framework,
renderer: Renderer
): Array<{ value: InstallMethod; label: string }> {
const options: Array<{ value: InstallMethod; label: string }> = [
{ value: 'npm', label: 'npm' },
{ value: 'pnpm', label: 'pnpm' },
{ value: 'yarn', label: 'yarn' },
{ value: 'bun', label: 'bun' },
];
if (framework === 'html') {
// CDN is HTML-only, and only when the renderer ships a CDN build — matching
// the install page, which hides the CDN tab for renderers without one.
if (framework === 'html' && supportsCdnInstall(renderer)) {
options.unshift({ value: 'cdn', label: 'CDN' });
}
return options;
@@ -154,7 +167,7 @@ export async function promptInstallOptions(
(await (async () => {
const value = await p.select({
message: 'Install method',
options: installMethodOptions(framework),
options: installMethodOptions(framework, media),
});
if (p.isCancel(value)) process.exit(0);
return value;
+9
View File
@@ -0,0 +1,9 @@
[
{ "id": "dash-video" },
{ "id": "hls-video" },
{ "id": "mux-audio" },
{ "id": "mux-video" },
{ "id": "native-hls-video" },
{ "id": "simple-hls-audio-only" },
{ "id": "simple-hls-video" }
]
@@ -0,0 +1,19 @@
import { describe, expect, it } from 'vitest';
import { supportsCdnInstall } from '../prompts.js';
// Wires the cdn-media manifest into the CLI the same way the install page reads
// the cdnMedia collection. Every current renderer ships (or is covered by) a
// CDN build, so all resolve true; the no-CDN path (e.g. Vimeo) arrives with the
// new rendering engines. `rendererSupportsCdn`'s false branch is unit-tested in
// cdn-code.test.ts.
describe('supportsCdnInstall', () => {
it('returns true for preset renderers (covered by the preset bundle)', () => {
expect(supportsCdnInstall('html5-video')).toBe(true);
expect(supportsCdnInstall('html5-audio')).toBe(true);
expect(supportsCdnInstall('background-video')).toBe(true);
});
it('returns true for hls, whose media bundle ships a CDN build', () => {
expect(supportsCdnInstall('hls')).toBe(true);
});
});