mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
perf(client): read each tsdown preset's own package manifest
The client tsdown presets found a package's own manifest by name: a glob of every packages/*/*/package.json, parsed until the name matched. tsdown's native config loader imports each package config without module cache, so the module-level cache never hit and all 82 configs repeated the glob (40-125 ms each) synchronously on tsdown's main thread, where it delayed every other package build. It was 34.5% of the client pass's main thread. - clientBundle, staticLinked and clientLibrary take the package directory (import.meta.dirname at every call site) and read <dir>/package.json once; the package name, loader id and externals come from that manifest. - A missing, unreadable or nameless manifest throws an actionable error. - The glob, the name search and the module-level caches are removed. tsdown client pass 12.78 s -> 8.73 s (median of 3 interleaved runs each, -31.7%); all 11,566 lib outputs byte-identical; all 82 configs resolve the same externals and banners. Refs #5852
This commit is contained in:
1 parent
1c6078dca6
commit
e4410b2764
88 files changed
+190
-159
No files matched your search
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-api-gateway', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-api-job-controller',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{ hostPhase: true },
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-api-remotes',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{ hostPhase: true },
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-api-session-controller',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{ hostPhase: true },
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-api-terminal-controller',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{ hostPhase: true },
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-api-workspace-controller',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{ hostPhase: true },
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-api-workspace-files',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{ hostPhase: true },
|
||||
)
|
||||
@@ -143,7 +143,7 @@ If `test:gui` is red on code you did not touch, neither silently fix nor ignore
|
||||
|
||||
Bringing up a new `packages/client/<name>` plugin package (ui-workspace is a complete example; ui-sidebar/ui-user-questions are minimal skeletons):
|
||||
|
||||
1. **Package skeleton**: `package.json` (`@deepseek-ai/dsh-client-<name>`, exports `.`/`./client`/`./src/*`/`./package.json`, `dsh.client` manifest, `files` list), `tsconfig.json` (extends `tsconfig.base.client.json`, one `references` entry per workspace dependency), `tsdown.config.ts` (`clientBundle(id, ['lib/types/index.js'])`), `src/index.ts` (empty node-half apply), `src/css-modules.d.ts` when using CSS Modules, and `README.md` with the Model Experience section.
|
||||
1. **Package skeleton**: `package.json` (`@deepseek-ai/dsh-client-<name>`, exports `.`/`./client`/`./src/*`/`./package.json`, `dsh.client` manifest, `files` list), `tsconfig.json` (extends `tsconfig.base.client.json`, one `references` entry per workspace dependency), `tsdown.config.ts` (`clientBundle(import.meta.dirname, ['lib/types/index.js'])`), `src/index.ts` (empty node-half apply), `src/css-modules.d.ts` when using CSS Modules, and `README.md` with the Model Experience section.
|
||||
2. **Three registration surfaces, all required** (missing any one fails at a different, later point): the `tsconfig.client.json` aggregate `references` entry; a `dsh.client` row in `packages/bundle/web-app/cordis.patch.yml`; a `packages/bundle/web-app/package.json` dependency (profile boots resolve bare row names through the computed runtime resolution, which is installed as an interception on Node's resolvers — a row whose package no manifest declares fails to import). `pnpm-workspace.yaml` already globs `packages/*/*`.
|
||||
3. **dsh.client manifest semantics**: `platform: 'web'` always, and the declaration requires a `./client` export (the scan throws without one); `immediately: true` only for stage-one-prefetch infrastructure rows. `inject` lists package-name dependency edges — they are **informational only** (preflight display, HMR diffing); they do not sequence entry activation or apply order. Activation order is Cordis fiber inject waiting on *services*, nothing else. A non-baseline `external` request sequences its dynamic supplier ahead of the consumer — see [shared modules](#shared-modules-and-the-module-graph).
|
||||
4. **Registering into another package's slot**: apply order is unconstrained, and a business service is not a declaration barrier. Use `ctx.slots.inject(name, () => ctx.slots.register(...))`; it waits on the actual declaration, removes the contribution when that declaration collapses, reruns after redeclaration, and leaves with the caller's plugin fiber. Return a generator yielding each registration when several contributions must install and roll back atomically. A bare `slots.register` into an undeclared slot remains an error; keep service edges only for services the contribution actually reads.
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-connection', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-file-upload', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-hmr', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-locale', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,6 +1,6 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-client-modules',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
)
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-product-analytics', ['lib/types/index.js'], { hostPhase: true })
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'], { hostPhase: true })
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-resources', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-client-shortcuts',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js', 'lib/types/protocol.js'],
|
||||
{ hostPhase: true },
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
import { staticLinked } from '../tsdown.client.ts'
|
||||
|
||||
export default staticLinked(
|
||||
'@deepseek-ai/dsh-client-store',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
)
|
||||
@@ -11,7 +11,7 @@
|
||||
* inputs, including origins recorded by chained source maps.
|
||||
*/
|
||||
import { readFile, stat, utimes } from 'node:fs/promises'
|
||||
import { existsSync, globSync, readFileSync } from 'node:fs'
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { createRequire, isBuiltin } from 'node:module'
|
||||
import { basename, dirname, isAbsolute, relative, resolve as resolvePath, sep } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
@@ -100,22 +100,25 @@ function browserSourcePath(source: string, sourcemapPath: string): string {
|
||||
* the package without lib/index.js and the host Loader cannot import its node
|
||||
* half. The Client build consumes `lib/types` and chains those tsc maps, with
|
||||
* original source content, into the standalone plugin map.
|
||||
* @param id - plugin id (package name), stamped into the __ModuleLoader__.load
|
||||
* handoff and onto the injected style tags.
|
||||
* @param packageDir - the package's own directory, normally the config's
|
||||
* `import.meta.dirname`. Its `package.json` name is the plugin id stamped into
|
||||
* the __ModuleLoader__.load handoff and onto the injected style tags.
|
||||
* @param libEntry - node-half entries.
|
||||
* @param options - phase placement, lib overrides, companion Node configs, and optional per-file Client banner.
|
||||
* @returns ENV-selected tsdown config for the current build face.
|
||||
* @throws {Error} when `<packageDir>/package.json` is unreadable or declares no name.
|
||||
*/
|
||||
export function clientBundle(
|
||||
id: string,
|
||||
packageDir: string,
|
||||
libEntry: readonly string[],
|
||||
options: ClientBundleOptions = {},
|
||||
): BuildFaceConfig {
|
||||
const lib = clientLibraryConfig(id, libEntry, options.lib)
|
||||
const manifest = readPackageManifest(packageDir)
|
||||
const lib = clientLibraryConfig(manifest, libEntry, options.lib)
|
||||
return ({ env }) => {
|
||||
const face = buildFace(env?.DSH_BUILD_FACE)
|
||||
const clientEntry = face === undefined ? 'src/client/index.ts' : 'lib/types/client/index.js'
|
||||
const client = clientConfig(id, clientEntry, options.clientBanner)
|
||||
const client = clientConfig(manifest, clientEntry, options.clientBanner)
|
||||
const node = [lib, ...(options.companions ?? [])]
|
||||
if (face === 'host') return options.hostPhase === true ? node : [SKIP_WORKSPACE_BUILD]
|
||||
if (face === 'client') {
|
||||
@@ -147,13 +150,16 @@ export function clientBundle(
|
||||
* 4. stylesheets ship with the package: a relative `.css` import survives as a
|
||||
* relative external and the sheet is emitted under `lib/` at its
|
||||
* `src`-relative path, so vite stays the only owner of class hashing.
|
||||
* @param id - package name, used in tsdown diagnostics.
|
||||
* @param packageDir - the package's own directory, normally the config's
|
||||
* `import.meta.dirname`; its `package.json` name is used in tsdown diagnostics.
|
||||
* @param libEntry - emitted JavaScript entries consumed from `lib/types`, one
|
||||
* bundle each: a multi-entry build would emit a hash-named shared chunk that
|
||||
* the exact `files` list cannot publish.
|
||||
* @returns ENV-selected tsdown config for the Client build face.
|
||||
* @throws {Error} when `<packageDir>/package.json` is unreadable or declares no name.
|
||||
*/
|
||||
export function staticLinked(id: string, libEntry: readonly string[]): BuildFaceConfig {
|
||||
export function staticLinked(packageDir: string, libEntry: readonly string[]): BuildFaceConfig {
|
||||
const id = readPackageManifest(packageDir).name
|
||||
// Each entry names its own output file, so two entries with the same basename
|
||||
// would overwrite one artifact instead of emitting two.
|
||||
const names = new Set(libEntry.map(entry => basename(entry, '.js')))
|
||||
@@ -177,12 +183,14 @@ export function isStaticLinkedConfig(configs: readonly UserConfig[]): boolean {
|
||||
|
||||
/**
|
||||
* Build a Client-only Node library during the Client pass.
|
||||
* @param id - Package name used in tsdown diagnostics.
|
||||
* @param packageDir - The package's own directory, normally the config's
|
||||
* `import.meta.dirname`; its `package.json` name is used in tsdown diagnostics.
|
||||
* @param libEntry - Emitted JavaScript entries consumed from `lib/types`.
|
||||
* @returns ENV-selected tsdown config for the Client build face.
|
||||
* @throws {Error} when `<packageDir>/package.json` is unreadable or declares no name.
|
||||
*/
|
||||
export function clientLibrary(id: string, libEntry: readonly string[]): BuildFaceConfig {
|
||||
const lib = clientLibraryConfig(id, libEntry)
|
||||
export function clientLibrary(packageDir: string, libEntry: readonly string[]): BuildFaceConfig {
|
||||
const lib = clientLibraryConfig(readPackageManifest(packageDir), libEntry)
|
||||
return clientOnly([lib])
|
||||
}
|
||||
|
||||
@@ -218,14 +226,15 @@ function buildFace(value: unknown): BuildFace {
|
||||
}
|
||||
|
||||
function clientLibraryConfig(
|
||||
id: string,
|
||||
manifest: PackageManifest,
|
||||
libEntry: readonly string[],
|
||||
overrides: UserConfig = {},
|
||||
): UserConfig {
|
||||
let externals: readonly RegExp[] | undefined
|
||||
const isProductionDependency = (specifier: string): boolean =>
|
||||
matchesSpecifier(productionExternals(id), specifier)
|
||||
matchesSpecifier(externals ??= productionExternals(manifest), specifier)
|
||||
return {
|
||||
name: id,
|
||||
name: manifest.name,
|
||||
entry: [...libEntry],
|
||||
outDir: 'lib',
|
||||
format: ['esm'],
|
||||
@@ -330,9 +339,10 @@ function stylesheetAsset(source: string, importer: string): { readonly file: str
|
||||
return { file, fileName: file.slice(boundary + SOURCE_MARKER.length).split(sep).join('/') }
|
||||
}
|
||||
|
||||
/** The manifest fields the build faces read to state their own module edges. */
|
||||
interface WorkspaceManifest {
|
||||
readonly name?: string
|
||||
/** The manifest fields the build faces read to name the package and state its own module edges. */
|
||||
interface PackageManifest {
|
||||
/** Package name: the tsdown config name, the Client loader id, and the diagnostic subject. */
|
||||
readonly name: string
|
||||
/** Sections a real install materializes on disk next to the built package. */
|
||||
readonly dependencies?: Record<string, string>
|
||||
readonly peerDependencies?: Record<string, string>
|
||||
@@ -340,52 +350,44 @@ interface WorkspaceManifest {
|
||||
readonly dsh?: { readonly client?: { readonly external?: unknown } }
|
||||
}
|
||||
|
||||
const manifestCache = new Map<string, WorkspaceManifest>()
|
||||
const productionExternalCache = new Map<string, readonly RegExp[]>()
|
||||
const clientExternalCache = new Map<string, ReadonlySet<string>>()
|
||||
|
||||
/**
|
||||
* Read one workspace package's manifest. Located by package name rather than by
|
||||
* cwd, because tsdown evaluates every package config with the repository root as
|
||||
* `process.cwd()` during a workspace build. Callers read it on the first
|
||||
* resolveId of a build, not while a config is built, so selecting a build face
|
||||
* never touches a manifest.
|
||||
* @param id - package name, as spelled at the preset call site.
|
||||
* Read the manifest of the package whose config calls a preset. The caller
|
||||
* passes its directory because tsdown evaluates every package config with the
|
||||
* repository root as `process.cwd()` during a workspace build.
|
||||
* @param packageDir - the package's own directory.
|
||||
* @returns the parsed manifest.
|
||||
* @throws {Error} when no workspace package declares that name.
|
||||
* @throws {Error} when `package.json` is unreadable, is not JSON, or declares no string name.
|
||||
*/
|
||||
function workspaceManifest(id: string): WorkspaceManifest {
|
||||
const cached = manifestCache.get(id)
|
||||
if (cached !== undefined) return cached
|
||||
for (const manifestPath of globSync('packages/*/*/package.json', { cwd: REPOSITORY_ROOT })) {
|
||||
const manifest = JSON.parse(
|
||||
readFileSync(resolvePath(REPOSITORY_ROOT, manifestPath), 'utf8'),
|
||||
) as WorkspaceManifest
|
||||
if (manifest.name !== id) continue
|
||||
manifestCache.set(id, manifest)
|
||||
return manifest
|
||||
function readPackageManifest(packageDir: string): PackageManifest {
|
||||
const manifestPath = resolvePath(packageDir, 'package.json')
|
||||
let parsed: unknown
|
||||
try {
|
||||
parsed = JSON.parse(readFileSync(manifestPath, 'utf8'))
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`tsdown: cannot read ${manifestPath}; pass the package directory (the import.meta.dirname of its tsdown.config.ts)`,
|
||||
{ cause: error },
|
||||
)
|
||||
}
|
||||
throw new Error(`tsdown: no packages/*/*/package.json declares the name ${id}`)
|
||||
if (typeof parsed !== 'object' || parsed === null || !('name' in parsed) || typeof parsed.name !== 'string') {
|
||||
throw new Error(`tsdown: ${manifestPath} declares no string package name`)
|
||||
}
|
||||
return parsed as PackageManifest
|
||||
}
|
||||
|
||||
/**
|
||||
* External patterns for one package's Node half: its own production sections,
|
||||
* subpaths included.
|
||||
* @param id - package name, as spelled at the preset call site.
|
||||
* @param manifest - the package's own manifest.
|
||||
* @returns one `^name(/|$)` pattern per production dependency, name-sorted.
|
||||
*/
|
||||
function productionExternals(id: string): readonly RegExp[] {
|
||||
const cached = productionExternalCache.get(id)
|
||||
if (cached !== undefined) return cached
|
||||
const manifest = workspaceManifest(id)
|
||||
function productionExternals(manifest: PackageManifest): readonly RegExp[] {
|
||||
const names = new Set([
|
||||
...Object.keys(manifest.dependencies ?? {}),
|
||||
...Object.keys(manifest.peerDependencies ?? {}),
|
||||
...Object.keys(manifest.optionalDependencies ?? {}),
|
||||
])
|
||||
const patterns = [...names].sort().map(name => new RegExp(`^${escapeSpecifier(name)}(/|$)`))
|
||||
productionExternalCache.set(id, patterns)
|
||||
return patterns
|
||||
return [...names].sort().map(name => new RegExp(`^${escapeSpecifier(name)}(/|$)`))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,19 +410,15 @@ export function requestedExternals(
|
||||
* Module-table specifiers one package requests. The shell baseline is implicit
|
||||
* for every dynamic bundle; `dsh.client.external` only adds package-specific
|
||||
* dynamic rows or subpaths.
|
||||
* @param id - package name, as spelled at the preset call site.
|
||||
* @param manifest - the package's own manifest, whose `dsh.client` declaration adds requests.
|
||||
* @returns the baseline plus the package's explicit requests.
|
||||
*/
|
||||
function clientExternals(id: string): ReadonlySet<string> {
|
||||
const cached = clientExternalCache.get(id)
|
||||
if (cached !== undefined) return cached
|
||||
const externals = new Set([
|
||||
function clientExternals(manifest: PackageManifest): ReadonlySet<string> {
|
||||
return new Set([
|
||||
...PLATFORM_MODULES,
|
||||
...PRELOADED_CLIENT_EXTERNALS,
|
||||
...requestedExternals(id, workspaceManifest(id).dsh?.client ?? {}),
|
||||
...requestedExternals(manifest.name, manifest.dsh?.client ?? {}),
|
||||
])
|
||||
clientExternalCache.set(id, externals)
|
||||
return externals
|
||||
}
|
||||
|
||||
/** Escape a package name for literal use inside a RegExp source. */
|
||||
@@ -469,8 +467,10 @@ function asyncChunkRequirePlugin(): TsdownPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
function clientConfig(id: string, entry: string, clientBanner?: (fileName: string) => string | undefined): UserConfig {
|
||||
const isRequested = (specifier: string): boolean => clientExternals(id).has(specifier)
|
||||
function clientConfig(manifest: PackageManifest, entry: string, clientBanner?: (fileName: string) => string | undefined): UserConfig {
|
||||
const id = manifest.name
|
||||
let requested: ReadonlySet<string> | undefined
|
||||
const isRequested = (specifier: string): boolean => (requested ??= clientExternals(manifest)).has(specifier)
|
||||
const isolation = clientInputIsolation(id)
|
||||
return {
|
||||
name: `${id}/client`,
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-agent-preset', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-approval', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,6 +1,6 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-client-ui-attachment',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
)
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-brand-official', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -2,7 +2,7 @@ import { clientBundle } from '../tsdown.client.ts'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const bundle = clientBundle('@deepseek-ai/dsh-client-ui-chat', ['lib/types/index.js'])
|
||||
const bundle = clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
const stylesheet = fileURLToPath(new URL('./src/client/chat/ChatView.module.css', import.meta.url)).replaceAll('\\', '/')
|
||||
const whaleImage = fileURLToPath(new URL('./src/client/chat/running-whale@2x.png', import.meta.url))
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-commands', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-conversation', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-deliverables', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-directory-picker-browse', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-directory-picker-native', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,6 +1,6 @@
|
||||
import { staticLinked } from '../tsdown.client.ts'
|
||||
|
||||
export default staticLinked(
|
||||
'@deepseek-ai/dsh-client-ui-dockkit',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
)
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-goal', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-input-trigger', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-jobs', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-layout', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-message-feedback', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-model-selection', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-open-in-app', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-permission-presets', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-plan', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-plugin-manager', ['lib/types/index.js'], { hostPhase: true })
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'], { hostPhase: true })
|
||||
@@ -1,6 +1,6 @@
|
||||
import { staticLinked } from '../tsdown.client.ts'
|
||||
|
||||
export default staticLinked(
|
||||
'@deepseek-ai/dsh-client-ui-primitives',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
)
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-reference', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-renderer', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-schedule', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-session', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -3,7 +3,7 @@ import { readFile } from 'node:fs/promises'
|
||||
import { basename } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const bundle = clientBundle('@deepseek-ai/dsh-client-ui-settings-account', ['lib/types/index.js'])
|
||||
const bundle = clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
|
||||
export default ((options) => bundle(options).map(config => ({
|
||||
...config,
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-agent-loop', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-general', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-models', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-plugin-inventory', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-plugins', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-session-log', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-shell', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-subagent', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings-web-search', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-settings', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-shortcuts', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-sidebar-browser', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -4,7 +4,7 @@ import { dirname, join } from 'node:path'
|
||||
import { Rolldown, type UserConfig } from 'tsdown'
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
const bundle = clientBundle('@deepseek-ai/dsh-client-ui-sidebar-documentpreview', ['lib/types/index.js'], {
|
||||
const bundle = clientBundle(import.meta.dirname, ['lib/types/index.js'], {
|
||||
clientBanner: fileName => fileName.endsWith('client.pdf.js') ? pdfLicenseBanner()
|
||||
: fileName.endsWith('client.excel.js') ? excelLicenseBanner() : undefined,
|
||||
})
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-sidebar-files', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-sidebar-right', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-sidebar-terminal', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-sidebar', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-skill', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,6 +1,6 @@
|
||||
import { staticLinked } from '../tsdown.client.ts'
|
||||
|
||||
export default staticLinked(
|
||||
'@deepseek-ai/dsh-client-ui-slots',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
)
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-subagent', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-client-ui-theme',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{
|
||||
lib: {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-tool', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-trajectory', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-user-questions', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-workflow-run', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-workspace', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,6 +1,6 @@
|
||||
import { staticLinked } from '../tsdown.client.ts'
|
||||
|
||||
export default staticLinked(
|
||||
'@deepseek-ai/dsh-client-web',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js', 'lib/types/apply-injections.js'],
|
||||
)
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-experimental-client-ui-agent-team', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-experimental-client-ui-claude-code-mods', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-experimental-client-ui-cot-translation', ['lib/types/index.js'], { hostPhase: true })
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'], { hostPhase: true })
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-experimental-client-ui-voice-input', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -21,7 +21,7 @@ const worker: UserConfig = {
|
||||
|
||||
/** Build the Host plugin and Worker during the Host pass, and the dynamic Client plugin during the Client pass. */
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-experimental-inspector',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{
|
||||
hostPhase: true,
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-experimental-session-inspector', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-cordis-client-runner', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-client-ui-cordis', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle(
|
||||
'@deepseek-ai/dsh-session-log-export',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
{ hostPhase: true },
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
import { clientLibrary } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientLibrary(
|
||||
'@deepseek-ai/dsh-client-test-runtime',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
import { clientLibrary } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientLibrary(
|
||||
'@deepseek-ai/dsh-remote-mock',
|
||||
import.meta.dirname,
|
||||
['lib/types/index.js'],
|
||||
)
|
||||
@@ -1,3 +1,3 @@
|
||||
import { clientBundle } from '../../client/tsdown.client.ts'
|
||||
|
||||
export default clientBundle('@deepseek-ai/dsh-typert-registry', ['lib/types/index.js'])
|
||||
export default clientBundle(import.meta.dirname, ['lib/types/index.js'])
|
||||
@@ -232,7 +232,7 @@ describe('client build environment', () => {
|
||||
it('feeds the same build-process value to dynamic tsdown bundles and the Vite shell', async () => {
|
||||
process.env[PROBE_NAME] = 'shared-value'
|
||||
|
||||
const configs = clientBundle('@deepseek-ai/dsh-client-ui-sidebar', [
|
||||
const configs = clientBundle(join(import.meta.dirname, '../packages/client/ui-sidebar'), [
|
||||
'lib/types/index.js',
|
||||
])({ env: { DSH_BUILD_FACE: 'client' } })
|
||||
if (!Array.isArray(configs)) throw new TypeError('client bundle config must be an array')
|
||||
|
||||
@@ -16,7 +16,7 @@ interface CssPlugin {
|
||||
|
||||
function cssPlugin(name: 'dsh-css-modules-inline' | 'dsh-css-global-inline' | 'dsh-css-text-inline'): CssPlugin {
|
||||
const configs = clientBundle(
|
||||
'@deepseek-ai/dsh-client-test',
|
||||
join(import.meta.dirname, '../packages/client/ui-sidebar'),
|
||||
['lib/types/index.js'],
|
||||
)({ env: { DSH_BUILD_FACE: 'client' } })
|
||||
const client = configs.find(config => config.platform === 'browser')
|
||||
|
||||
@@ -6,7 +6,7 @@ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join, relative } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { build, type TsdownBundle, type UserConfig } from 'tsdown'
|
||||
import { build, type Rolldown, type TsdownBundle, type UserConfig } from 'tsdown'
|
||||
import { describe, expect, it, onTestFinished, vi } from 'vitest'
|
||||
import { clientBundle, requestedExternals, staticLinked } from '../packages/client/tsdown.client.ts'
|
||||
|
||||
@@ -35,18 +35,48 @@ interface InputIsolationPlugin {
|
||||
}>) => void
|
||||
}
|
||||
|
||||
function packageDir(packagePath: string): string {
|
||||
return fileURLToPath(new URL(`../packages/${packagePath}`, import.meta.url))
|
||||
}
|
||||
|
||||
/** A representative dynamic bundle using the shared client baseline. */
|
||||
const REQUESTING_PACKAGE = '@deepseek-ai/dsh-client-ui-conversation'
|
||||
const REQUESTING_PACKAGE_DIR = packageDir('client/ui-conversation')
|
||||
|
||||
function clientConfigs(id = REQUESTING_PACKAGE) {
|
||||
return clientBundle(id, ['lib/types/index.js'])(
|
||||
function clientConfigs(dir = REQUESTING_PACKAGE_DIR) {
|
||||
return clientBundle(dir, ['lib/types/index.js'])(
|
||||
{ env: { DSH_BUILD_FACE: 'client' } },
|
||||
).filter(config => config.platform === 'browser')
|
||||
}
|
||||
|
||||
describe('client bundle build faces', () => {
|
||||
it('names both configs and the loader registration after the package directory manifest', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-client-manifest-'))
|
||||
onTestFinished(() => { rmSync(root, { recursive: true, force: true }) })
|
||||
writeFileSync(join(root, 'package.json'), JSON.stringify({ name: '@deepseek-ai/dsh-client-fixture' }))
|
||||
const configs = clientBundle(root, ['lib/types/index.js'])({ env: { DSH_BUILD_FACE: 'client' } })
|
||||
expect(configs.map(config => config.name)).toEqual([
|
||||
'@deepseek-ai/dsh-client-fixture', '@deepseek-ai/dsh-client-fixture/client',
|
||||
])
|
||||
const outputOptions = configs[1]?.outputOptions
|
||||
if (typeof outputOptions !== 'object' || typeof outputOptions.banner !== 'function') {
|
||||
throw new Error('client banner missing')
|
||||
}
|
||||
expect(outputOptions.banner({ isEntry: true, fileName: 'client.js' } as Rolldown.RenderedChunk))
|
||||
.toBe('window.__ModuleLoader__.load({ id: "@deepseek-ai/dsh-client-fixture", factory: (require) => {')
|
||||
})
|
||||
|
||||
it('rejects a package directory without a named manifest', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-client-manifest-'))
|
||||
onTestFinished(() => { rmSync(root, { recursive: true, force: true }) })
|
||||
expect(() => clientBundle(root, ['lib/types/index.js']))
|
||||
.toThrow(/cannot read .*package\.json; pass the package directory/)
|
||||
writeFileSync(join(root, 'package.json'), JSON.stringify({ private: true }))
|
||||
expect(() => staticLinked(root, ['lib/types/index.js'])).toThrow(/declares no string package name/)
|
||||
})
|
||||
|
||||
it('watches source in development and consumes emitted JavaScript in the Client build', () => {
|
||||
const bundle = clientBundle('@deepseek-ai/dsh-client-test', ['lib/types/index.js'])
|
||||
const bundle = clientBundle(REQUESTING_PACKAGE_DIR, ['lib/types/index.js'])
|
||||
const development = bundle({ env: {} }).find(config => config.platform === 'browser')
|
||||
const artifact = bundle({ env: { DSH_BUILD_FACE: 'client' } })
|
||||
.find(config => config.platform === 'browser')
|
||||
@@ -88,8 +118,8 @@ function clientSourceMapPath(packagePath: string): string {
|
||||
return fileURLToPath(new URL(`../packages/${packagePath}/lib/client.js.map`, import.meta.url))
|
||||
}
|
||||
|
||||
function purityResolveId(id = REQUESTING_PACKAGE): ResolveId {
|
||||
const configs = clientConfigs(id)
|
||||
function purityResolveId(dir = REQUESTING_PACKAGE_DIR): ResolveId {
|
||||
const configs = clientConfigs(dir)
|
||||
const plugins = (configs[0] as { plugins: { name: string; resolveId?: unknown }[] }).plugins
|
||||
const gate = plugins.find(p => p.name === 'dsh-client-bundle-purity')
|
||||
if (gate?.resolveId === undefined) throw new Error('purity plugin missing from client config')
|
||||
@@ -173,14 +203,14 @@ describe('client bundle purity gate', () => {
|
||||
})
|
||||
|
||||
it('admits package-specific requests only for the declaring bundle', () => {
|
||||
const requesting = purityResolveId('@deepseek-ai/dsh-api-session-controller')
|
||||
const requesting = purityResolveId(packageDir('api/session-controller'))
|
||||
expect(requesting('@deepseek-ai/dsh-api-gateway/client')).toBeNull()
|
||||
expect(() => resolveId('@deepseek-ai/dsh-api-gateway/client')).toThrow(/purity/)
|
||||
})
|
||||
|
||||
it('externalizes the baseline independently of each package manifest', () => {
|
||||
const requesting = clientConfigs()[0]?.deps as { neverBundle: (specifier: string) => boolean }
|
||||
const plain = clientConfigs('@deepseek-ai/dsh-client-connection')[0]?.deps as {
|
||||
const plain = clientConfigs(packageDir('client/connection'))[0]?.deps as {
|
||||
neverBundle: (specifier: string) => boolean
|
||||
}
|
||||
|
||||
@@ -195,6 +225,7 @@ describe('client bundle purity gate', () => {
|
||||
|
||||
describe('client bundle experimental input isolation', () => {
|
||||
const experimental = '@deepseek-ai/dsh-experimental-client-ui-agent-team'
|
||||
const experimentalDir = packageDir('experimental/client-ui-agent-team')
|
||||
|
||||
function fixture() {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-client-inputs-'))
|
||||
@@ -209,10 +240,10 @@ describe('client bundle experimental input isolation', () => {
|
||||
return { root, owner, entry, prototype }
|
||||
}
|
||||
|
||||
function config(kind: 'static' | 'dynamic', id = REQUESTING_PACKAGE): UserConfig {
|
||||
function config(kind: 'static' | 'dynamic', dir = REQUESTING_PACKAGE_DIR): UserConfig {
|
||||
const configs = kind === 'static'
|
||||
? staticLinked(id, ['lib/types/client/index.js'])({ env: { DSH_BUILD_FACE: 'client' } })
|
||||
: clientConfigs(id)
|
||||
? staticLinked(dir, ['lib/types/client/index.js'])({ env: { DSH_BUILD_FACE: 'client' } })
|
||||
: clientConfigs(dir)
|
||||
const browser = configs.find(config => config.platform === 'browser')
|
||||
if (browser === undefined) throw new Error('client config missing')
|
||||
return browser
|
||||
@@ -277,7 +308,7 @@ describe('client bundle experimental input isolation', () => {
|
||||
writeFileSync(join(root, 'prototype/package.json'), JSON.stringify({ name, type: 'module' }))
|
||||
writeFileSync(entry, `export { marker } from ${JSON.stringify(importPath(entry, prototype))}\n`)
|
||||
await expect(bundle(owner, config(kind))).rejects.toThrow(/client bundle isolation.*experimental/)
|
||||
await expect(bundle(owner, config(kind, name))).resolves.toContain('experimental sentinel')
|
||||
await expect(bundle(owner, config(kind, packageDir('experimental/tool-terminal')))).resolves.toContain('experimental sentinel')
|
||||
})
|
||||
|
||||
it('proves the static library otherwise hides the experimental input in its emitted JavaScript', async () => {
|
||||
@@ -299,7 +330,7 @@ describe('client bundle experimental input isolation', () => {
|
||||
const { owner, entry, prototype } = fixture()
|
||||
writeFileSync(entry, `export { marker } from ${JSON.stringify(importPath(entry, prototype))}\n`)
|
||||
|
||||
await expect(bundle(owner, config(kind, experimental))).resolves.toContain('experimental sentinel')
|
||||
await expect(bundle(owner, config(kind, experimentalDir))).resolves.toContain('experimental sentinel')
|
||||
})
|
||||
|
||||
it('rejects experimental ownership preserved only by an emitted compiler source map', async () => {
|
||||
@@ -421,7 +452,7 @@ describe('client bundle debug artifacts', () => {
|
||||
})
|
||||
|
||||
it('maps first-party sources to their repository package paths', () => {
|
||||
const configs = clientConfigs('@deepseek-ai/dsh-client-ui-goal')
|
||||
const configs = clientConfigs(packageDir('client/ui-goal'))
|
||||
const outputOptions = configs[0]?.outputOptions
|
||||
if (typeof outputOptions !== 'object' || outputOptions === null) throw new Error('client output options missing')
|
||||
const transform = outputOptions.sourcemapPathTransform
|
||||
@@ -434,7 +465,7 @@ describe('client bundle debug artifacts', () => {
|
||||
})
|
||||
|
||||
it('maps dual-face host sources to the host package group', () => {
|
||||
const configs = clientConfigs('@deepseek-ai/dsh-host-directory-picker-native')
|
||||
const configs = clientConfigs(packageDir('host/directory-picker-native'))
|
||||
const outputOptions = configs[0]?.outputOptions
|
||||
if (typeof outputOptions !== 'object' || outputOptions === null) throw new Error('client output options missing')
|
||||
const transform = outputOptions.sourcemapPathTransform
|
||||
@@ -445,7 +476,7 @@ describe('client bundle debug artifacts', () => {
|
||||
})
|
||||
|
||||
it('maps inlined workspace sources to packages and leaves dependencies outside it unchanged', () => {
|
||||
const configs = clientConfigs('@deepseek-ai/dsh-client-connection')
|
||||
const configs = clientConfigs(packageDir('client/connection'))
|
||||
const outputOptions = configs[0]?.outputOptions
|
||||
if (typeof outputOptions !== 'object' || outputOptions === null) throw new Error('client output options missing')
|
||||
const transform = outputOptions.sourcemapPathTransform
|
||||
|
||||
@@ -167,7 +167,7 @@ it('discovers client-preset packages the shell links, excluding loader-delivered
|
||||
await writeFile(join(root, dir, 'package.json'), JSON.stringify(manifest))
|
||||
await writeFile(join(root, dir, 'tsdown.config.ts'), config)
|
||||
}
|
||||
const clientPreset = "import { clientLibrary } from '../tsdown.client.ts'\nexport default clientLibrary('x', [])\n"
|
||||
const clientPreset = "import { clientLibrary } from '../tsdown.client.ts'\nexport default clientLibrary(import.meta.dirname, [])\n"
|
||||
|
||||
// Linked by the compile shell: client preset, no loader-delivered half.
|
||||
await write('packages/client/linked', {}, clientPreset)
|
||||
|
||||
Reference in new issue
Block a user