@aiquants/daily-report 0.26.0 → 0.27.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 +36 -2
- package/README.md +86 -49
- package/dist/client.d.mts +4 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +4 -4
- package/dist/client.mjs +4 -4
- package/dist/server.d.mts +35 -31
- package/dist/server.d.ts +35 -31
- package/dist/server.js +3 -3
- package/dist/server.mjs +3 -3
- package/dist/styles/daily-report.standalone.css +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@aiquants/daily-report` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.27.0 (2026-10-05)
|
|
6
|
+
|
|
7
|
+
0.26.0 の続き: Fetch Metadata による要求の隔離、ポインター専用のスクロールバー (名前の無い `scrollbar` と `slider` を出さない)、添付の格子の整数 px の列、要求が全員去った描画の結果の保持、SSE リーダーのポート、E2E のテスト用ハンドルの読み取り専用化。どれも README の該当の節が今の契約を記す。
|
|
8
|
+
|
|
9
|
+
### Security
|
|
10
|
+
|
|
11
|
+
- **別オリジンのページからの要求は認証より前に 403**: API (`api.loader`・`api.action`)・SSE (`sse.loader`)・添付 (`attachment.loader`) のどの経路も、最初の文で要求の Fetch Metadata を見て (`isCrossSiteRequest`、`src/server/request-isolation.ts`)、`Sec-Fetch-Site` が `same-origin` でも `none` でもない要求 (同じサイトの兄弟のサブドメインの `same-site` を含む) を、認証・レートの課金・可視集合の解決・認可・サービスの呼び出しのどれより前に 403 (`{"error":{"message":"Cross-site request rejected"}}`・`Cache-Control: no-store`・`X-Content-Type-Options: nosniff`。`Set-Cookie` もログの行も無い) で断る。
|
|
12
|
+
断らないのは、最上位のナビゲーション (`Sec-Fetch-Mode: navigate`・GET か HEAD・`Sec-Fetch-Dest` が `object` でも `embed` でもない。別のページのリンクから原本を開く) と、`Sec-Fetch-Site` の無い要求 (ブラウザーでないクライアント。下限のどのブラウザーも送る) だけ。添付の 403 は添付の失敗の組み立てを通るので、添付のどの応答とも同じヘッダー (`Cross-Origin-Resource-Policy: same-origin`・`nosniff`) を持つ。応答の側の `Cross-Origin-Resource-Policy` は多重の守りとして残す (README の Request isolation)。
|
|
13
|
+
以前は、セッションの Cookie (通常の `SameSite=Lax`) が付く同じサイトの別オリジンのページから、フォームの POST が日報の作成・更新・公開・削除・コメント・スター・既読へ届き (フォームの送信はプリフライトを要さず、React Router はリソースの経路に CSRF の検査をかけない)、`<img>`・no-cors の `fetch`・HEAD の探りが認証・レートのトークン・可視集合の解決・認可まで走らせた (見える添付と見えない添付で応答までの仕事が違い、閲覧者のレートのバケットを空にして 429 にできた)。`createDailyReportServer` か `createDailyReportHandlers` を結線したホストは、この版へ上げるだけで守られる。ページと別のオリジンから API を呼ぶホストは断られる (パッケージのクライアントはページ自身のオリジンからしか呼ばない)。
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **スクロールバーはポインター専用 (名前の無い `scrollbar` と `slider` を出さない)**: 両ビューが渡す `enableArrowButtonTabStops: false` は、`@aiquants/virtualscroll` 3.10.0 で「ホストがキーボードのスクロールを自分で持つ」ことのただ 1 つの合図になり、バーはネイティブのスクロールバーと同じポインター専用の部品になる。バー全体が `aria-hidden="true"` なので支援技術には (名前の無いものも含め) `scrollbar` も `slider` も見えず、矢印は Tab 順に入らず、バーのどこを押しても既定動作を取り消してフォーカスを動かさない。ポインターのスクロール (矢印と長押し・溝・つまみ・タップスクロールサークル) は変わらない。
|
|
18
|
+
以前は名前の無い `role="scrollbar"` と `role="slider"` が支援技術に見え (WCAG 4.1.2)、バーの押下は行にあったフォーカスをバー (`tabIndex={-1}`) へ移した。ラベルのカタログは virtualscroll の 11 個のエンジンキーを再利用し、新しい 4 キー (`verticalScrollBar`・`horizontalScrollBar`・`verticalScrollThumb`・`horizontalScrollThumb`) がバーとつまみの名前になる (隠れたバーの名前も `config.labels` で上書きできる)。キーは全 94 (エンジン 11 + 固有 83)。
|
|
19
|
+
- **添付の格子の列は整数 px**: 格子は自分の大きさの容器 (`data-testid="daily-report-attachment-grid-container"`。inline-size の容器で、格子の包含ブロック) の中に 1 つだけ置き、容器の内容の幅 W が列数・格子の幅・ファイル名を収める列幅のただ 1 つの入力になる。n 列の格子の幅は列幅 t が整数 px になる最も広い n·t + 16(n − 1) ≤ W (区切りごとに列数の隣に書く `round()` の幅。列は `1fr` のまま) で、列幅は t = ⌊(min(W, 1,264) − 16(n − 1)) / n⌋、隙間はどれもちょうど 16px、余り (W が整数 px なら 0〜n − 1px) は格子の外の終わりの側に残る。
|
|
20
|
+
1280 × 800 の側面ペインの列幅は 234⅔ と 231⅓ から 234 と 231 になる (枠の高さ 156 と 154 は変わらない)。以前の端数の列幅はタイルの縁を画素の間に置き、比 1 では隙間を 16 と 17px で描いた。`round()` を持たない Chrome 121〜124 は幅の宣言だけを捨て、今までの端数の列幅で同じ列数に並ぶ。添付の節は大きさの容器でなくなり、ファイル名を収める幅の観測器は格子ではなく格子の容器を測る (格子そのものの幅は余りを除いた幅なので、そこからは列数が決まらない)。
|
|
21
|
+
- **全員が去った描画も、払い終えた結果を残す**: サムネイルの生成は、描画の締め切り (502 `render_timeout`) か、待っている要求が全員去ったとき (503 `aborted`。その時点で答える) に描画を待つのをやめ、どちらでもその描画を続いている描画の登録簿へ渡す。描画が内容で決まる結果 (出力の検証を通った縮小画像か `unsupported`) で決着したら、同一性を確かめた生成なら、誰が待っているかを問わずキャッシュに記録してから枠を返す。決着するまで、同じ内容の次の生成は展開を重ねずにそれを待つ。中断に応じる描画ポートの `failed` と例外は記録しない。
|
|
22
|
+
以前は全員が去った生成の描画の結果を種別を見ずに捨てたので、タイルが描画の窓を出て戻ると、既定の 2 枠では同じ原本をもう 1 度読んで展開した (今は読み取り 1 回・描画 1 回)。
|
|
23
|
+
- **開発用の SSE のスイッチに名前**: `showDevControls` の SSE の切り替えのスイッチ (`role="switch"` のボタン) は、ボタン自身に `labels.devSseToggle` の `aria-label` と `title` を持つ。以前は囲む要素の `title` だけで、スイッチは名前を持たなかった (WCAG 4.1.2)。
|
|
24
|
+
- **強制配色のスクロールバー**: `VIEW_SCROLL_BAR_THEME_CLASS_NAME` は強制配色 (`forced-colors: active`) で、つまみを状態ごとの規則と同じ選択子でシステム色に言い直し (休み `CanvasText`、ホバーとドラッグ `Highlight`、無効 `GrayText`)、溝に内側の 1px の `CanvasText` の輪郭を付ける (配置は変わらない)。以前は強制配色でつまみも溝も `Canvas` になり、つまみが見えなかった。
|
|
25
|
+
- **E2E のテスト用ハンドルは読み取りと見せ方 1 つ** (Breaking を参照): `__virtualScroll` は VirtualScroll のハンドルの読み取りの部分 (`getViewportSize`・`getScrollPosition`・`getScrollAnchor`・`getRange`・`getFenwickSize`)、日報の検索 3 つ、ビューのスクロールの口を通る `revealIndex(index, options)` だけを持つ。`revealIndex` はキーの移動と同じく呼び出しの直後に錨を記録するので、直後の一覧の変化も見せた日報を同じ位置に留める。以前はハンドルを丸ごと広げたので、E2E が錨を通らずに位置を動かせた。
|
|
26
|
+
- **SSE リーダーはポートの型で受ける**: `createDailyReportHandlers` の設定の `sseReader` は、クラス `DailyReportSseReader` の型ではなくポート `DailyReportSseReaderPort` (`ready()` と `subscribe(onEntry, onError)`) で受ける。0.24.0 と 0.26.0 の Breaking が言う、ホストが自前で差し替えるリーダーが実装するのはこの型。以前のクラスの型は private の欄を持つので、同じ 2 つのメソッドを持つホストの実装も型の読み替えなしには渡せなかった。
|
|
27
|
+
- **開発者向け**: 公開のスクリプト (`publish:*`) は `pnpm run verify` が作ったビルドをビルドし直さずに測り、`node scripts/check-bundle-size.mjs --write`、続けて `--exact` を走らせる。縮んだ項目は `--write` が下げるので、縮みは公開する版の基準に作りとして記録される (以前は縮みも `--exact` で落ち、基準を記録し直すコミットが要った)。増えた項目は記録せずに `--exact` で止め、レビューを通した `--write --accept` を待つ。
|
|
28
|
+
配置の格子の単位 u = 4 は `src/shared/layout-lattice.ts` の `LAYOUT_LATTICE_PX` ただ 1 つで、List の行の枠・DetailList の測る前の行の見積もり (88u = 352)・添付のタイルの寄せはどれもそこから読む (写しの宣言は `constants.spec.ts` が構文木で落とす)。SQL の結果のキャッシュのキーはどれも `cache-keys.ts` の組み立てが可視集合のダイジェストで閉じ、ID 一覧の名前空間の接頭辞は `DAILY_REPORT_IDS_CACHE_PREFIX` (`"daily-report:ids:"`)、営業日の解決のキーも組み立て (`businessDateCacheKey`) から作る (キーのバイト列は変わらない)。錨の spec は本物の VirtualScroll の上でも、窓の中と外の測った行の置き換えと、下端の揃えを保留している間の窓の中の削除を確かめる。
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- server の型 `DailyReportSseReaderPort`: 共有 SSE リーダーのポート (上の Changed)。
|
|
33
|
+
|
|
34
|
+
### Breaking
|
|
35
|
+
|
|
36
|
+
- `__virtualScroll` (両ビューのテスト用ハンドル。README の Test hooks) から、VirtualScroll のハンドルの位置を動かす関数 (`scrollToIndex`・`scrollBy`・`scrollTo`・`applyWheel`・`updateItemSize`) と、`getContentSize`・`getFenwickTreeTotalHeight`・`focusItemAtIndex` を外した。Migration: `__virtualScroll.scrollToIndex(index, options)` は `__virtualScroll.revealIndex(index, options)` へ置き換える (揃え方と offset は同じ)。ほかの位置の変化は画面の操作 (キー・ホイール・クリック) で起こす。
|
|
37
|
+
- ピアの `@aiquants/virtualscroll` の下限を 3.10.0 へ上げる。両ビューは 3.10.0 の `enableArrowButtonTabStops: false` (ポインター専用のバー) と、バーとつまみの名前のキーに頼る (3.9.0 では名前の無い `scrollbar` と `slider` が支援技術に見え、バーの押下がフォーカスを移す)。Migration: `@aiquants/virtualscroll` を 3.10.0 以降へ上げる。`labels` で上書きできるエンジンのキーは 4 つ増える (上書きは任意)。
|
|
38
|
+
|
|
5
39
|
## 0.26.0 (2026-10-04)
|
|
6
40
|
|
|
7
41
|
0.25.0 の続き: 位置の変化ごとの錨の記録、行と面の 4 px の格子、読み込みの画面の枠とエラーの文言の色、コメントの節の 1 つの規則、添付の配信とサムネイルの生成の締め付け、共有 SSE リーダーの位置の固定。どれも README の該当の節が今の契約を記す。
|
|
@@ -44,7 +78,7 @@ All notable changes to `@aiquants/daily-report` are documented here.
|
|
|
44
78
|
|
|
45
79
|
### Breaking
|
|
46
80
|
|
|
47
|
-
- `DailyReportSseReader.ready()` はストリームの末尾を読めないとき拒否する (0.24.0 と 0.25.0 は `"$"` へ縮退して解決した)。Migration: 自前の SSE ハンドラで共有リーダーを使うホストは、`ready()` の拒否で接続を閉じてクライアントに開き直させる (同梱のハンドラはそうしている)。リーダーを自前で差し替えるホストの `ready()` も、位置を具体 ID
|
|
81
|
+
- `DailyReportSseReader.ready()` はストリームの末尾を読めないとき拒否する (0.24.0 と 0.25.0 は `"$"` へ縮退して解決した)。Migration: 自前の SSE ハンドラで共有リーダーを使うホストは、`ready()` の拒否で接続を閉じてクライアントに開き直させる (同梱のハンドラはそうしている)。リーダーを自前で差し替えるホストの `ready()` も、位置を具体 ID に固定できないときは拒否する (自前のリーダーが実装する型は、後の版が公開した `DailyReportSseReaderPort`)。
|
|
48
82
|
- ピアの `@aiquants/virtualscroll` の下限を 3.9.0 へ上げる。両ビューは 3.9.0 の `onScrollAdjust` で錨を記録し直し、揃えた端を守る装置の画素への揃えに頼る。Migration: `@aiquants/virtualscroll` を 3.9.0 以降へ上げる。
|
|
49
83
|
- server の `SqlResultCache` から `invalidate` と `flush` を外した。Migration: 1 つのキーを消していた呼び出しは、そのキーを接頭辞とする `invalidatePrefix(<キー>)` か、全部を消す `clearAll()` へ置き換える。
|
|
50
84
|
|
|
@@ -126,7 +160,7 @@ All notable changes to `@aiquants/daily-report` are documented here.
|
|
|
126
160
|
- **`subscribe` の `onError` が必須に**: `DailyReportSseReader.subscribe(onEntry, onError)` の `onError` は省略できない。run の失敗は内部の `"error"` イベントでは
|
|
127
161
|
なく各購読者の `onError` へだけ届き、呼ばれた時点で購読は解除済みなので、呼び出し側は接続を閉じてクライアントに開き直させる (同梱の SSE ハンドラはそうしている)。
|
|
128
162
|
購読者が残っていても失敗した run は再起動せず、次の購読が新しい run を起動する。購読より前に読んだエントリは再生しない。`destroy()` は全購読者を通知なしで
|
|
129
|
-
外して run を止め、読み取り位置を初期化する (実行中の `subscribe` は例外になる)。リーダーを自前で差し替えるホストは `ready()`
|
|
163
|
+
外して run を止め、読み取り位置を初期化する (実行中の `subscribe` は例外になる)。リーダーを自前で差し替えるホストは `ready()` も実装する (実装する型は、後の版が公開した `DailyReportSseReaderPort`)。
|
|
130
164
|
|
|
131
165
|
## 0.23.0 (2026-10-03)
|
|
132
166
|
|