chore: import upstream snapshot with attribution
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Guard: no subpath export ships raw TypeScript source.
|
||||
*
|
||||
* `emdash` used to expose `./routes/*`, `./api/*`, `./auth/providers/*` (and
|
||||
* more) as raw `./src/*.ts`. `skipLibCheck` does not skip `.ts`, so a strict
|
||||
* consumer's `tsc` type-checked our source and its transitive graph against
|
||||
* their config -- and, because the raw source imported `Database` etc. from
|
||||
* `src` while `emdash/locals` provided the compiled `dist` identity, hit a
|
||||
* dual-package type-identity wall (issue #1053 was one symptom).
|
||||
*
|
||||
* The fix was structural: those subpaths are now compiled to
|
||||
* `dist/*.mjs` + `dist/*.d.mts`, so consumers only ever see declarations
|
||||
* (`skipLibCheck` covers them). This guard keeps it that way: it fails CI if
|
||||
* any subpath export target is a raw `.ts`/`.tsx` file again.
|
||||
*
|
||||
* Documented exception: modules that bridge into `.astro` cannot be compiled
|
||||
* (the consumer's Astro build must process the `.astro`), so they ship as
|
||||
* source by necessity, exactly like the `.astro` files themselves. The
|
||||
* allowlist below names them; `.astro` targets are always fine.
|
||||
*
|
||||
* This replaced an earlier fixture-based consumer-typecheck harness: once raw
|
||||
* source is not shipped, there is no raw-source graph to type-check, so a
|
||||
* static export-shape check is the whole guarantee.
|
||||
*/
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const pkgPath = resolve(repoRoot, "packages/core/package.json");
|
||||
|
||||
/**
|
||||
* Export keys allowed to ship raw source because they bridge a runtime the
|
||||
* consumer supplies and whose own build must process them -- the same class
|
||||
* as the `.astro` targets. Keep this list short and justified.
|
||||
*/
|
||||
const RUNTIME_COUPLED = new Set([
|
||||
"./ui", // src/ui.ts -- re-exports Astro <Image>/<PortableText> components
|
||||
"./auth/providers/github-admin", // .tsx -- admin React + @cloudflare/kumo
|
||||
"./auth/providers/google-admin", // .tsx -- admin React + @cloudflare/kumo
|
||||
]);
|
||||
|
||||
// `.ts`/`.tsx` source, but NOT `.d.ts` declarations (those are the desired
|
||||
// shipping form -- `skipLibCheck` covers them).
|
||||
const RAW_SOURCE = /(?<!\.d)\.tsx?$/;
|
||||
|
||||
/** Walk an exports value (string | conditions object) collecting targets. */
|
||||
function targets(value) {
|
||||
if (typeof value === "string") return [value];
|
||||
if (value && typeof value === "object") return Object.values(value).flatMap(targets);
|
||||
return [];
|
||||
}
|
||||
|
||||
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
||||
const offenders = [];
|
||||
for (const [key, value] of Object.entries(pkg.exports ?? {})) {
|
||||
if (RUNTIME_COUPLED.has(key)) continue;
|
||||
for (const target of targets(value)) {
|
||||
if (RAW_SOURCE.test(target)) offenders.push(`${key} -> ${target}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (offenders.length > 0) {
|
||||
console.error(
|
||||
"[public-source-guard] FAIL -- subpath export(s) ship raw .ts/.tsx source.\n" +
|
||||
"Raw source is type-checked by strict consumers and reintroduces the\n" +
|
||||
"dual-package identity hazard (#1053). Compile these to dist (.mjs +\n" +
|
||||
".d.mts) via tsdown, or -- only if they bridge a consumer-supplied\n" +
|
||||
"runtime -- add the key to RUNTIME_COUPLED with a justification.\n",
|
||||
);
|
||||
for (const o of offenders) console.error(" " + o);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[public-source-guard] OK -- no subpath export ships raw .ts/.tsx ` +
|
||||
`(${RUNTIME_COUPLED.size} documented runtime-coupled exception(s)).`,
|
||||
);
|
||||
Reference in New Issue
Block a user