diff --git a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.i18n.yaml index 09b880e946..569f25ed92 100644 --- a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.i18n.yaml @@ -36,5 +36,5 @@ en: 898262f39c0243ae zh: e30f2161f5b669fe /agent-note-client-plugin-package-assets-served-by-url/testing: - en: d2ef6b4e95a9c6fd - zh: 7fcd77971bd20be5 + en: 8b6ce91df7c4c3a5 + zh: b149b71cef5be761 diff --git a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.md b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.md index 130af64945..672d988ba2 100644 --- a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.md +++ b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.md @@ -87,6 +87,6 @@ Images that third-party libraries load themselves (PDF.js fonts, cmaps, wasm, an - [package-assets.client.spec.ts](../../../../packages/client/modules/tests/package-assets.client.spec.ts) composes the real Web server and compares every answer with `fetchBundle()`: headers including the SVG policy, 304 without opening the file, `HEAD`, 405, multi-chunk streaming, stream closing on cancel, a browser cancellation that logs nothing, and 404 for excluded subpaths, missing exports and files, `..`, `%2e%2e`, encoded `..`, an empty path, malformed escapes, decoded `%` and `#`, unsupported types, directories, and inactive packages. - [assets.client.spec.ts](../../../../packages/client/modules/tests/assets.client.spec.ts) covers media types, the revision, emitted names, and references; [client-asset-types.spec.ts](../../../../scripts/client-asset-types.spec.ts) keeps the type root equal to the table. -- [client-bundle-css.spec.ts](../../../../scripts/client-bundle-css.spec.ts) covers emitted names, resolver calls in scripts and stylesheet text, their CommonJS rendering, preserved `url()` forms, each build rejection, the Node face guard, one-shot pruning, and watch rebuilds that keep earlier files; [loader.client.spec.ts](../../../../packages/client/modules/tests/loader.client.spec.ts) covers the default and carrier resolvers. +- [client-bundle-css.spec.ts](../../../../scripts/client-bundle-css.spec.ts) covers emitted names, resolver calls in scripts and stylesheet text, their CommonJS rendering in a complete build, preserved `url()` forms, each build rejection, the Node face guard, one-shot pruning, and watch rebuilds that keep earlier files; [loader.client.spec.ts](../../../../packages/client/modules/tests/loader.client.spec.ts) covers the default and carrier resolvers. - The gate specs reject each invalid manifest or reference form, and [node-half.client.spec.ts](../../../../packages/client/modules/tests/node-half.client.spec.ts) covers declarations, moved exports, and added or removed client declarations after an entry restart, an unchanged restart that publishes nothing and reads no bundle, and a chunk of a package named `@scope/assets`. - [desktop-onboarding.e2e.ts](../../../../apps/web/tests/desktop-onboarding.e2e.ts) and [reasoning-preview.e2e.ts](../../../../apps/web/tests/reasoning-preview.e2e.ts) assert the package-asset URLs and decode the images in a browser; [preview-boot.e2e.ts](../../../../apps/web/tests/preview-boot.e2e.ts) decodes the ui-chat mask the WebWorker preview resolves to a Blob URL, and the runtime's [package-assets.spec.ts](../../../../packages/experimental/webworker-runtime/tests/package-assets.spec.ts) covers the archive and resolver. diff --git a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.zh.md b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.zh.md index 952cdf1d09..48d978a62a 100644 --- a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.zh.md +++ b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.zh.md @@ -87,6 +87,6 @@ plugins/@deepseek-ai/dsh-client-ui-chat/assets/running-whale%402x-06738fa29b2f.p - [package-assets.client.spec.ts](../../../../packages/client/modules/tests/package-assets.client.spec.ts) 组合真实 Web server,并将每个响应与 `fetchBundle()` 比对:包括 SVG 策略在内的响应头、不打开文件的 304、`HEAD`、405、多分片流式发送、取消时关闭流、浏览器取消请求时不记日志,以及以下情况的 404:被排除的子路径、缺少导出或文件、`..`、`%2e%2e`、编码后的 `..`、空路径、错误的转义、解码后的 `%` 和 `#`、不支持的类型、目录和未启用的包。 - [assets.client.spec.ts](../../../../packages/client/modules/tests/assets.client.spec.ts) 覆盖媒体类型、revision、产出文件名和引用;[client-asset-types.spec.ts](../../../../scripts/client-asset-types.spec.ts) 保证类型根与类型表一致。 -- [client-bundle-css.spec.ts](../../../../scripts/client-bundle-css.spec.ts) 覆盖产出文件名、脚本和样式表文本中的解析调用、它们的 CommonJS 渲染、保留的 `url()` 形式、每种构建拒绝、Node face 守卫、一次性构建的清理,以及 watch 重建保留旧文件;[loader.client.spec.ts](../../../../packages/client/modules/tests/loader.client.spec.ts) 覆盖默认解析和载体解析。 +- [client-bundle-css.spec.ts](../../../../scripts/client-bundle-css.spec.ts) 覆盖产出文件名、脚本和样式表文本中的解析调用、完整构建中它们的 CommonJS 渲染、保留的 `url()` 形式、每种构建拒绝、Node face 守卫、一次性构建的清理,以及 watch 重建保留旧文件;[loader.client.spec.ts](../../../../packages/client/modules/tests/loader.client.spec.ts) 覆盖默认解析和载体解析。 - 各门禁的 spec 拒绝每种无效的 manifest 或引用形式;[node-half.client.spec.ts](../../../../packages/client/modules/tests/node-half.client.spec.ts) 覆盖条目重启后的声明更新、导出移动、client 声明的增减、未变化的重启既不发布也不读取 bundle,以及名为 `@scope/assets` 的包的分片。 - [desktop-onboarding.e2e.ts](../../../../apps/web/tests/desktop-onboarding.e2e.ts) 和 [reasoning-preview.e2e.ts](../../../../apps/web/tests/reasoning-preview.e2e.ts) 断言包资源 URL,并在浏览器中解码这些图片;[preview-boot.e2e.ts](../../../../apps/web/tests/preview-boot.e2e.ts) 解码 WebWorker 预览解析为 Blob URL 的 ui-chat 遮罩图,运行时的 [package-assets.spec.ts](../../../../packages/experimental/webworker-runtime/tests/package-assets.spec.ts) 覆盖归档和解析。 diff --git a/packages/client/tsdown.client.ts b/packages/client/tsdown.client.ts index 83f0c67d6b..9810983691 100644 --- a/packages/client/tsdown.client.ts +++ b/packages/client/tsdown.client.ts @@ -517,8 +517,8 @@ const URL_SCHEME = /^[a-z][a-z\d+.-]*:/i * render turns each call into `require.asset(...)`, the module loader's * synchronous asset resolver, which returns the reference unchanged unless its * carrier maps it. The fixed hexadecimal suffix keeps plugin strings that happen - * to contain the shorter prefix out of that rewrite, and, unlike a per-build - * value, keeps the source maps that carry the loaded module text byte-stable. + * to contain the shorter prefix out of that rewrite, and keeps the source maps + * that carry the loaded module text byte-stable across builds. */ const PACKAGE_ASSET_CALL = '__dshPackageAsset_5f8e2c1a9b7d' diff --git a/scripts/client-bundle-css.spec.ts b/scripts/client-bundle-css.spec.ts index cdebabc8ce..3703a36225 100644 --- a/scripts/client-bundle-css.spec.ts +++ b/scripts/client-bundle-css.spec.ts @@ -43,7 +43,7 @@ const WHALE = Uint8Array.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 1 const WHALE_REV = packageAssetRevision(WHALE) const WHALE_URL = `plugins/@deepseek-ai/dsh-client-asset-fixture/assets/whale-${WHALE_REV}.png` -/** The per-build resolver call identifier a compiled module emits before rendering. */ +/** The resolver call identifier a compiled module emits before rendering. */ const RESOLVER_CALL = /__dshPackageAsset_[0-9a-f]{12}(?=\()/u /** Read the resolver call identifier from one compiled module. */ @@ -94,7 +94,7 @@ async function assetPackage( exports: Readonly> = ASSET_EXPORTS, ): Promise { const root = await temporaryDirectory('dsh-client-asset-') - await writeFiles(root, { 'package.json': JSON.stringify({ name: PACKAGE_NAME, exports }), ...files }) + await writeFiles(root, { 'package.json': JSON.stringify({ name: PACKAGE_NAME, type: 'module', exports }), ...files }) return root }