Files
lambert.liandClaude Opus 4.7 5f88b11a8a feat(file-preview): configurable large file policy with i18n and error reporting
- Add LargeFilePolicy union type ("default" | "off" | PreviewSizePolicyConfig)
  with validatePreviewSizePolicy / resolvePreviewSizePolicy helpers; validator
  rejects Infinity/NaN and inverted thresholds
- LargeFileGate accepts policy / onError / renderBlockedFallback props; all
  UI strings externalized via useLocale (5 new locale fields); block report
  dedup keyed on id+size+name so contract-violating id reuse still re-reports
- PluginPreviewRenderer passes through largeFilePolicy and
  renderLargeFileFallback; unsupported branch now also goes through gate
- downloadSource refactored by source kind (file/blob/arrayBuffer/url);
  caller mimeType overrides response Content-Type; network/HTTP errors
  normalized to PreviewError (REMOTE_CORS_ERROR / REMOTE_HTTP_ERROR)
- Tests cover custom maxBytes, tiered policy, FILE_TOO_LARGE onError,
  custom renderLargeFileFallback; tests pin LocaleProvider value={zhCN}
- Demo app shows 4 policy variants with onError telemetry pattern and
  policy-derived UI label (no hardcoded strings to drift)
- README documents the largeFilePolicy API and user-input safety pattern

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-06 10:50:28 +08:00

46 lines
1.3 KiB
TypeScript

import { defineConfig } from "tsup";
import { promises as fs } from "node:fs";
import path from "node:path";
/**
* Recursively copy non-source side-effect files (CSS) from src/ to dist/
* so consumer bundlers can resolve `import "./styles/Foo.css"` exactly the
* way it appears in the source.
*/
async function copyNonSourceAssets(srcDir: string, destDir: string) {
const entries = await fs.readdir(srcDir, { withFileTypes: true });
for (const entry of entries) {
if (entry.name === "__tests__") continue;
const srcPath = path.join(srcDir, entry.name);
const destPath = path.join(destDir, entry.name);
if (entry.isDirectory()) {
await fs.mkdir(destPath, { recursive: true });
await copyNonSourceAssets(srcPath, destPath);
} else if (entry.name.endsWith(".css")) {
await fs.copyFile(srcPath, destPath);
}
}
}
export default defineConfig({
entry: [
"src/**/*.ts",
"src/**/*.tsx",
"!src/**/*.test.ts",
"!src/**/*.test.tsx",
"!src/**/__tests__/**",
"!src/**/*.d.ts",
],
format: ["esm"],
dts: true,
bundle: false, // preserve module structure — better for code-splitting and CSS side-imports
splitting: false,
sourcemap: true,
clean: true,
target: "es2020",
external: ["react", "react-dom"],
async onSuccess() {
await copyNonSourceAssets("src", "dist");
},
});