@aiquants/daily-report 0.22.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +222 -0
- package/README.md +791 -113
- package/dist/client.d.mts +35 -149
- package/dist/client.d.ts +35 -149
- package/dist/client.js +4 -6
- package/dist/client.mjs +4 -6
- package/dist/{ids-stream-BnM6L-Sk.d.ts → ids-stream-BR5RSj5u.d.ts} +157 -148
- package/dist/{ids-stream-DCuiaTit.d.mts → ids-stream-DvB2h1dj.d.mts} +157 -148
- package/dist/index.d.mts +29 -9
- package/dist/index.d.ts +29 -9
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/server.d.mts +153 -66
- package/dist/server.d.ts +153 -66
- package/dist/server.js +5 -4
- package/dist/server.mjs +5 -4
- package/dist/styles/daily-report.standalone.css +1 -1
- package/dist/{types-CqgYQgbH.d.mts → types-DkERw8NE.d.mts} +2 -1
- package/dist/{types-CqgYQgbH.d.ts → types-DkERw8NE.d.ts} +2 -1
- package/package.json +31 -14
- package/dist/logger-D3krZrNK.d.mts +0 -15
- package/dist/logger-D3krZrNK.d.ts +0 -15
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@aiquants/daily-report` are documented here.
|
|
4
|
+
|
|
5
|
+
## 0.24.0 (2026-10-03)
|
|
6
|
+
|
|
7
|
+
共有 SSE リーダーを `@aiquants/sse` の `createSharedSource` へ載せ替え、接続の直後に足されたエントリが配られないことのある順序の誤りを直す。
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **共有リーダーを `createSharedSource` へ載せ替え**: `DailyReportSseReader` の参照カウント・状態機械と、状態の遷移を 50 ms 周期で待つ 2 本のループを、
|
|
12
|
+
`@aiquants/sse` の `createSharedSource` (`lingerMs: 0`・`replay: "none"`) へ置き換える。最初の購読者で専用のブロッキングクライアントと `xRead` のループ (run) を
|
|
13
|
+
1 本起動し、最後の解除で即時に止める。停止の最中の購読は次の run が受け持つ。再開位置は購読者へエントリが届いたときだけ進み、停止させた run が読んで
|
|
14
|
+
配れなかったエントリは次の run が読み直す。run の失敗 (クライアントの生成失敗・`xRead` の例外・予期しない切断) は全購読者を切り離して各自の `onError` を呼び、
|
|
15
|
+
次の購読で新しい run を起動する。
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **`DailyReportSseReader.ready()`**: 読み取り位置が具体 ID に固定された時点で解決する Promise を返す (以後にストリームへ足されたエントリは今の購読者全員へ届く)。
|
|
20
|
+
プロセスの最初の run の前と `destroy()` の後だけストリームの末尾を 1 回読み (run の起動と共有)、以後は即時に解決する。末尾を読めないときも `"$"` の縮退のまま
|
|
21
|
+
解決し、拒否しない。
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **接続の直後のエントリの取りこぼし**: プロセス最初の購読では、共有リーダーが位置をストリームの末尾へ非同期に固定する前に `connected` が届いていたため、
|
|
26
|
+
それを見て足されたエントリが固定前の末尾に入り、どの接続にも配られなかった。カーソルの無い接続は `ready()` を待ってから最新 ID を読んで `connected` を書き、
|
|
27
|
+
カーソル経路は `connected` を先に書いたまま catch-up の読取りを `ready()` の後へ回す (catch-up と位置の固定の間に足されたエントリも落とさない)。
|
|
28
|
+
`destroy()` の前に始まった末尾の読取りは、その後の位置を書き換えない。
|
|
29
|
+
|
|
30
|
+
### Breaking
|
|
31
|
+
|
|
32
|
+
- **`subscribe` の `onError` が必須に**: `DailyReportSseReader.subscribe(onEntry, onError)` の `onError` は省略できない。run の失敗は内部の `"error"` イベントでは
|
|
33
|
+
なく各購読者の `onError` へだけ届き、呼ばれた時点で購読は解除済みなので、呼び出し側は接続を閉じてクライアントに開き直させる (同梱の SSE ハンドラはそうしている)。
|
|
34
|
+
購読者が残っていても失敗した run は再起動せず、次の購読が新しい run を起動する。購読より前に読んだエントリは再生しない。`destroy()` は全購読者を通知なしで
|
|
35
|
+
外して run を止め、読み取り位置を初期化する (実行中の `subscribe` は例外になる)。リーダーを自前で差し替えるホストは `ready()` も実装する。
|
|
36
|
+
|
|
37
|
+
## 0.23.0 (2026-10-03)
|
|
38
|
+
|
|
39
|
+
List / DetailList のキーボード操作と画像添付のサムネイル (`?thumbnail=tile`) を加え、両ビューの選択・フォーカス・行の幾何と添付配信の契約を仕上げる。どれも README の該当の節が今の契約を記す。
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- **キーボード操作**: 両ビューで ↑ ↓ Home End PageUp PageDown が選択を移してフォーカスを追わせ、DetailList は行そのものの Enter / Space とクリックでスクロールせずに選ぶ。ビューごとの行カーソルが選択・Tab の止まり先・フォーカスの持ち主・保留中のフォーカス要求を日報 id で持ち、よそにあるフォーカスを奪わない。キーの移動は移動先の描画とフォーカスまでをキーの 1 回の確定の中で終える (描画窓の外の移動先は揃えのスクロールと同じ確定で描く) ので、キーの後にフォーカスの要求は残らない。修飾キー・IME の変換中・入力の領域 (フォームと編集可能要素。行の中の編集フォームのボタンを含む)・15 種の ARIA ウィジェットの内側のキーは扱わない。キーボードで行へ入ったフォーカスは表示領域へ入れ、その間ビューの根要素は `data-daily-report-keyboard-focus` を持つ。一覧はキー操作の説明 `listKeyboardHelp` を `aria-describedby` で参照する。
|
|
44
|
+
- **Tab 順・出口・編集の入口**: Tab 順に入るのは Tab の止まり先の行 (見えているフォーカスの持ち主、次に見えている選択、無ければ見えている先頭行) の操作部品だけで、List を横断する Tab は 3 回。スクロールバーの矢印も止まり先にしない。Ctrl+Home / Ctrl+End は一覧の直前 / 直後の Tab の止まり先 (本物の Shift+Tab / Tab が行く所) へフォーカスを移してブラウザーのスクロールで見せ、その側に止まり先が無ければキーを扱わない (List のデスクトップでは Ctrl+End がリサイズの取っ手へ出る)。自分の日報には削除の手前に編集のボタン (`labels.edit`・`data-detail-edit-button`) が付き、編集へのキーボードの入口になる (タイトルへフォーカスを移し、キャンセルと公開の成功で編集のボタンへ戻す)。編集フォームの送信 (タイトルでの Enter) は遷移も保存もしない。
|
|
45
|
+
- **長押し・フォーカスの持ち主・スクロールの固定**: 長押しは静かなフレームの後の最初の繰り返しを keydown の中でその場で動かし (キーが描画より遅ければフレームを待たない)、フレームの柵の後ろの繰り返しは DOM も幾何も読まずに溜めて、フレームに 1 回の移動として同期的に描く (長押しでないキーは溜めた分を同期的に当ててから、移動先の行から動く)。長押しの間、デスクトップの側面ペインの中身は描き直さない。フォーカスの持ち主は 1 つの規則で決まり (一覧の外のポインターの押下で外れ、一覧の中ではフォーカスの移り変わりだけで変わる)、持ち主の行はフォーカス先の差し替え・作り直し・窓への復帰でフォーカスがどこにも無ければ取り戻し、日報が一覧から消えたら同じ位置の日報へ渡す。一覧が変わっても、先頭に見えている日報を日報 id の錨で同じ位置に留める (CSS Scroll Anchoring の規則)。
|
|
46
|
+
- **見出しと読み上げ**: `config.headingLevel` (2〜5 の整数、既定 3) の日報の見出しと 1 段下の節の見出し、DetailList の見出しの札とメタデータの `dl` / `dt` / `dd` (日付は `<time>`)、行の状態のラベル `rowState` と、描かれている目印 (添付の件数・種別のバッジ) を続ける行の説明。種別は読み込み済みの日報の `sourceType` だけを正とし、行ごとに 1 回解決した値をバッジ・説明・コメントの可否に使う。`SourceTypeConfig.name` はバッジの略語の正式な名前 (`<abbr title>` と読み上げ。空白だけか文字列でなければ描画時に `RangeError`)。見出し語と値の組はどこでも 1 つの部品 (`MetadataField`) の `dt` / `dd` で、値の文字に見出し語を書き込まない (DetailList のメタデータの列の区分と作成区分は別々の組。側面ペインとオーバーレイの先頭は、値が日報の見出し (営業日だけ) の営業日の組と作成者の組)。
|
|
47
|
+
2 つのタブの並びは何を切り替えるかで名前を持つ (ビューの切り替えは新しいラベル `viewTabList`、側面ペインのタブ (本文・関連) は新しいラベル `reportTabList`。営業日だけの日報の見出しは同じ日の日報どうしで同じなので名前に借りない)。ラベルは固有 84 キー・全 91 キー (0.22.1 の固有 81 キーへ `listKeyboardHelp`・`rowState`・`edit`・`attachmentThumbnailUnavailable`・`viewTabList`・`reportTabList` を足し、`overlayDialog`・`overlayBackdrop`・`categoryInfo` を除いた)。
|
|
48
|
+
- **モバイルのオーバーレイと側面ペイン**: オーバーレイはプラットフォームのモーダルな `<dialog>` (`showModal()`。最前面の層に描き、開いている間はホストの表示も含めてダイアログの外を不活性にする。先頭の日報の見出しと作成者の値で「営業日 作成者」と名付けて開くと見出しへフォーカス、Tab の循環、IME の変換中は閉じない Escape、プラットフォームの閉じる要求も同じ閉じる処理を通す。どの閉じ方でも中のフォーカスを外してから `close()` でモーダルを終え、開き直さずに閉じた dialog のまま (`inert`) 滑り出しを描いてカードへフォーカスを戻す。背景は `aria-hidden` の飾りの層 `data-daily-report-overlay-backdrop` で、名前もフォーカスも持たない)。デスクトップの側面ペインは枠 (`data-report-id`・`aria-busy`) をキーと同じ描画で替え、中身 (`data-displayed-report-id`) は `useDeferredValue` で後から描いて表示する日報ごとにちょうど 1 回作り直す (記事タブの巻き戻しは表示した日報だけ)。
|
|
49
|
+
自動既読はペインが留まっている (デスクトップは選択に追いついて `aria-busy` が無い、オーバーレイは開いている)
|
|
50
|
+
間に 500 ms 経った日報だけを既読にし、記事タブの末尾へのスクロールは表示中ユーザー自身のコメントの投稿の後だけ (SSE で届いたコメントでは動かさない)。コメントの削除はゴミ箱のボタンが開閉する確認 (`aria-expanded`・`aria-controls`) で、時間では閉じず、Escape・確認の外へ出るフォーカス・外の押下で取り消し、確定の後は次 (無ければ前) のゴミ箱か節の見出しへフォーカスを移す。
|
|
51
|
+
- **添付サムネイルの配信**: 描画ポート `attachmentThumbnailRenderer` (`{ id, render }`。生成時に形を確かめ、`id` が空白だけなら `RangeError`) と `GET {apiBasePath}/attachment/{token}?thumbnail=tile`。キャッシュ・合流・304 は認可の後、原本と別のレートバケット 2 つ (`If-None-Match` の無い要求は認可の前に生成のトークンを使い、認可の直後に答えた要求も 1/10 を認可の費用として残す。再検証 (`If-None-Match`) は上限の 10 倍の再検証のバケットで払って生成のトークンを握らずに認可を待ち、ETag が一致すれば生成のバケットが空でも 304、一致しなければ認可の直後に生成のトークンを使う。
|
|
52
|
+
初めての表示と再訪は互いを 429 にしない)、待ち行列付きのゲート、段ごとの時間予算 (待ち 30 s・読み取り 30 s・描画 10 s)、調整値 `attachmentThumbnailRateLimitPerMinute` / `attachmentThumbnailConcurrency` / `attachmentThumbnailCacheBytes`、決着しないポートの `read_stuck` / `render_stuck`。
|
|
53
|
+
読み取りの長さを行のサイズと突き合わせ、合わない結論は記録せず ETag の無い `no-store` で返す (`size_mismatch`)。描画の出力はシグネチャとヘッダーの寸法も確かめる。
|
|
54
|
+
- **sharp の描画ポート `createSharpThumbnailRenderer(sharp)`** と構造型 `SharpLike`・結果の型 `DailyReportAttachmentThumbnailOutputMediaType`・展開の予算 `DAILY_REPORT_SHARP_THUMBNAIL_DECODE_BUDGET_BYTES`・作業領域の見積り `predictSharpThumbnailWorkingSetBytes` とその表 `DAILY_REPORT_SHARP_THUMBNAIL_WORKING_SET_MODEL` (server エントリ): ホストの sharp を受け、箱に収めて拡大せず、EXIF の向き・白への平坦化・WebP (品質 75・effort 4)。sharp を起動する前に原本の組み方 (JPEG のフレームヘッダー・PNG のインターレース・WebP のチャンク) を読み、続けてヘッダーを読んで、描画 1 回の作業領域 (組み方の展開器が画像全体のために持つバッファー + libvips の全幅の行 2,048 本 + 4 MiB。107 の配置の実測を下回らない) を見積もる。
|
|
55
|
+
5,000 万画素か見積りが 200,000,000 バイトを超える画像と、組み方の読めない画像は展開せずに `unsupported`。libvips を 1 枚 1 スレッドに固定し、読み込み器をプロセス全体で形式ごとに 1 つ (PNG・JPEG・GIF・WebP。Ultra HDR の JPEG も JPEG の読み込み器が SDR の基本画像を展開する) に絞り、資源の枯渇だけを `failed` にする。id は `sharp.versions` から組む。
|
|
56
|
+
- **添付の格子とタイル**: 列数 1 + ⌊(W + 16) / 256⌋ のコンテナクエリ (長さはどれも px。格子の幅は 1,264px まで)、列幅 t に対して高さ round(2t / 3) の CSS の整数 px の枠 (種類の箱の比。枠ごとの inline-size の容器の中で CSS が `round(nearest, 100cqi * 320 / 480, 1px)` と `aspect-ratio: 480 / 320` から列幅と同じ配置の中で決め、スクリプトは測りも書きもしない。格子のどの行の枠も同じ数の装置の画素で描く。画像の角は枠の切り抜きだけが作る)、`data-thumbnail-state`、ページ全体の読み込み枠 2 本と進み具合 (1,024 URL。読み込めた URL は再表示の最初の確定で描き、その再検証は `load` の前のアンマウントで中断する)。`src` を書くのは表示の状態からの投影だけで、StrictMode と `<Activity>` の再表示でも読み込めた画像が残る。格子の中のファイル名は列幅にちょうど収める (省略記号が拡張子に接する。
|
|
57
|
+
文書ごとに 1 つの `ResizeObserver` が格子そのものを測り、通知の中では記録を読むだけで何も書かず、列幅の変わった格子を次のアニメーションフレームの 1 回の `flushSync` でまとめて収め直す。格子を描いた最初のフレームの名前は CSS の省略で、名前を描ける書体の読み込みでだけ収め直す)。原本は自動取得しない。共有エントリに URL のコーデックと種類の一覧、server エントリに出力の定数とポートの型。
|
|
58
|
+
- **開発者向けの守り**: 公開する入口すべての gzip の予算 (`check:bundle`)、すべてのソースのファイルと `scripts` の下の検査のスクリプトの網羅率の下限 (`coverage-floors.json`。`scripts/ratchet-coverage.mjs` が上げるだけのつめ車で、項目の欠け・古い項目・下限割れで落ちる。100 % に届かない新しいファイルは理由 (`exemption`) を添えた項目でだけ入る。
|
|
59
|
+
どのスクリプトも `scripts/lib/` のモジュールの `main({ packageRoot, argv })` を 2 文で呼ぶ入口で、spec が `main` を同じプロセスで実行し、入口ごとに 1 つの子プロセスの確認を残すので、スクリプトも `src` と同じ下限 100 で測る)、README のコードブロックと `examples/` の突き合わせ、README の API Surface の節と公開名の突き合わせ、仕様書が引用する識別子と `src` の突き合わせ、テスト仕様書が名指す spec のファイルの突き合わせ (名指すファイルが在り、どの spec のファイルも名指され、テストの件数を書かない)、ホスト向けの誤りの部品の外での `RangeError` / `TypeError` の構築の禁止、docstring とコメントの言語の規則のつめ車 (`docstring-baseline.json`。
|
|
60
|
+
ファイルごとに数がちょうど等しく、下がるだけ。`check:docstrings` / `docstrings:ratchet` の `scripts/ratchet-docstrings.mjs`。値の置き換えの検査と同じ 1 つの数のつめ車 `scripts/lib/count-ratchet.mjs` の上に立つ: 項目の無いファイルは 0、古い項目も落とし、`--write` は下げるか消すだけで、終了コードは 0 / 1 / 2)、宣言した Node.js の下限と実行時 API の突き合わせ、パッケージ全体の本番のソースの暗黙の値の置き換えの検査 (別の項目・要素の読み出しや null / undefined 以外の字面への `??` / `||` と `??` の連鎖。`check:no-fallback` / `no-fallback:ratchet` の `scripts/check-no-fallback.mjs`。ファイル・式の字面・受け持つ数 (`occurrences`)・理由を添えた例外のほかは、パッケージの根の `no-fallback-baseline.json` の数とちょうど等しく、下がるだけ。
|
|
61
|
+
宣言と違う数の式に一致する例外も落とす)、公開の前のピアの下限の検査 (`peer-floors.json` と `check:peer-floors`。`workspace:^` が展開する版が下限より古ければ、版を上げる前の `publish:*` と、素の `pnpm publish` も通る `prepublishOnly` が止まる)、配布する CSS の構造の spec (選択子の範囲・線種・フォーカスの表示・拡大縮小・動き・間隔の段と行の高さ・状態の色のコントラスト)。`CHANGELOG.md` を tarball に入れる。
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- **選択とフォーカスは 2 本の経路**: 選択は blue-500 の輪 (強制配色では、行の枠が輪の帯に offset −8 で描く 2px の `Highlight` のアウトライン。枠の角 24 で面と同心)、キーボードフォーカスは offset 4 のアウトライン (操作部品は offset 2)。選択した面は輪の外に影を描かない (選択が影の色を透明 (`shadow-transparent`) にし、休み・ホバー・スクロール中の打ち消しのどの大きさの影も色をその 1 つの変数から読むので、どの規則が勝っても輪の下の隙間は 4 辺ともページの色)。状態は行自身と直下の面 (`data-daily-report-row-surface`) から描き、状態に依る選択子は描く要素自身で終える (キー 1 回で計算し直すのは状態を描く要素だけ)。フォーカスの表示はパッケージのトークンだけで、色を遷移させず、要素を拡大縮小しない (スイッチは実寸の 40 × 24)。スイッチとタブの状態の色もパッケージのトークン (明暗とも 3:1 以上、強制配色ではシステム色。選ばれたタブは下端の 2px の線を持つ)。枠線は線種を宣言し、カード状の面は `CARD_SURFACE_CLASS_NAME` を共有する。
|
|
66
|
+
- **幾何と見た目**: 行の余白 G = 8 と、それに立つ長さ (ホバーの浮き上がり・フォーカスの輪の届く幅・操作列の寄せ・行の枠の角) は CSS の px で書く (輪とアウトラインは根の文字サイズで伸びないので、rem の項があると根が 16px 以外のとき端の行の表示が切れる)。List の行の枠の高さは根の文字サイズ R に従う 1 つの値 P(R) = 2G + 2 × (1 + 15) + 4 + 6.75R = 52px + 6.75rem (整数の px へ切り上げ。根 16px で 160 = `DEFAULT_ITEM_HEIGHT`、カード 144・間隔 16) で、行の枠・VirtualScroll の行の高さ・キーボード操作の行の高さが同じ値を使い、根の文字サイズが変わると先頭に見えている行を留めたまま P を求め直す。間隔は 4 / 8 / 16 の段で、パッケージが書く箱の長さと行の箱 (プレビュー 20・読み物 24) は 4px の格子 (容器に従う添付の格子の列幅と、それから決まる枠の高さだけは例外で、タイルの行を k 段持つ面は k · h(t) (mod 4) だけ格子から外れる)。List のカードは主ボタン (96px 以上) と操作の並びが折り返す。
|
|
67
|
+
側面ペインは一覧の高さの中で G の枠に収まり、そのタブの中身 (記事と相関で 1 つのスクロールの箱) は中身の高さによらずスクロールバーの溝を取る (`scrollbar-gutter: stable`)。中身を切りフォーカスを受ける中身を持つ箱は、操作部品のフォーカスの輪の届く 4px (offset 2 + 幅 2) を自分の縁の内側に取る (`FOCUS_RING_REACH_CLASS_NAME`。ソースの検査が守る)。操作列は始まりが G、終わりが選んだビューの中身の端に揃い、横にはみ出さず折り返す。2 つのタブの並びは 1 つの区切りの操作部品 (角 12・寄せ 4・タブの角 8・高さ 32。ホストの `--radius` に依らず同心)。
|
|
68
|
+
枠線のある面の寄せは枠線と余白の和で数える (カード状の面・誤りの面・閉じるボタンは 1 + 15 = 16、入力欄は 1 + 7 = 8)。角 12 の中の面 (読む面・仮の面・DetailList のメタデータの列とスケルトンの中の面・投稿されたコメント・縁のある札) は寄せがどれも角と同じ 12 で、中身の箱の角が面の角と同心。List のカードの中身 (6.75rem) は、どの根の文字サイズでも 4px 以上の余裕を残してカードに収まる (根 16px で 140 ≤ 144)。仮の面 (`PLACEHOLDER_PANEL_CLASS_NAME`)・内容を読む面 (`READING_PANEL_CLASS_NAME`)・縁のある札 (`BORDERED_PILL_CLASS_NAME`) はトークン 1 つずつ。
|
|
69
|
+
操作ボタンは縮まない 24px の的と 16px の SVG のアイコン (明暗とホバーの地色に 3.59:1 以上)、文字の下限 12px、暗色のスクロールバーの配色。動くのは `motion-safe` の変形と不透明度だけで、スクリプトのスクロールも、タッチやペンで払った後の VirtualScroll の滑走も動きを減らす設定に従う (ビュー自身のウィンドウの設定を読み、設定があれば開始の閾値をどの速さも届かない値にした慣性のオプションを渡す。ドラッグは指に 1 対 1 で追う)。状態を描く面とその祖先は不透明度を動かさない (読み込み中の明滅は面の中の要素が持つ)。DetailList の未読の左の線を外し、未読は既読の切り替えの点と行の状態で示す。
|
|
70
|
+
- **一覧の同一性と描画の量**: List の行は日報 id をキーにし、DetailList は選択が変わったときだけ上端へ揃える (以前は 1 件の挿入で 504 → 79,882,212 px へ飛んだ)。選択は外部ストアで配り、キーの緊急の描画でページの見出し・カードの本体・添付の節を描き直さない (Tab の止まり先が動いて描き直すのは操作部品だけ)。行のフォーカス先の `tabindex` は行カーソルだけが書き (登録の時点と、行の Tab の止まり先が変わった時点。同じ値は書き直さず、行の部品は描かない)、キーの移動は移動先の `tabindex` をフォーカスが着く前に、移動元の `tabindex` をフォーカスが離れた後に書く。フォーカス中の要素の `tabindex` を書かず、書いた後にレイアウトを読まないので、キーが強いるスタイルの計算は `focus()` 自身の 1 回だけ。キー 1 回の確定は 1 回 (行の状態・ホストの選択・スクロールをまとめる) で、描き直すのは移動先と移動元の行の枠・ビュー・制御される選択を持つホスト・スクロールしたときの `VirtualScroll` だけ。
|
|
71
|
+
その確定で窓へ入る行のうち、スクロールの後に見せる行 (ビューポートの行と両側 1 行) の外の行 (先読みの行) は行の要素と枠を埋める面だけを `aria-busy` で描き、本体は確定の後の遷移で描く (次のキーで見せる行へ入れば、そのキーの確定で描く)。行の位置と件数 (`aria-posinset` / `aria-setsize`) はコンテキストで配り、窓より前への挿入・削除と件数の変化で描き直すのは行の枠だけ。
|
|
72
|
+
DetailList の行の高さはビューに 1 つの `ResizeObserver` が小数の px で測り、日報の位置の見当は前後 16 行を確かめてから一覧全体を探す。行の枠は CSS の閉じ込め (List は size・layout・style、DetailList は layout・style。ホバーの影が行の余白 G を越えるので paint は閉じ込めない) を持ち、側面ペインのタブの中身は `contain: strict`。タブの中身は計算済みのスタイルを読まず、スクロールバーのつまみの営業日の吹き出しは自分の置き場から描く (可視範囲の変化とホイールで描き直すのは吹き出しだけ)。
|
|
73
|
+
長押しの流れは keydown ごとに状態を作らない。
|
|
74
|
+
- **添付の節**: 節の見出しとそれで名付ける格子と行の一覧、行の中のリンクは行の Tab 順、ファイル名は拡張子の前に空白の入らない 1 つの名前、目印は 24px の箱と 16px の記号、失敗表示のアイコンは明 4.35:1・暗 5.56:1、サムネイルの地の色は遷移させず、可視判定の `IntersectionObserver` は文書ごとに 1 つ。サムネイルの枠は `contain: strict` の配置の境界で、枠自身のスタイルはマウントの後に変わらない (状態の見た目 (地の色・読み込み待ちの脈動・角丸の切り抜き・縁) は枠いっぱいの絶対配置の地 `daily-report-attachment-thumbnail-skin` が描き、画像と失敗の文言はその中) ので、読み込みで決まる画像の大きさでも脈動の始まりと終わりでも、配置し直すのは枠の中だけ。読み込み待ちの脈動は、読み込みの制御器が気配を見せてよいとした枠 (観測中に見えている枠と、枠を得た読み込みの間の枠。`data-thumbnail-active` を枠の要素へ直接付け外しし、React の確定を作らない) の地だけで、画面の外に先読みで描いた行の枠は脈動しない。
|
|
75
|
+
- **添付配信**: 原本の 405 は `Allow: GET, HEAD` を持ち、JSON のエラー応答は `Cache-Control: no-store`。ログは info / warn / error に分け (error はサーバー自身の失敗だけ)、429 の行はバケットごとに拒否の続きの 1 件目と、次の許可の `rate_limit_suppressed count=<N>` (再検証のバケットは `revalidation_rate_limit_suppressed`) の 1 行だけにする。経路のパラメータ `token` が無いのはホストの経路の設定誤りで、コーデックも DB も呼ばずに `[daily-report]` の例外を投げ、error の行 (`reason=unexpected`) を残して 500 を返す。`Retry-After` (503 の 5 s・429 の 60 s) とレートの窓は、クライアントの再試行の待ちと失敗の記憶と 1 つの共有の値。読み取りポートの `principal` は帰属と監査のためだけで、結果はそれに依存してはならない (要求者ごとの ACL を強制するストレージでは描画ポートを注入しない)。
|
|
76
|
+
- **開発者向け**: 公開エントリは名前で列挙する (`src/public-surface.spec.ts` が固定)。ホスト向けの設定の誤りは 1 つの文面 (`[daily-report] <path> must be <expectation>`。値の拒否は、型の違うポートや関数も含めて末尾に `; got <value>` の付く `RangeError`、知らないキーは知っているキーを並べる `RangeError` (`<path> must be one of "<キー>", …; got "<キー>"`)、欠けた (`undefined` の) 関数とポートは `TypeError`。`RangeError` / `TypeError` を作るのは `src/shared/config-errors.ts` の部品だけ)。スタンドアロンの CSS は spec とテストの補助を走査しない。版ごとの移行の手引きは README からこの CHANGELOG へ移した。
|
|
77
|
+
- **作成者と営業日の出どころ**: List のカードの作成者はサーバーが解決した表示名 `employeeName` だけを読み (`author` へ落ちない)、カードと側面ペイン・オーバーレイの見出しの営業日は一覧の項目の `businessDate` から描く。アクションの API (`useDailyReportActionContext` の `addComment` / `deleteComment` / `toggleStar` / `toggleRead` / `updateReport` / `publishReport` / `deleteReport`) の `businessDate` は読み込んだ日報の `date` の型 (`string | null`。省略可) で、無い値は空文字に置き換えずに送信の項目ごと省く。
|
|
78
|
+
- **日報の詳細のフック**: `useDailyReportDetail` は返すどの項目 (日報・誤り・`isLoading`・`isRefetching`) も日報 id と組の 1 つの記録で持ち、id が変わった最初の描画でもその id の始めの状態 (キャッシュの日報 (期限切れも含む。無ければ営業日の一覧のキャッシュ)・キャッシュが無いときだけ読み込み中・誤り無し) を返す。前の id の日報・誤り・読み込み中を次の id の下で返さず、期限切れのキャッシュの日報は `null` を挟まずに描いてから裏で取り直し、前の id への遅れた書き込みは捨てる。モバイルのオーバーレイは詳細を読まず、中身が自分で読む。
|
|
79
|
+
- **ビューの高さ**: 両ビューの高さはホストの配置が与える場所そのもので、スクリプトは高さを計算も書きもしない。ページの箱からビューの根要素までのどの箱も親の縦の flex の列の残りを埋め (`flex: 1 1 0%`・`min-height: 0`)、ページの下には余白が無いので、ビューの箱はページの下端でちょうど終わり、下端に揃えた最後の面と側面ペインはその G = 8px 上 (上の操作列から最初の面までと同じ)。ビューの根要素は大きさを閉じ込めてはみ出しを切る (`contain: size`・`overflow: clip`。描いた中身は箱にも祖先の大きさにも戻らない)。`VirtualScroll` の `viewportSize` は根要素の境界の箱の高さで、最初の描画の前に 1 回読み、以後は根要素だけを観測する 1 つの `ResizeObserver` で追う (配達の中では DOM を読みも書きもしない) ので、測る順序に依らず 1px 未満の変化にも追い、推測の高さで描かない。空の一覧の文言は一覧の上端に重ねる。
|
|
80
|
+
|
|
81
|
+
### Removed
|
|
82
|
+
|
|
83
|
+
- client の `ITEM_CONTAINER_HEIGHT` / `ITEM_VERTICAL_PADDING` / `resetDailyReportIdsStreamSessionForTesting`、server の `sanitizeMediaType` / `encodeRfc8187` / `asciiFallbackFileName`、ほかに消費側が読み込まない 0.22.1 の公開名 116 (共有 22・client 52・server 42。一覧は Breaking)、ラベル `overlayDialog`・`overlayBackdrop`・`categoryInfo`、設定の廃止キー (`fieldLabels` / `title`) だけの移行先を名指す文面、List のカードの `useTapClick` による選択・`role="button"`・`aria-pressed` / `aria-label`、トグルの `aria-pressed`、DetailList のテスト用ハンドルの `selectItem`、オーバーレイの背景のボタン (移行は Breaking)。
|
|
84
|
+
|
|
85
|
+
### Breaking
|
|
86
|
+
|
|
87
|
+
- ピア `react` / `react-dom` は `>=19` (後始末付きの ref コールバックを使う)、`@aiquants/virtualscroll` は 3.8.0 以降 (`enableArrowButtonTabStops` を使う。下限は `peer-floors.json` に 1 回だけ書き、公開のスクリプトが `workspace:^` の展開する版を確かめる)。server エントリは Node.js 20.3 以降 (`engines.node` は `>=20.3.0`。0.22.1 は `>=18.0.0`): サムネイルの段の締め切りが `AbortSignal.any` で合成する。
|
|
88
|
+
ブラウザーの下限は Chrome 121・Firefox 122・Safari 17.4 で、機能の検出も代わりの経路も持たない: Safari 17.4 より前では出口のキーとオーバーレイの Tab の処理が `TypeError` を投げ (出口のキーはブラウザーの意味のまま、オーバーレイの端の Tab はブラウザーの外枠へ出る)、Chrome 105〜120・Firefox 106〜121 は `visibility: hidden` の要素を止まり先に数え (出口のキーがフォーカスを動かさずに消費される)、`:has()` の無いエンジンでは List のカードに選択とフォーカスの表示が出ない。下限の内側でも、CSS の `round()` を持たない Chrome 121〜124 はタイルの枠の高さの宣言を捨てて `aspect-ratio` だけで端数の高さ (2t / 3) にする (格子の行ごとに 1 装置画素違いうる)。Migration:
|
|
89
|
+
React 19 以降と `@aiquants/virtualscroll` 3.8.0 以降へ上げ、サーバーを Node.js 20.3 以降で動かし、利用者のブラウザーを下限以上にする (下限より古いブラウザーや Node.js を支えるホストは 0.22.x に留まる)。
|
|
90
|
+
- 公開名を整理した。どの入口も名前でだけ公開し、公開するのは消費側 (ホストのアプリ・examples) が読み込むか README が文書にする名前だけ (README の API Surface の節がすべてを載せる)。0.22.1 から外した名前:
|
|
91
|
+
- client: `ITEM_CONTAINER_HEIGHT` / `ITEM_VERTICAL_PADDING` / `resetDailyReportIdsStreamSessionForTesting`、部品の `DailyReportAttachmentList` / `DailyReportCommentForm` / `DailyReportCommentList` / `DailyReportPostedComment` (コメント 1 件の部品。同名の型は共有エントリに残る) / `DailyReportEditForm` / `DailyReportLoading` / `DailyReportLoadError` / `BusinessDayThumbOverlay` / `UnreadIndicator`、フックの `useAnimatedNumber` / `useDynamicViewportHeight` / `useDailyReportErrorSurface`、
|
|
92
|
+
キャッシュと変更の内部 (`DailyReportCache` / `DailyReportDetailResource` / `EMPTY_DETAIL` / `EMPTY_ITEM` / `getCachedReport` / `writeCache` / `updateDailyReportCache` / `deleteDailyReportCache` / `clearDailyReportCache` / `subscribeCacheReady` / `acquireMutationLock` / `releaseMutationLock` / `registerRecentDeletion` / `applyBroadcastReportUpdate` / `applyDailyReportServerUpdates`)、
|
|
93
|
+
ids stream の内部 (`DailyReportIdsStreamClientOptions` / `DailyReportIdsStreamPhase` / `DailyReportIdsStreamState` / `getDailyReportIdsStreamSessionUserKey` / `refreshDailyReportIdsStream` / `retryDailyReportIdsStream` / `upsertDailyReportIdsStreamItem` / `removeDailyReportIdsStreamItem`)、
|
|
94
|
+
調整値 (`CONTENT_DRAG_POINTER_INPUTS` / `DAILY_REPORT_FETCH_DEBOUNCE_MS` / `FAST_SCROLL_INERTIA_OPTIONS` / `FAST_SCROLL_WHEEL_MULTIPLIER` / `MAX_PREVIEW_LINES` / `PREFETCH_LOOKAHEAD` / `PREFETCH_MAX_DATES` / `SCROLL_BAR_WIDTH` / `SSE_INITIAL_CONNECT_DEFER_MS` / `VIRTUAL_SCROLL_OVERSCAN_COUNT` / `WHEEL_RESET_TIMEOUT_MS`)、型の `DailyReportActionContextType` / `DailyReportClientConfig` / `DailyReportDetailListScrollRestore` / `DailyReportHeaderProps` / `DailyReportPageProps` / `UseDailyReportSseConnectionOptions`。
|
|
95
|
+
- 共有: ids stream の内部 (`classifyIdsStreamLine` / `compareIdsStreamOrder` / `computeIdsStreamSnapshotToken` / `findIdsStreamResumeIndex` / `isIdsStreamOrdered` / `upsertInIdsStreamOrder` / `DailyReportIdsStreamCursor` / `DailyReportIdsStreamErrorLine` / `DailyReportIdsStreamLine`)、ログ (`createLogger` / `LogLevel` / `DailyReportLogger`)、表示の整形 (`fallbackText` / `formatBusinessDateDisplay` / `formatToIsoDate` / `parseBusinessDateKeyToDate` / `resolveTodayBusinessDateKey`)、コメントの部品 (`UIComment` / `resolveCommentColorClass`)、`dailyReportAttachmentItemSchema`、
|
|
96
|
+
型の `DailyReportAttachmentState` / `DailyReportSseTerminalEvent`。
|
|
97
|
+
- server: `sanitizeMediaType` / `encodeRfc8187` / `asciiFallbackFileName`、閲覧範囲の内部 (`buildVisibleSourceTypeCondition` / `computeSourceTypeDigest` / `computeViewerScopeDigest` / `deniesEverySourceType` / `isSourceTypeVisible` / `normalizeVisibleSourceTypes` / `VisibleSourceTypeSet`)、認可の資源の種 (`defineDailyReportAuthzResources` / `seedDailyReportAuthzResources` / `AuthzResourceItem`)、`formatDateValue`、
|
|
98
|
+
型の `DailyReportService` / `DailyReportHandlersConfig` / `DailyReportSseReaderConfig` / `SqlResultCacheQueryOptions` / `EpochStore` / `RedisStreamMessage` / `DailyReportRedisClient` / `DailyReportRedisBlockingClient` / `DailyReportEncodeUserId` / `DailyReportResolveUserId` / `DailyReportResolveVisibleSourceTypes` / `DailyReportVisibleSourceTypes` / `DailyReportVisibilityDimensions` / `DailyReportVisibilityResolveContext` / `DailyReportVisibilityResolveReason` / `DailyReportSourceTypeInput` / `DailyReportExternalSource` / `DailyReportIdsSource` / `DailyReportAttachmentBytes` と、
|
|
99
|
+
表と行の型 (`DailyReportHubTable` / `DailyReportInternalTable` / `DailyReportCommentTable` / `DailyReportLabelTable` / `DailyReportHubLabelTable` / `DailyReportUserStatusTable` / `DailyReportAttachmentTable` / `DailyReportUserTable` / `DailyReportHubRow` / `DailyReportInternalRow` / `DailyReportCommentRow` / `DailyReportUserStatusRow`)。
|
|
100
|
+
|
|
101
|
+
Migration: 行の計算は `DEFAULT_ITEM_HEIGHT` (根の文字サイズが 16px のときの List の行の枠の高さ P = 160 = カード 144 + 2 × 8) で行う (List 自身は根の文字サイズから P = 52px + 6.75rem を求め、この値を読まない)。型は公開の名前から引く (`DailyReportServiceConfig["externalSources"]` などの設定のキー、`DailyReportTables["hub"]` などの表、`ReturnType<typeof createDailyReportService>`、`Parameters<typeof createDailyReportHandlers>[0]`、`ReturnType<typeof createEpochStore>`、`ReturnType<typeof useDailyReportConfig>`、`ReturnType<typeof useDailyReportActionContext>`、`ComponentProps<typeof DailyReportPage>`、`DailyReportAttachmentSummary["state"]`、`(typeof DAILY_REPORT_SSE_TERMINAL_EVENTS)[number]`)。
|
|
102
|
+
使っていた部品・整形・HTTP の部品・内部の値は自前に写し、ids stream のセッションはテストの間でモジュールを読み直して分ける (`vi.resetModules()` と動的な import など)。
|
|
103
|
+
- List のカードは `[data-daily-report-card]` の中の本物の `<button data-daily-report-button>` で、選択は `click` だけで起こる。カードとトグルの `aria-pressed` と、DetailList のテスト用ハンドルの `selectItem` を削除し、両ビューのハンドルを同じ形 (`findReportIndex` / `getReportItem` / `getReportIds`) にした。Migration: カードは `button[data-daily-report-button="<id>"]` で探し、選択は `aria-current="true"`・トグルの状態は `title` / `aria-label` で読み、選ぶのは画面の操作 (クリック・キー) で行う。
|
|
104
|
+
- Tab 順: 行の中の操作部品 (★・既読・編集・削除・コメント・添付のリンク) は Tab の止まり先の行でだけ Tab 順に入り、スクロールバーの矢印は止まり先でない。自分の日報の DetailList の行と側面ペインには編集のボタンが 1 つ増え、行の中の `Ctrl+Home` / `Ctrl+End` は一覧の出口になる。Migration: 別の行の部品へ Tab で進んでいた手順は先に矢印キーでその行へ移り、Tab の回数を数えるテストは自分の日報の編集のボタンを足す。
|
|
105
|
+
- 両ビューは見出し (`config.headingLevel`、既定 3) と 1 段下の節の見出し、`dl` を描く。モバイルのオーバーレイは `[data-daily-report-mobile-overlay]` の `<dialog>` そのもの (`showModal()` のモーダルで、`aria-modal` も `z-index` も持たない。開いている間はホストの表示も不活性) で、先頭の日報の見出し (営業日) と作成者の値で名付ける (ラベル `overlayDialog` は削除し、上書きは未知のキーとして `RangeError`)。背景はボタンではなく `aria-hidden` の飾りの層 (`data-daily-report-overlay-backdrop`) で、名前もフォーカスも持たないのでラベル `overlayBackdrop` も削除した (上書きは未知のキーとして `RangeError`)。`DailyReportAttachmentIndicator` は必須の `id` を取る。Migration:
|
|
106
|
+
素の `h3` / `h4` / `dl` を装飾するホストの CSS はビューの外へ絞り、`labels` から `overlayDialog` と `overlayBackdrop` を外し、背景を名前やボタンのロールで探していたテストは `[data-daily-report-overlay-backdrop]` で探し、ダイアログは `dialog[data-daily-report-mobile-overlay]` か `getByRole("dialog")` とダイアログの名前「営業日 作成者」で探し、開いている間はホストの表示を操作できない前提にし、目印を自分で描くなら文書の中で一意の `id` (`useId()` など) を渡す。
|
|
107
|
+
- 見出し語と値は別々の組で、値の文字に見出し語を書き込まない。DetailList のメタデータの列の区分の項目 (見出し語 `categoryInfo`・値「区分: … / 作成区分: …」) は、`category` と `creationCategory` の 2 つの組 (値のあるときだけ) になり、ラベル `categoryInfo` を削除した (上書きは未知のキーとして `RangeError`)。側面ペインとモバイルのオーバーレイの作成者は見出し語と値の組になり、「作成者:」の文字は無い。
|
|
108
|
+
Migration: `labels` から `categoryInfo` を外し、区分や作成者を「区分: 」「作成者:」の文字で探していたテストは `dt` / `dd` の組 (`getByRole("term")` / `getByRole("definition")`) で読む。
|
|
109
|
+
- ビューの高さはホストの CSS 変数もウィンドウの高さも読まない: 0.22.1 はウィンドウの高さから根要素の `--footer-height` / `--header-height` / `--scrollbar-height` を引き、さらに下に 4px の隙間を空け、測れないときは 600px や 240px の推測の高さで描いた。0.23.0 のビューはホストの配置が与える場所を埋め (ページの箱からビューの根要素までどの箱も親の縦の flex の列の残りを埋める)、下の隙間も推測の高さも持たない。Migration:
|
|
110
|
+
`DailyReportPage` (か `DailyReportResolvedContent`) を、高さの決まった縦の flex の列 (`display: flex; flex-direction: column` で、高さが定まるか、最小の高さ (`min-height: 100dvh` など) を持つ列の伸びる項目) の中に置く。フッターは同じ列のページの後に置けばよく、その高さを束ねる変数は要らない。そうした列の外では、ビューは大きさを閉じ込めているので高さが 0 になる。
|
|
111
|
+
- 添付のクエリを厳格に解釈する: `download` は `1` を 1 回だけ受け付け、ほかの値 (`?download=true`・`?download=yes`・空) や繰り返しは 400 (以前は `1` 以外なら原本をインラインで返し、繰り返しは最初の値で決めた)。Migration: URL は `buildDailyReportAttachmentUrl` で組む。
|
|
112
|
+
- 添付の構成はサービスのキー (`attachmentIdCodec` / `readAttachment` / `attachmentMaxBytes`。`createDailyReportHandlers` は受け付けない) になり、サービス (`createDailyReportService` の戻り値) の `attachmentDelivery`・読み取りポートの `options.signal`・`DailyReportAttachmentSummary.hasThumbnail` が必須になった。Migration: キーは `createDailyReportService` / `createDailyReportServer` へ渡し、手書きのサービスには `attachmentDelivery`、要約を組むコードには `hasThumbnail`、ポートを直接呼ぶコードには `signal` を渡す。
|
|
113
|
+
- 生成時の検証とログの水準: 添付の数値設定 6 つの `null`・下限未満・整数でない値は公開のキーを名乗る `RangeError` (`[daily-report] <キー> must be an integer >= <下限>; got <値>`)、組でしか効かないキーの欠けた組み合わせは `[daily-report] <欠けたキー> must be injected when <キー> is given` の `TypeError` になり (以前は黙って効かなかった)、添付配信のログは info / warn / error に分かれて error へ届く行が減った。Migration: 下限以上の整数を渡すかキーを省き、要るポートを注入するか効かないキーを外し、error の行で見張っていた監視は warn の 404 / 413 / 429 / 502 / 503 も見る。
|
|
114
|
+
- 設定の誤りの種別と文面: 関数でない `config.onSessionExpired` (`null`・文字列など) は `TypeError` から、渡された値を示す `RangeError` (`…; got <値>`) になった (欠けた (`undefined` の) ときは今も `TypeError`)。知らない `config` のキーと `labels` のキーは、知っているキーを並べる 1 つの文面 (`[daily-report] config key must be one of "apiBasePath", …; got "<キー>"`・`[daily-report] labels key must be one of …`) になり、廃止キー (`fieldLabels` / `title`) も移行先を名指さずにこの文面で拒否する。素の object でない `labels` は `…; got array` などで値の種類を示す。Migration: 設定の誤りを `instanceof TypeError` だけで捕まえていたコードは `RangeError` も捕まえ、文面を読むなら `[daily-report] <path> must be` の形で読む。
|
|
115
|
+
|
|
116
|
+
## 0.22.1 (2026-09-29)
|
|
117
|
+
|
|
118
|
+
- **文書**: README の `interviewerWithAffiliation` の例の所属名を、英語の列と同じく中立の例示に替えた。
|
|
119
|
+
|
|
120
|
+
## 0.22.0 (2026-09-29)
|
|
121
|
+
|
|
122
|
+
SSE の再接続を `@aiquants/sse` へ任せる契約版。ストリームが黙って止まることも、認証切れで再接続し続けることもなくし、
|
|
123
|
+
カーソル・追いつき・保持範囲の欠落を塞ぐ。
|
|
124
|
+
|
|
125
|
+
- **新機能 — `@aiquants/sse` による再接続**: `useDailyReportSseConnection` は `useReopeningEventSource` の上で動き、
|
|
126
|
+
カーソルを effect の外で保持する (`user` / `onMessage` の再生成で再接続しても受信済みの位置を失わない)。非 200 の後は
|
|
127
|
+
full-jitter で開き直し、名前付き heartbeat が 45 s 途絶えたら閉じて開き直す。健全 open (失敗回数を 0 へ戻す時間) は
|
|
128
|
+
無通信の窓 + heartbeat 1 回分 (60 s)。
|
|
129
|
+
- **新機能 — 終端フレーム**: SSE は未認証を `auth-required`、内部利用者でない場合を `forbidden`、保持範囲より古いか
|
|
130
|
+
不正なカーソルを `resync-required` として、200 の終端フレーム (`event:` より前に `retry: 86400000`) で返す。
|
|
131
|
+
- **新機能 — 追いつきの完全化**: カーソルはヘッダ優先 (`Last-Event-ID`) で読み、1,000 件ずつ全件をページ送りする。
|
|
132
|
+
追いつき中の Fan-Out は溜めて id 順に書き、接続内の id は必ず増える。ページの間に MAXLEN で削られたら
|
|
133
|
+
`resync-required`。ids の初回は `streamAnchor` (スナップショット時点のストリーム id) を最初のカーソルにする。
|
|
134
|
+
- **変わらないもの**: 受信者ごとの絞り込み・可視性・コメントの伏せ字は接続ごとのまま。
|
|
135
|
+
- **破壊的変更 (0.x 枠 — クリーンカットオーバー、互換別名なし)**:
|
|
136
|
+
- `DailyReportPage` / `DailyReportConfigProvider` の `config` と、新しいポート `onSessionExpired` が必須になった
|
|
137
|
+
(パッケージは自分で遷移しない)。移行: ホストが認証切れ時の処理 (例: 1 回だけ再読込) を渡す。
|
|
138
|
+
- `reloadDocument` を削除した。
|
|
139
|
+
- `getDailyReportIdsByExternalId` は `{ items, streamAnchor }` を返す。移行: 配列は `.items` から読む。
|
|
140
|
+
- SSE の 401 / 403 は終端フレームになった。ステータスで判定していた呼び出し側は `auth-required` / `forbidden` を聞く。
|
|
141
|
+
- `@aiquants/sse` を `dependencies` に加えた。
|
|
142
|
+
- **公開**: `publish:*` と `prepublishOnly` は公開の前に `.config/scripts/check-publish-leaks.mjs` で tarball を検査する。
|
|
143
|
+
|
|
144
|
+
## 0.21.0 (2026-09-24)
|
|
145
|
+
|
|
146
|
+
v0.21 は UI クロームの多言語化 — 英語 (`"en"`) を既定、日本語 (`"ja"`) を第 2 言語とし、パッケージが描画する
|
|
147
|
+
利用者可視の文言すべてと埋込み `VirtualScroll` のスクロールクロームを 1 つの `config.locale` で切り替える。
|
|
148
|
+
ピア `@aiquants/virtualscroll` 3.7.0 のラベルカタログ (`VIRTUAL_SCROLL_LABEL_CATALOGS` /
|
|
149
|
+
`resolveVirtualScrollLabels`) を単一真実源として再利用し、エンジン由来の文言は再記述しない。
|
|
150
|
+
|
|
151
|
+
- **新機能 — `config.locale` (UI クローム言語)**: `DailyReportClientConfigInput.locale?: DailyReportLocale`
|
|
152
|
+
(`"en"` | `"ja"`、既定 `"en"` — 型はエンジンの `VirtualScrollLocale` そのもの)。非対応値 (`"ja-JP"` / `"fr"` /
|
|
153
|
+
`"EN"` / `""` / `null`) は描画時 `RangeError` — 言語ネゴシエーションはしない。解決済みの `locale` / `labels` は
|
|
154
|
+
`useDailyReportConfig()` から読める。
|
|
155
|
+
- **新機能 — ロケール別ラベルカタログ**: `DAILY_REPORT_LABEL_CATALOGS` (`en` / `ja`、外側と各カタログを凍結)、
|
|
156
|
+
`DAILY_REPORT_LABEL_KEYS` (88 キー、エンジン 7 キーが先頭) と `resolveDailyReportLabels(locale, overrides)` を
|
|
157
|
+
`@aiquants/daily-report/client` から公開。型 `DailyReportLocale` / `DailyReportLabels` /
|
|
158
|
+
`DailyReportLabelOverrides` / `DailyReportOperation` を追加。固有 81 キーのうち 9 キー (件数・ID・操作名を
|
|
159
|
+
含む文言) は整形関数で、数値はロケールに束縛した BCP 47 タグ (`en-US` / `ja-JP`) で桁区切りする。
|
|
160
|
+
`config.labels` の未知キー・空白文字列・整形関数キーへの非関数・素でない object は描画時 `RangeError`。
|
|
161
|
+
- **新機能 — 埋込み VirtualScroll への転送**: List / DetailList の `VirtualScroll` へ `locale` とエンジン 7 キーを
|
|
162
|
+
渡す (矢印の `aria-label` と空状態「No items」/「項目がありません」)。エンジンラベルは 7 値で安定化し、
|
|
163
|
+
毎レンダー作り直した `labels` でも一覧の memo 境界を貫通しない。
|
|
164
|
+
- **破壊的変更 (0.x 枠 — クリーンカットオーバー、互換別名なし)**:
|
|
165
|
+
- ピア `@aiquants/virtualscroll` は 3.7.0 以降 (再利用するエンジンのラベルカタログ `VIRTUAL_SCROLL_LABEL_CATALOGS` を持つ版)。
|
|
166
|
+
移行: `@aiquants/virtualscroll` を 3.7.0 以降へ上げる。
|
|
167
|
+
- **既定の表示言語が英語になった。** 従来コンポーネントへ直書きしていた日本語 (ボタン・プレースホルダー・
|
|
168
|
+
確認ダイアログ・状態バッジ・読み込み / エラー表示・失敗バナー等) は `locale` 省略時に英語で描画される。
|
|
169
|
+
移行: 日本語 UI を保つホストは `config.locale: "ja"` を渡す。ja カタログは従来の日本語を保ち、
|
|
170
|
+
`@aiquants` パッケージ共通の日本語語彙と表記へ揃えた 4 値だけが異なる: `treeComingSoon`
|
|
171
|
+
(`ツリーは現在準備中です` — タブ名 `🌳 ツリー` と同じ呼び名)、`resizeHandle`
|
|
172
|
+
(`日報一覧と詳細ペインの境界のサイズ変更ハンドル`)、`unknownUser` (`不明なユーザー`)、
|
|
173
|
+
`interviewerWithAffiliation` (半角括弧 `佐藤 (山田商事)`)。
|
|
174
|
+
- `config.fieldLabels` / 型 `DailyReportFieldLabels` / `defaultDailyReportFieldLabels` を削除し、21 キーを
|
|
175
|
+
`config.labels` へ畳み込んだ (キー名は同じ)。移行: `fieldLabels: { ... }` → `labels: { ... }`。ja カタログは
|
|
176
|
+
中立な日本語見出し (`営業日` / `作成者` / `顧客` / `内容` / `コメント` / `概要` / `関連` 等) を持つため、
|
|
177
|
+
業務語彙 (例 `商談内容`) だけを上書きすればよい。`locale: "ja"` だけを足して `fieldLabels` の移行を
|
|
178
|
+
忘れると業務語彙がカタログの語へ置き換わるため、同じ変更で `labels` へ移す (例 `{ locale: "ja", labels: { customer:
|
|
179
|
+
"顧客・面談先", content: "商談内容", comments: "コメント一覧", tabArticle: "記事", tabRelations: "相関" } }`)。
|
|
180
|
+
- `config.title` を削除し `labels.title` へ畳み込んだ (en `"Daily Reports"`、ja `"日報"`)。移行:
|
|
181
|
+
`title: "X"` → `labels: { title: "X" }`。`renderHeader` の `title` 引数と両一覧の `aria-label` はこの値。
|
|
182
|
+
- **config のキー集合を閉じた。** 廃止キー `fieldLabels` / `title` は描画時に移行先を名指す `RangeError`
|
|
183
|
+
(`config.fieldLabels was removed in 0.21.0; use config.labels (the same 21 keys)` /
|
|
184
|
+
`config.title was removed in 0.21.0; use config.labels.title`)。値が `undefined` でもキーが在れば拒否し、
|
|
185
|
+
その他の未知キーも受け付けるキー一覧を示す `RangeError`。`useMemo` の戻り値など型付きリテラル外で組んだ
|
|
186
|
+
config は TypeScript の余剰プロパティ検査を受けず**コンパイルは通る**ため、実行時に検出する。移行: 廃止キーと
|
|
187
|
+
未知キーを config から外す。
|
|
188
|
+
- `DailyReportClientConfig` から `title` / `fieldLabels` を削除し、解決済みの `locale` / `labels` を追加。
|
|
189
|
+
`sourceTypeConfigs` は必須 (省略時は内蔵既定) になった。移行: 解決済みの値は `useDailyReportConfig()` の
|
|
190
|
+
`labels.title` / `labels` / `locale` / `sourceTypeConfigs` から読む。
|
|
191
|
+
- `defaultDailyReportClientConfig` は凍結済みのロケール非依存の入力形 `DailyReportClientConfigDefaults`
|
|
192
|
+
(`apiBasePath` / `ssePath` / `draftLabelName` / `renderHeader` / `showDevControls`) になった。`title` /
|
|
193
|
+
`fieldLabels` / `sourceTypeConfigs` / `locale` / `labels` を持たないため、`{ ...defaultDailyReportClientConfig,
|
|
194
|
+
locale: "ja" }` は日本語で描画される。移行: 解決済みの値は `useDailyReportConfig()` で読む。
|
|
195
|
+
- 共有層の `mergeComments` を `mergeComments(legacyComments, modernComments, currentUserId,
|
|
196
|
+
unknownAuthorName)` にした (第 4 引数は必須、`currentUserId` も省略不可 — サーバーの `isMine` を使うなら
|
|
197
|
+
`undefined`)。空白・非文字列の `unknownAuthorName` は `RangeError`。作者名の無いコメント (レガシーの
|
|
198
|
+
`name`、リレーショナルの `userName` が空 / `null` / 欠落) は `unknownAuthorName` を作者名にし、クライアントは
|
|
199
|
+
`labels.unknownUser` を渡す (従来はレガシーが固定の `"Unknown"`、リレーショナルは `-`)。送信中コメントの
|
|
200
|
+
作者名 (名前もメールも無いユーザー) も `labels.unknownUser`。移行: 第 4 引数に作者名の無いコメントの表示名を渡し
|
|
201
|
+
(クライアントなら `labels.unknownUser`)、`currentUserId` を省いていた呼び出しは `undefined` を渡す。
|
|
202
|
+
- サーバーの `addComment` は表示名の無い投稿者の SSE `comment-add` を `userName: ""` (従来 `"Unknown"`) で
|
|
203
|
+
配信する (読み取り経路と同じ規約)。受信側が `labels.unknownUser` で描く。移行: `"Unknown"` で作者名の無さを
|
|
204
|
+
判定していた受信側は空文字列で判定する。
|
|
205
|
+
- `DailyReportErrorInfo.operation` を `string` から `DailyReportOperation` へ絞った。`message` は
|
|
206
|
+
`labels.operationFailed(operation)` を選択ロケールで解決した文言 (en 既定では英語)。移行: `operation` は
|
|
207
|
+
`DailyReportOperation` の値で比べ、日本語の文言を期待する表示は `locale: "ja"` を渡す。
|
|
208
|
+
- `locale: "ja"` のとき、従来英語だった箇所も日本語になる: 上位タブ (`📄 一覧` / `🌳 ツリー` / `📋 詳細一覧`)、
|
|
209
|
+
画面タイトル (`日報`)、読み込み失敗注記 (`エラー`)、サイドペインのタブ (`概要` / `関連`)、スクロール矢印
|
|
210
|
+
(`上へスクロール` / `下へスクロール`)、空状態 (`項目がありません`)。移行: 従来の英語表記を保つホストは `labels` で
|
|
211
|
+
上書きする (例 `labels: { tabList: "📄 List", tabDetailList: "📋 DetailList" }`)。
|
|
212
|
+
- 内蔵既定の `sourceTypeConfigs` (`Internal` バッジ) のラベルは `labels.sourceInternal` (en `"Original"`、
|
|
213
|
+
ja `"オリジナル"`、従来はロケールに関係なく `オリジナル`)。ホストが `sourceTypeConfigs` を渡す場合は従来どおりそれが丸ごと使われる。
|
|
214
|
+
移行: en でも `オリジナル` を保つホストは `labels.sourceInternal` を上書きするか `sourceTypeConfigs` を渡す。
|
|
215
|
+
- 詳細の読み込み失敗表示 (List タブのサイドペイン) は例外メッセージ (`error.message`) ではなく
|
|
216
|
+
`labels.reportLoadFailed(reportHubId)` を描画する (DetailList と同じ文言)。移行: 例外の文言を期待していたテストは
|
|
217
|
+
`labels.reportLoadFailed(reportHubId)` の文言を期待する。
|
|
218
|
+
- 文言以外の既定値 (`apiBasePath` / `ssePath` / `draftLabelName` / `showDevControls` / `renderHeader`) は
|
|
219
|
+
明示 `undefined` でも既定値へ解決する (従来は明示 `undefined` が既定を上書きしていた)。移行: 明示の `undefined` で
|
|
220
|
+
既定を消していたホストは、使う値そのものを渡す。
|
|
221
|
+
- **不変**: `draftLabelName` (DB のラベルデータ) は `locale` に連動しない。日付は従来どおり ISO 表記。
|
|
222
|
+
このパッケージには BCP 47 の `formatLocale` は無い (桁区切りは `locale` に束縛、日付は ISO)。
|