Files
photo-live/services/api/src/shared/configure-app.ts
T
浅念 8f2c21d25a feat(viewer): embed carousel iframe with visibility pause
P4b Task 4:宿主 loader 以 iframe 载入的轮播页(/embed/:slotToken,裸布局)。

- src/embed/feed.ts:纯函数集——A22 旧响应裁决(dispatch seq + configVersion
  双闸:过期/回看丢弃、等值差分合并、升值全量重置)、照片队列差分(新照片
  追加队尾、缺席淘汰、thumb 签名刷新)、interval/高度夹取、轮询退避;
- src/embed/useEmbedFeed.ts:取数编排(If-None-Match → 304 零处理)、轮询
  (查询 interval 覆盖 → EMBED_POLL_INTERVAL_MS,连续 5 失败 ×5 退避,成功
  归零;404/410 静默 collapse 隐藏自身)、A23 不可见暂停(document 隐藏 +
  IntersectionObserver 滚出视口 + 本地收起;恢复立即校准)、轮播 intervalMs
  切换;__embedPollMs e2e 注入点;
- src/embed/postMessage.ts:上行 resize/collapse(referrer origin 收敛,缺失
  退 '*'——载荷无敏感数据,宿主侧 loader source+origin 双校验)、下行 expand
  (event.source === window.parent 白名单);
- EmbedPage.vue:交叉淡入淡出(仅 thumb 小图省流量)、点击 window.open 单图
  深链(noopener)、计数圆点、「照片即将上线」空态卡、×收起;lang 查询
  (auto→相册 defaultLocale)驱动嵌入词条子集;
- api client:fetchPublicEmbedSlot(304/ETag 分支,不走 apiRequest);
- e2e:宿主夹具页 public/__test__/embed-host.html(仅测试资产)+ embed.spec 7
  用例(轮换/新标签深链/收起记忆/窄屏 sm/轮询增量/换绑重置/空态/幽灵槽);
  helpers 增展示位 admin API 种子 + flushOutbox;
- vitest 18 用例(裁决矩阵/队列差分/夹取/退避/304/可见性状态机)。

配套修正:api CORS exposedHeaders ETag(跨源浏览器可读,304 语义成立);
contracts 新增浏览器安全子路径 ./constants(根出口 re-export internal-sync
的 node:crypto 会打进浏览器包);eslint ignore embed-loader 产物拷贝
(Task 3 起 viewer lint 红,先修)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-20 23:02:07 +08:00

22 lines
1.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// services/api/src/shared/configure-app.ts —— 应用级配置(全局前缀 / CORS /
// 响应头),main-cn.ts 生产引导与 e2e 测试装配共用同一函数:此前 e2e 各 spec
// 手工镜像 setGlobalPrefix,两处漂移无从守护;收敛为单一来源后,e2e 对
// x-powered-by 头的断言才真正落在生产引导路径上(P1a 终审修缮②)。
// 参数类型取 NestExpressApplication:disable() 是 Express 适配器特有方法。
import type { NestExpressApplication } from '@nestjs/platform-express';
import { API_PREFIX } from './constants';
export function configureApp(app: NestExpressApplication): void {
app.setGlobalPrefix(API_PREFIX);
// 隐藏 Express x-powered-by 指纹响应头(终审修缮②,e2e 断言之)。
app.disable('x-powered-by');
const corsOrigins = (process.env.CORS_ORIGINS ?? 'http://localhost:5173')
.split(',')
.map((origin) => origin.trim())
.filter((origin) => origin !== '');
// exposedHeaders:嵌入轮播 iframe(跨源 fetch 公开展示位端点)需读 ETag 响应头
// 维持 If-None-Match 条件请求(P4b Task 4)——CORS 缺省只暴露 simple headers,
// 不加此配置浏览器侧 response.headers.get('etag') 恒为 null(304 语义失效)。
app.enableCors({ origin: corsOrigins, exposedHeaders: ['ETag'] });
}