@aiquants/daily-report 0.33.0 → 0.35.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 +130 -0
- package/README.md +312 -74
- package/dist/client.d.mts +147 -130
- package/dist/client.d.ts +147 -130
- package/dist/client.js +4 -4
- package/dist/client.mjs +4 -4
- package/dist/comment-adapter-ChA4KOE1.d.mts +172 -0
- package/dist/comment-adapter-DqBqtqfA.d.ts +172 -0
- package/dist/index.d.mts +24 -3
- package/dist/index.d.ts +24 -3
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/logger-BaxnzF-0.d.mts +17 -0
- package/dist/logger-BaxnzF-0.d.ts +17 -0
- package/dist/server.d.mts +266 -15
- package/dist/server.d.ts +266 -15
- package/dist/server.js +11 -4
- package/dist/server.mjs +11 -4
- package/dist/{sse-schema-DcOgQr_O.d.mts → sse-schema-getLS62T.d.mts} +1 -1
- package/dist/{sse-schema-DcOgQr_O.d.ts → sse-schema-getLS62T.d.ts} +1 -1
- package/dist/styles/daily-report.standalone.css +1 -1
- package/package.json +4 -3
- package/dist/ids-stream-CtlszCHr.d.ts +0 -32
- package/dist/ids-stream-CyK2upgD.d.mts +0 -32
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,136 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@aiquants/daily-report` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.35.0 (2026-10-08)
|
|
6
|
+
|
|
7
|
+
任意の文字の検索。サーバーの設定のブロック `search` とクライアントの `config.search` を渡したホストだけで働き、渡さないホストの振る舞いは変わらない (公開・削除・コメントの経路がトランザクションに入ることと、`DailyReportDb` の `execute` を除く)。仕様は `docs/specs/2026.10.07 [AI] 03-search-specification.md`、README の **Text search** が今の振る舞いを述べる。
|
|
8
|
+
|
|
9
|
+
あわせて 0.34.0 の続き: フォーカスを見える要素へだけ渡すことと状態の面のフォーカスの引き継ぎ、誤りの知らせの読み上げ (常設の警告の領域と繰り返しの数)、ストリームの読み上げの領域、コメントの削除の 404、`DailyReportErrorProvider` を必須にすること、デスクトップのビューの上端と内容の列の寄せの格子、側面ペインの読む面の取っておく高さ、DetailList の日時の見え方、行の導きの写し、サーバーのログのチャンネル、JSON の答えの弱い比較の 304 と 1 回の直列化、エンドポイントの表が宣言する上限、要求の中断で返るストリームの枠、公開面の閉包。どれも README の該当の節が今の振る舞いを述べる。
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **フォーカスは見える要素へだけ渡す**: 自分を外すか空になる操作部品 (2 つの再試行のボタン・誤りの知らせを閉じる操作・見出しの札の入れ物・本体へ入れ替わる状態の面) は、1 つの規則 (`focusVisibleSuccessor`) でフォーカスを渡し、受け取るのは文書の中にあってフォーカスでき、面積のある箱を持ち、`checkVisibility` (`visibility` と不透明度を含む) を通る要素だけで、渡った先を確かめる。
|
|
14
|
+
状態の面と札の入れ物は、フォーカスを持つ間は操作部品のフォーカスの輪を描く。状態の面がフォーカスを持ったまま本体へ入れ替わると、ページの引き継ぎ (`FocusHandOverContext`) を、ビューが行をマウントした最初の確定で受け取って Tab の止まり先の行 (空の一覧なら選ばれたビューのタブ) へ渡し、利用者の切り替えで作り直した状態の画面は新しい面へ渡す。札の入れ物はフォーカスを持ったまま空になると、ページの後継 (ビューの行、無ければ選ばれたビューのタブ) へ渡す。
|
|
15
|
+
以前は状態の面が輪を消したまま (`outline-none`) フォーカスを持ち、読み込みの失敗からキーで再試行するとフォーカスは毎回画面に出さない読み上げの領域 (1 × 1 の箱) へ渡り (行カーソルへ渡す枝は、ビューがその確定でまだ行を描かないので走らなかった)、札の入れ物はストリームが終わると 0 × 0 の箱でフォーカスを持った (WCAG 2.4.7)。
|
|
16
|
+
- **誤りの知らせはフォーカスを body へ落とさない**: 知らせを閉じるときの返し先は、来た元・ビューの行カーソル・知らせを置いたダイアログ・選ばれたビューのタブ (行の無い一覧)・状態の面 (ビューがまだ無い) の順の、見える最初の要素。以前は来た元も行カーソルもダイアログも無いと (来た元の消えた空の一覧など) body へ落ち、状態の面がフォーカスを持つ間の利用者の切り替えもフォーカスを body へ落とした。
|
|
17
|
+
- **コメントの削除の 404 も済んだものとみなす**: サーバーにもう無いコメントの削除 (404) は、巻き戻しも誤りの知らせもせず、コメントを外したままにする (日報の削除と同じ道)。404 を済んだと数えるのは対象を消す操作 (`delete`・`deleteComment`) だけで、その処理は 404 の意味 (`onGone`) を持たなければ型検査を通らず、ほかの操作の処理は持てない (`ActionCallbacks`)。以前はコメントを戻して誤りを知らせ、やり直しても毎回 404 になった。
|
|
18
|
+
- **同じ失敗の繰り返しも読み上げ、知らせの移動では読み上げない**: 読み上げは、失敗より前から空のまま置いた常設の `role="alert"` の領域 (`[data-daily-report-notice-alert]`。プロバイダー自身のものと、登録された置き場ごとのもの) が受け持ち、失敗はそのとき前面にある置き場の領域へ、回の番号を鍵にした新しい文字として 1 回だけ書く。見える帯は文言を名前に持つ `role="group"` で、同じ文言の失敗が続くと回数を見せる (`labels.noticeRepeated`)。
|
|
19
|
+
以前は同じ文言の失敗が DOM を何も変えず (見えも読み上げもしない)、ポータルの置き場と流れの中の置き場が React の別の位置だったので、オーバーレイを開閉するたびに古い知らせを新しい `role="alert"` として差し込み直した (WCAG 4.1.3、2.2.4)。
|
|
20
|
+
- **ストリームの読み上げの領域は移り変わりだけを知らせ、フォーカスを受けない**: ページの常設の状態の領域は空のままマウントし、マウントの後の変化 (再試行の後の読み込み中・再接続中・失敗) だけを知らせる。以前はマウントの時点で読み込み中の文字を持ったので最初の読み込みは読み上げられず、読む画面では見える状態の面と同じ文字を 2 度読ませた。
|
|
21
|
+
- **ストリームの枠は要求の中断で返る**: 閲覧者のストリームの枠は、受け入れ (`createStreamSlots().admit`) が本体のシグナルに結び付け、受け入れた後のどの中断でもその時に 1 回だけ返る。以前の ids のストリームは中断の購読を応答を作るときに足したので、再開の GET が全量のクエリを待つ間に中断されると、枠はクエリの決着まで (中断の後に本体を引かないアダプターでは返らずに) 残り、そうした要求が 32 本重なると、その閲覧者の次のストリームは 503 になった。
|
|
22
|
+
- **JSON の答えの 304 は弱い比較**: `jsonResponseWithETag` は `If-None-Match` の並びの各タグを `W/` を外して比べ (`*` は一致にしない)、添付の縮小画像と同じ 1 つの読み手 (`ifNoneMatchIncludes`) を使う。以前は字面の一致で比べたので、圧縮する中継 (gzip の nginx は転送する強い ETag を弱める) を通る 1 KiB 以上の答えは、再検証で 1 度も 304 にならなかった。
|
|
23
|
+
- **デスクトップのビューの上端と面の縁も格子に乗る**: 内容の列の上と左右の寄せと原点は格子のブロックの刻み q (1/4 の倍数で 4 px、1/8 の奇数倍で 8 px) で、ビューの上の操作列 (設定したときは検索の行も) は高さを q へ切り上げる帯 (`VIEW_TOOLBAR_BAND_CLASS_NAME`) に入る。
|
|
24
|
+
以前は列の上の寄せが 4 px で、ホストの 32 px のヘッダーの下ではビューの上端が 68 px (8 で割って 4 余る) だったので、1/8 の奇数倍の画素密度 (1.125・1.375・2.625 など) ではビューの上端が装置の画素の半分ずれ、どの行の縁・選択の輪・アウトラインもそれを受け継いだ (1280 × 800・1.125 で操作列・ビュー・最初の面の上端が 40.5・76.5・85.5 装置画素。今は 45・81・90)。412 px 幅・2.625 の面の左の縁も 31.5 から 42 装置画素になった。
|
|
25
|
+
- **側面ペインの読む面は読み込みの前後で高さを変えない**: 読み込み中の読む面は読む行 3 本分の高さを取っておき (`min-h-24`: 寄せ 12 × 2 + 24 px の行 × 3 = 96 px)、骨組みは 24 px の行の箱 3 本で、16 px の棒をそれが代わる文字の行の上に置く。以前の取っておく高さは 88 px、骨組みは 64 px (読む行 2.67 本分) で、3 行の日報は読み込むと 88 から 96 px へ伸び、骨組みの棒は文字の行より 4 px 上にあった。
|
|
26
|
+
- **行の導きの写しはページのライブラリーに左右されない**: ids のストリームの publish から行を導くとき、変化の場所は前の行の値の読み取り (末尾に続く Δ 行なら Δ + 1 行、ほかの変化は 1 行ごとに二分探索) で決め、新しい行の配列は前もって確保した配列への 1 回の写しで作る (`concat`・`filter`・`slice` を使わない)。利用者の操作 (持つ・手放す・外す) も持つ行の表と二分探索で行の場所を決める。
|
|
27
|
+
以前の追加は `rows.concat(additions)` で、`concat` の速い経路はページ全体の保護 (`Symbol.isConcatSpreadable`) に依るので、ページのどこかのライブラリーが 1 度書くと (apache-arrow はプロトタイプに書く) publish ごとに全行を 1 件ずつたどった。Chromium 148 の 228,222 行で、保護が壊れた `concat` は中央値 51.6 ms、今の写しは 0.65 ms。値の置き換え・外す・手放すも行を写して絞り込み、日報の作成 1 回の SSE で約 13 ms、削除 1 回で 9〜10 ms を使った。
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **`DailyReportDb` は `execute` を持つ** (公開の型の変更): 索引と検索の SQL を流すため。drizzle の `db` とトランザクションは持っているので、`db` をそのまま渡すホストは変更が要らない。手で書いた代役を渡すホストは `execute(query)` を足す。
|
|
32
|
+
- **公開・削除・コメントの追加と削除はトランザクションの中で行う**: 索引を同じトランザクションで書くため。検索の設定が無くても同じで、変わるのはデッドロックの犠牲になったときに丸ごとやり直されることだけ。
|
|
33
|
+
- **DetailList の日時は `YYYY-MM-DD HH:mm` で見せる** (既定の見た目): カードの作成日時のような ISO の日時は、日付・空白 1 つ・時と分で見せ (秒は丸めずに切る: `2026-12-31T23:59:59` は `2026-12-31 23:59`)、`<time datetime>` には ISO の値をそのまま残す。日付だけの値と日付の無い `-` はそのまま。規則は `DateText` の 1 か所で、見出しの札とメタデータの列 (と、それを使うどの呼び出し元) も同じ形で見せる。以前は `2025-10-17T14:20:00` のように `T` と、いつも `:00` の秒を見せた。
|
|
34
|
+
- **サーバーのログの行はチャンネルを名乗る**: どの行も、書いた部分 (チャンネル) の接頭辞を持つ (`[DailyReportAPI]`・`[DailyReportSSE]`・`[DailyReportStreams]` など。ホストのロガーへ渡す行も同じ。`createChannelLogger`)。ホストのロガーはどのチャンネルのどの水準の行も受け取り、水準を自分で選ぶ。ホストのロガーが無ければ、チャンネルごとの既定の水準から console へ書く。
|
|
35
|
+
迂回のバケットの 429 は自分のチャンネル `[DailyReportRefresh]` (以前は `[DailyReportAPI]`)、`createDailyReportServer` の redis の警告は `[DailyReportServer]` (以前は `[DailyReport]`)、共有の SSE リーダーは `[DailyReportSseReader]` (以前は `[SSE Reader]`)、`transformJsonArray` は `[DailyReportExternalSource]` で書く。500 は文面と例外のオブジェクトを 1 回の呼び出しで書く 1 行 (以前は `Stack:` の 2 行目を別に書き、同時の要求の行と混ざった)。
|
|
36
|
+
- **JSON の答えは 1 回だけ直列化する**: `jsonResponseWithETag` は本文の字面から ETag を作る (`etagOfText`)。以前は ETag のためと本文のために 2 回直列化した (622,349 バイトの答えで組み立て 5.41 ms のうち 0.78 ms)。
|
|
37
|
+
- **エンドポイントの表は上限を宣言する**: API の経路の表 (`API_ENDPOINT_TABLE`。以前の `API_ENDPOINT_BODY_KINDS`) の行は、本体の種類と、閲覧者ごとのデータベースの仕事を縛る上限 (`admission`: `cache`・`refresh-bucket`・`stream-slots`・`search-limiter`。型で 1 つ以上) を持つ。上限を名乗らないエンドポイントは表に足せず、表を回す 1 つの spec が宣言した上限をハンドラーごとに確かめる。
|
|
38
|
+
- **開発者向け**: 詳細の表示の欄の解決 (`resolveHubDisplayFields`) と投稿コメントの見え方 (`isSearchCommentVisible`) を、詳細と索引と照合の基準が共有する。営業日の一覧の取得は、ID でまとめた詳細と同じ 1 つの読み取り (`fetchVisibleHubDetails`) を使う。エンドポイントの名前は `shared/api-endpoints.ts` の表に `search` と `reports` を足した。
|
|
39
|
+
- 整数の設定と内部の上限はどれも 1 つの検証 (`requireIntegerSetting`) で読む: クライアントの読み込みの枠 (`createLoadSlotLimiter`)・進捗の記憶 (`createThumbnailProgressStore`)・検索の設定・件名の列の長さも。2^53 以上の値は拒む (以前の手書きの `Number.isInteger` は通した)。`src/integer-bounds.spec.ts` が手書きの整数の検証を例外の一覧なしに落とす。
|
|
40
|
+
- docstring の検査は、関数に加えて契約を述べる宣言の JSDoc (プロパティとメソッドのシグネチャ・列挙と項目・型の別名・インターフェース・クラス・関数でない公開の定数) にも英語と日本語の両方を求める (1 行の形 `English. 日本語。` も受ける)。本番のコードは違反 0。
|
|
41
|
+
- 検査のスクリプトと spec は、モノレポの根を 1 つの解決 (`scripts/lib/repository-root.mjs`: 自分のファイルから上の `pnpm-workspace.yaml` か `.git`、検証した `PROJECT_ROOT`) で見つけ、見つからなければパスを名乗って落ちる。決まった段数の `../../../.config` は使わない。
|
|
42
|
+
- 条件付き要求の読み手 `ifNoneMatchIncludes` は `src/server/attachment-delivery/http.ts` から `src/server/response.ts` へ移った (JSON の答えと添付の縮小画像が共有する)。
|
|
43
|
+
- `src/docs-examples.spec.ts` は、仕様書が引用する名前を探すとき、分割代入で受ける名前 (動的な読み込みの答えを含む) も数える。
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- **文字の検索**: 検索窓 (操作列の下の 2 段目。AND/OR の切り替え・入力欄・消去のボタン・状態の行) で、空白で区切ったキーワード (二重引用符の組はそのすべての語を含む 1 つのキーワード) を探す。語は、閲覧者が読める 1 つの欄か 1 つのコメントの、fuzzy-search の既定の正規化をかけた文字の部分文字列として当たる。認可は詳細と同じ (削除した日報・ほかの利用者の下書き・見えない区分を出さず、コメントは区分の範囲か自分の投稿だけ)。
|
|
48
|
+
- **索引**: 専用のスキーマの 2 つの派生の表 (`DailyReportSearchDocument`・`DailyReportSearchComment`。`defineDailyReportSearchSchema`)。作成・更新・公開・削除・コメントの追加と削除の 6 つの経路は、元の表の書き込みと同じトランザクションの中で日報の行に鍵を取ってから索引を書き直し、書けなければ保存も失敗する。パッケージの外の書き込みの後は `service.reconcileSearchIndex` (区切りごとのトランザクション) で突き合わせる。
|
|
49
|
+
- **要求**: `GET {apiBasePath}/search?q=&combine=intersection|union` (列ごとの答え・ETag・400 の理由・閲覧者ごとの回数とプロセスの同時数の 429) と `GET {apiBasePath}/reports?ids=` (ID でまとめた詳細、100 件まで)。設定が無ければどちらも 404。
|
|
50
|
+
- **画面**: 答えを見せている間は答えの順で一覧を置き換え、見出しは当たりの件数、行は詳細を ID でまとめて読む。保存・SSE の日報とコメントの知らせ・落ち着いた ID の列の変化で、約 1 秒後に静かに送り直す (`If-None-Match`)。選択は答えに残れば保ち、消えたら一番近い日報へ移り、解除で検索の前へ戻る。検索中の作成は検索を解除してから作る。
|
|
51
|
+
- **公開の名前**: server エントリの `defineDailyReportSearchSchema` と型 `DailyReportSearchConfig` / `DailyReportSearchSourceTextReader` / `DailyReportSearchTables` / `DailyReportSearchReconcileOptions` / `DailyReportSearchReconcileProgress` / `DailyReportSearchReconcileSummary`。サービスの `searchLimits` / `searchDailyReports` / `getDailyReportDetailsByIdsByExternalId` / `reconcileSearchIndex`。プロバイダーの状態の `searchInvalidation` / `isReportRemoved` / `removedVersion`。
|
|
52
|
+
- **ラベル 12 個** (固有キーは 85 から 97): `searchInputLabel`・`searchPlaceholder`・`searchCombineAnd`・`searchCombineOr`・`searchCombineAndTitle`・`searchCombineOrTitle`・`searchClear`・`searching`・`searchNoHits`・`searchSyntaxHelp` と、整形関数の `searchHitCount(count)`・`searchFailed(failure)`。
|
|
53
|
+
- **公開面の閉包**: 公開した宣言が参照するパッケージ自身の型は、どれもいずれかの入口から公開する (API Extractor の `ae-forgotten-export` と同じ規則。`src/public-surface.spec.ts` が 3 つの入口の宣言の出力をたどって確かめる)。ホストは自分が渡すか受け取る型 (ポート・props・フックの値) を形を書き写さずに名前で読める。
|
|
54
|
+
共有エントリ: `DailyReportActionResultReading`・`DailyReportAttachmentState`・`DailyReportBusinessDateInput`・`DailyReportUIComment`・`DailyReportIdsStreamCursor`・`DailyReportSseTerminalEvent`・`DailyReportLogger`・`DAILY_REPORT_SEARCH_COMBINES`・`DailyReportSearchCombine`・`DailyReportSearchHit`。
|
|
55
|
+
client: 部品の props (`DailyReportPageProps`・`DailyReportResolvedContentProps`・`DailyReportListProps`・`DailyReportDetailListProps`・`DailyReportDetailListScrollRestore`・`DailyReportAttachmentIndicatorProps`)、設定 (`DailyReportClientConfig`・`DailyReportHeaderProps`・`DailyReportSearchSetting`・`DailyReportSearchSettingInput`)、アクションのコンテキスト (`DailyReportActionContextType`・`DailyReportActions`・`DailyReportActionFunctions`・`DailyReportActionLedgers`・`DailyReportActionState`・`DailyReportActionBusinessDate`)、
|
|
56
|
+
`DailyReportDetailResource`・`UseDailyReportSseConnectionOptions`・`DailyReportListNavigationHandle`・ids のストリーム (`DailyReportIdsStreamState`・`DailyReportIdsStreamPhase`・`DailyReportIdsStreamClientOptions`・`DailyReportIdsStreamItemsChange`・`DailyReportIdsStreamItemReplacement`)・`DailyReportSearchFailure`。
|
|
57
|
+
server: `DailyReportService`・`DailyReportEpochStore`・`DailyReportSqlResultCacheQueryOptions`・`DailyReportExternalSource`・`DailyReportSseReaderConfig`・`DailyReportVisibleSourceTypeSet`・`DailyReportResourceRouteArgs`、ポートの型 (`DailyReportResolveUserId`・`DailyReportEncodeUserId`・`DailyReportResolveVisibleSourceTypes`・`DailyReportVisibleSourceTypes`・`DailyReportVisibilityDimensions`・`DailyReportVisibilityResolveContext`・`DailyReportVisibilityResolveReason`・`DailyReportRedisClient`・`DailyReportRedisBlockingClient`・`DailyReportRedisStreamMessage`・`DailyReportSseEntryMessage`)、
|
|
58
|
+
表と行 (`DailyReportHubTable`・`DailyReportInternalTable`・`DailyReportCommentTable`・`DailyReportLabelTable`・`DailyReportHubLabelTable`・`DailyReportUserStatusTable`・`DailyReportUserTable`・`DailyReportAttachmentTable`・`DailyReportHubRow`・`DailyReportInternalRow`・`DailyReportUserStatusRow`・`DailyReportIdsSource`)、`DailyReportDb` の部品 (`DailyReportDbRows`・`DailyReportDbSelectChain`・`DailyReportDbInsertChain`・`DailyReportDbUpdateChain`・`DailyReportDbDeleteChain`)、
|
|
59
|
+
添付 (`DailyReportAttachmentThumbnailDelivery`・`DailyReportAttachmentBytes`・`DailyReportAttachmentThumbnailError`・`DailyReportAttachmentThumbnailFailure`・`DailyReportSharpPipelineLike`・`DailyReportSharpHeaderLike`) と検索 (`DailyReportSearchDocumentTable`・`DailyReportSearchCommentTable`・`DailyReportSearchSqlExecutor`・`DailyReportSearchPlan`・`DailyReportSearchSet`・`DailyReportSearchWord`)。
|
|
60
|
+
- client の `DAILY_REPORT_LATTICE_BLOCK_QUANTUM_CLASS_NAME`: 装置の画素の格子のブロックの刻み q をカスタムプロパティ `--aqdr-lattice-block` で運ぶクラス (パッケージ自身の刻みのクラスそのもの)。ホストは文書の根に置き、自分のバー (ヘッダーとフッター) の高さを `round(up, <大きさ>, var(--aqdr-lattice-block))` で切り上げる。1/8 の奇数倍の画素密度では 4 px (`DAILY_REPORT_LAYOUT_LATTICE_PX`) が装置の画素の半分なので、単位だけでは格子を外れる。
|
|
61
|
+
- **ラベル `noticeRepeated(count)`** (固有キーは 98): 同じ文言の失敗が続いたときに知らせの文言の横に見せる回数 (en `(2 times)`、ja `(2 回目)`)。
|
|
62
|
+
- **ID でまとめた詳細 (`reports`) の受け入れ**: 検索と同じ工場から作る自分の受け入れを持つ。同時数は検索の `concurrency` の 2 倍 (`REPORTS_CONCURRENCY_PER_SEARCH_CONCURRENCY`。閲覧者 1 人の取り分は検索の `concurrency`) で、回数は閲覧者ごと 1 分に検索の `rateLimitPerMinute` の 10 倍 (`REPORTS_RATE_PER_SEARCH_RATE`。検索のバケットと分け合わない)。超えた要求は 429 (`Retry-After`) で、拒否の行は `route=reports` を名乗る。内部ユーザーを持たない閲覧者は受け入れもクエリも使わずに空の答え。
|
|
63
|
+
|
|
64
|
+
### Breaking
|
|
65
|
+
|
|
66
|
+
- **`DailyReportErrorProvider` は必須**: 通知の面はプロバイダーの外で黙って何もしない既定値を持たず、`DailyReportErrorProvider` の外で描いた `DailyReportActionProvider` と List のモバイルのオーバーレイは描画で `[daily-report] useDailyReportErrorSurface must be used within a DailyReportErrorProvider` を投げる (アクションのコンテキストのフックがプロバイダーの外で投げるのと同じ)。以前はプロバイダーの外の失敗を知らせずに捨てた。
|
|
67
|
+
Migration: `DailyReportPage` を使うホストは変更が要らない。`DailyReportActionProvider` を自分で組むホストは `DailyReportErrorProvider` で包む (README が以前から求めていた組み方)。
|
|
68
|
+
- **ホストのロガーへ渡す行は接頭辞を持ち、どの水準も届く** (上の Changed): ホストのロガーは、以前は接頭辞の無い行を、チャンネルの既定の水準を通ったものだけ受けた。今はどの行も `[DailyReport<チャンネル>]` で始まり (文字列でない文面は接頭辞を別の最初の引数として)、debug を含むどの水準も届く。500 は 1 行で、例外のオブジェクトを 2 番目の引数で受ける。
|
|
69
|
+
Migration: 行の字面を照合するホストの記録や警報は、接頭辞の付いた行に合わせる (迂回のバケットの 429 は `[DailyReportRefresh]`)。水準を選ぶのはホストのロガー。
|
|
70
|
+
- **`deleteReport` は失敗で拒否する**: 削除の失敗は、日報を一覧へ戻した後に失敗を返す (誤りの知らせも出す)。以前は `@throws` を書きながら解決したので、呼び出し側は削除が済んだものとしてフォーカスを渡した。利用者の切り替えの後に解決した継続は巻き戻さずに解決する。
|
|
71
|
+
側面ペインの削除のボタンは拒否を受けて `labels.deleteFailed` の `alert()` を出し (誤りの知らせと並ぶ)、日報が消えたものとしてフォーカスを渡さない。DetailList の削除のボタンは受けて何もしない。
|
|
72
|
+
Migration: アクションのコンテキストの `deleteReport` を自分で呼ぶホストは拒否を受ける (`catch` する)。
|
|
73
|
+
|
|
74
|
+
## 0.34.0 (2026-10-07)
|
|
75
|
+
|
|
76
|
+
0.33.0 の続き: コメントの作者を ID で決めること、誤りの知らせを時間で消さず何も覆わない流れの中に置くことと、モバイルのオーバーレイの中に描くこと、自分を外す再試行ボタンのフォーカスとストリームの状態の読み上げ、端の行の `Home` / `End`、照合用 ID の衝突と消えた日報の削除、期限のある台帳と操作ごとの錠、1/8 の倍数の画素密度の装置の画素の格子、action と API のワイヤの契約の公開と ID の 1 つの定義域、キャッシュを迂回する読み取りの合わせ方と上限、閲覧者ごとのストリームの枠、JSON の応答の記録、対を持たないサロゲートのファイル名。どれも README の該当の節が今の振る舞いを述べる。
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- **コメントの作者は ID で決める**: SSE で届いたコメントは、作者の ID が表示中ユーザーの ID (`userId`。`encodeUserId` のポートの値) と等しいときだけ閲覧者自身のもの。投稿中の仮のコメントの id を本物の id へ解決するのは、その投稿自身の答えだけ。
|
|
81
|
+
以前は本文の一致で決めたので、ほかの利用者が投稿中のコメントと同じ本文を書くと、そのコメントを自分のもの (`isMine: true`) としてキャッシュし、投稿中の仮の id を相手のコメントの id へ解決した。その後の投稿中のコメントの削除は相手のコメントへ向かって `Unauthorized` で断られ、自分のコメントは残って誤りを知らせた。自分の別のタブや端末のコメントは他人のもの (`isMine: false`) になり、読み直すまで削除できなかった。
|
|
82
|
+
- **誤りの知らせはモバイルのオーバーレイを開いている間も操作できる**: 内蔵の知らせ (`role="alert"`) は、オーバーレイを開いている間はダイアログの中 (日報と閉じるボタンの間) に描き、閉じた後はページの置き場へ戻る。以前は知らせをプロバイダーの子の隣に描いたので、オーバーレイのモーダルな `<dialog>` の外で不活性になり、読み上げの木にも無く、押すことも閉じることもできなかった (パッケージの知らせを使うホストでは、オーバーレイの中のどの失敗も見えないままだった)。
|
|
83
|
+
- **誤りの知らせは時間で消えず、何も覆わない**: 知らせは利用者が閉じるボタンか、中にフォーカスがある間の `Escape` で消すまで残り (WCAG 2.2.3)、新しい失敗は文言を置き換える。`Escape` は知らせだけを消し、オーバーレイを閉じない。フォーカスを持ったまま消えるときは、来た元へ、無ければビューの行カーソルへ、それも無ければ知らせを置いたダイアログへ戻す。
|
|
84
|
+
知らせは流れの中の置き場 (ページの下・オーバーレイの中) に描くので、フォーカスを持つ行にもボタンにも重ならない。以前の知らせは 8 秒で消え (フォーカスを持っていれば body へ落ちた)、`Escape` は効かず、下端に固定したトーストとして末尾に揃えた DetailList の行の 28 px とアウトラインの下の縁を覆った。
|
|
85
|
+
- **自分を外す再試行ボタンはフォーカスを落とさず、ストリームの状態は読み上げる**: 見出しの進捗の札は局面ごとに中身だけを替える 1 つの入れ物で、ページの読み込み中と読み込みの失敗は中身だけを替える 1 つの状態の面。どちらの再試行も、押されて自分が外れる前に入れ物か面へフォーカスを渡し、面がフォーカスを持ったまま本体へ入れ替わるとビューの行カーソル (無ければページの状態の領域) へ渡す。
|
|
86
|
+
ページの常設の見えない状態の領域が、読み込み中と再接続中を `role="status"` で、失敗を `role="alert"` で知らせる。以前はどちらの再試行もフォーカスを body へ落とし、データ未受信の読み込みの失敗は読み上げの領域を持たず、読み込み中の唯一の領域 (再接続中の札) は同じ確定で外れた (WCAG 2.4.3、4.1.3)。
|
|
87
|
+
- **選択されていない端の行の `Home` / `End`**: フォーカスがもう先頭 (末尾) の行にあり、その行が選択されていなければ、`Home` (`End`) はその行をその場で選ぶ (両ビュー)。以前は何もしなかったので、選択中の日報を消して末尾の行にフォーカスだけが残ると、`End` を押しても側面ペインは選択を促す表示のままだった。矢印と `PageUp` / `PageDown` は、端で動かなければ今までどおり何も選ばない。
|
|
88
|
+
- **同じミリ秒の 2 つの操作は別の照合用 ID を持つ**: 楽観的な日報とコメントの仮の id (その 10 進の文字が照合用 ID) は、ページに 1 つの列から、前に引いた値より必ず小さく、壁時計のミリ秒の負の数以下の値を引く (`drawTemporaryId`)。以前は `-Date.now()` だったので、同じミリ秒の 2 つの操作が 1 つの照合用 ID を分け合い、エコーと失敗を別の操作に結び付けることがあった。
|
|
89
|
+
- **もう無い日報の削除は済んだものとみなす**: 日報の削除に 404 が返ったら、巻き戻しも誤りの知らせもせずに、キャッシュと編集の項目を捨てる (一覧の行は外したまま)。ほかの操作の 404 は今までどおり巻き戻して知らせる。
|
|
90
|
+
- **キャッシュを待つ SSE の知らせは期限で必ず刈る**: 自分の操作のエコーの抑止と、キャッシュをまだ持たない日報への知らせの待ちは、どちらも期限のある 1 つの台帳 (`createExpiringLedger`) が持ち、どの日報の足し・読みでも期限の過ぎた項目を先頭から外して、待ちのキャッシュの購読もやめる。以前の待ちは、同じ日報の次の知らせ・キャッシュの書き込み・日報の削除・アンマウントでしか期限を確かめなかったので、キャッシュされない 50 件の日報への知らせが 50 件の購読を残し、期限の後も 51 件が残った。
|
|
91
|
+
- **操作の錠は操作ごと**: `acquireMutationLock` は錠ごとの返し方を返し、返し方はその錠だけを 1 回だけ返す。SSE のコメントの変更は錠に触れずに変更の時刻だけを記録し (`markReportMutated`)、作成の後の 1 秒の錠は後の錠で延びるだけ。以前は日報ごとに 1 つの錠で、SSE のコメントや重なった操作が進行中の操作の錠や作成の後の錠を外した。
|
|
92
|
+
- **1/8 の倍数の画素密度でも行とタイルは装置の画素に乗る**: 装置の画素の格子の定義域は 1 から 3 までの 1/8 の倍数のすべて (412 px 幅の多くの Android の端末の既定 2.625 を含む)。中身が高さを決める箱 (DetailList の行の本体・誤りの知らせ) と添付のタイルの寄せは、格子のブロックの刻み (カスタムプロパティ `--aqdr-lattice-block`。1/4 の倍数で 4 px、1/8 の奇数倍で 8 px) へ切り上げ、ホバーの浮き上がりは 12 個の画素密度で整数の装置の画素へ上書きする。
|
|
93
|
+
以前は 1/4 の倍数だけを定義域にしたので、2.625 では 4 の奇数倍の行やタイルの段の下のすべてが装置の画素の半分ずれ (980 px の行の下端が 6,478.5 装置画素、オーバーレイのタイルの段の送りが 188 CSS px = 493.5 装置画素)、面の縁が 2 行の装置の画素へにじんだ。
|
|
94
|
+
- **対を持たないサロゲートを含むファイル名の添付も配る**: `Content-Disposition` の `filename*` は名前の整った形 (対を持たないサロゲートは U+FFFD) の UTF-8 を符号化し、行から決まるヘッダーの部品は読み取りの前に作る。以前は符号化が `URIError` を投げ、原本を上限まで読んだ後に 500 (`URI malformed`) で答えたので、取込元の切り詰めでサロゲートの対が割れた名前の添付は、どの要求でも配れなかった。
|
|
95
|
+
- **JSON の応答は要求ごとの記録を書かない**: `jsonResponseWithETag` はログを書かない純粋な組み立てで、JSON の答えの跡は API の経路が工場のロガーへ書く `debug` の 1 行 (`<状態> endpoint=<名前> etag_match=<true|false>`) だけ。要求のヘッダーの値も、エンドポイントより前の答え (401・404・405) も書かない。
|
|
96
|
+
以前はどの JSON の応答も、未認証の 401 を含めて、モジュールの console のロガーへ `info` の 1 行を `If-None-Match` の値ごと書いたので (16,000 バイトの `If-None-Match` で 16,125 バイトの行)、未認証の送り手が行の数も大きさも決められ、ホストのロガーでは行き先も量も変えられなかった。
|
|
97
|
+
|
|
98
|
+
### Changed
|
|
99
|
+
|
|
100
|
+
- **キャッシュを迂回する読み取りはキーごとに合わせる**: `SqlResultCache` の迂回の取得 (`forceRefresh`) は、キーごとに走る取得 1 本と待つ取得 1 本までで、同時に届いた迂回の読み取りはいくつでも多くとも 2 回の取得で答え、どの呼び出しも届いた後に始まった取得の結果を受け取る。走る迂回の取得には迂回しない読み手も相乗りし、その間に無効化されたら結果をバケットに書かない。以前の迂回は取得を合わせず登録もしなかったので、同時の 20 本の迂回は 20 回の問い合わせになった。
|
|
101
|
+
- **action のレートの上限は共有の留まる時間から導く**: 側面ペインの自動既読の留まる時間 (`AUTO_READ_DWELL_MS` = 500 ms) をクライアントとサーバーが 1 つの定義から読み、上限は留まるペインの余裕 5 × ⌈60,000 ÷ 500⌉ = 600 (値は変わらない)。留まる時間を縮めれば上限も上がる (以前はサーバーが 500 を書き写していたので、クライアントだけを縮めると、留まった複数のペインの自動既読がどの spec も通ったまま 429 になった)。上限はホストの設定にしない。
|
|
102
|
+
- **合わない答えは合わなかった欄を名乗る**: パッケージのクライアントは、送った操作の答えでない action の答えを `[daily-report] <intent> answered a body that is not its result (<パス>: <code>; …)` で、エンドポイントのスキーマに合わない答えを `… does not match its schema (<パス>: <code>; …)` で拒む (受け取った値は書かない)。以前はどちらもパスを名乗らなかった。
|
|
103
|
+
- **ids のストリームのクエリは 1 組の符号化と解釈**: クライアントの再開と強制の再取得の URL も、サーバーの解釈も、共有の表のクエリの名前を 1 組の関数で書き・読む。片方だけの改名は往復で落ちる (以前はクライアントが 4 つの名前を字面で書いたので、改名はどの spec も通ったまま、どの再開も先頭からの全量の再送にした)。
|
|
104
|
+
- **開発者向け**:
|
|
105
|
+
- ID のワイヤの定義域は `src/shared/ids.ts` (`isPositiveSafeInteger`・`dailyReportIdSchema`) の 1 つで、クエリとフォームの文字の解釈 (`parseCanonicalPositiveId`・`parseCanonicalNonNegativeInteger`・`parseWireBoolean`・`parseForceRefreshParam`) は `src/server/wire-params.ts` から `src/shared/wire-text.ts` へ移った。SSE のメッセージのどの ID の欄も同じ定義域で読む (以前の素の `z.number()` は 0・負の数・小数を通した)。合わない値の説明は `src/shared/wire-mismatch.ts` (`describeWireMismatch`)。
|
|
106
|
+
- サーバーの action の 200 の答えは、指示から組む 1 つの部品 (`answerActionCommand`) だけが組む。
|
|
107
|
+
- 同時実行のゲートは `src/server/attachment-delivery/concurrency-gate.ts` から `src/server/concurrency-gate.ts` へ移り (名前と引数の形は同じで、枠を取らない確かめ `canAcquire(owner)` を足した)、過負荷の 503 の `Retry-After` (`retryAfterHeaders`) は `src/server/response.ts` へ、整数の設定の検証 (`requireIntegerSetting`・`resolveIntegerSetting`) は `src/shared/config-errors.ts` へ移った。`src/server/rate-limit.ts` はどの機能のフォルダーも読まず、拒否の理由の名前は各経路が自分で決める (`RateLimitReason` は無い)。
|
|
108
|
+
- 追加した行の網羅率の検査と値の置き換えの検出は、リポジトリの共有のモジュール (`.config/scripts/lib/changed-lines-coverage.mjs`・`.config/scripts/lib/no-fallback.mjs`) に 1 つずつあり、パッケージの `scripts/` は自分の免除と例外のファイルを渡す薄い入口。値の置き換えの検出は右辺の関数の呼び出し・値の作成・タグ付きテンプレートも数え (`a ?? f()` と `a || f()`)、レビューした例外は `scripts/no-fallback-exceptions.json` に置く。
|
|
109
|
+
- docstring とコメントの言語の検査は本番のコードを違反 0 に保ち、基準 (`docstring-baseline.json`) に本番のコードの項目を許さない (数を数えるのは spec とテスト用の部品だけ)。
|
|
110
|
+
- 共有エントリ (公開した名前) とサーバーエントリ (迂回の合わせ方・ストリームの枠) のバンドルの基準を、見直した増加として記録した。
|
|
111
|
+
|
|
112
|
+
### Added
|
|
113
|
+
|
|
114
|
+
- 共有エントリ (`@aiquants/daily-report`) が action と API のワイヤの契約を公開する: `DAILY_REPORT_ACTION_INTENTS`・`DAILY_REPORT_ACTION_FIELDS`・`encodeDailyReportActionCommand`・`parseDailyReportActionResult` (`{ result }` か、合わなかった欄の説明の `{ mismatch }` を返す)・`DAILY_REPORT_API_ENDPOINTS`・`DAILY_REPORT_API_QUERY_PARAMS`・`DAILY_REPORT_CLIENT_TEMP_ID_PATTERN` と、型の `DailyReportActionIntent`・`DailyReportActionCommand`・`DailyReportActionResult`・`DailyReportActionResultOf`・`DailyReportActionFailure`。
|
|
115
|
+
パッケージのクライアントの外から action と API を呼ぶホストは、手で書き写した 2 つ目の契約の代わりにこれを読む。0.33.0 の Breaking の移行の手引きが答えを読む型として挙げた `ActionResult` は、この `DailyReportActionResult` (以前は公開していなかった)。
|
|
116
|
+
- server の `readDailyReportSseStreamEntry` (Redis のストリームのエントリ 1 件を、共有リーダーと同じく 1 度だけ読む。自分のリーダーを渡すホストのため)。
|
|
117
|
+
- キャッシュを迂回する読み取りの閲覧者ごとの上限: `business-date`・`report`・ids のストリームの `forceRefresh=true` は、閲覧者 1 人あたり 1 分に 60 件まで (ハンドラー工場ごと、つまりワーカーのプロセスごと。認証が返す外部の利用者 ID で数える)。上限はパッケージのクライアント自身の迂回 (ビュー 5 つ × 強制の再走査 2 回 × 要求 6 回) から導く。
|
|
118
|
+
超えた要求は引数の 400 の後、どのサービスの呼び出しよりも前に 429 (`{"error":{"message":"Too many requests"}}`、`Retry-After: 60`) で断る。行は閲覧者の窓ごとに最初の `429 endpoint=<名前> reason=refresh_rate_limit` と、窓の終わりの `refresh_rate_limit_suppressed count=<N> since=<…> route=api` の 2 行まで (warn。既定のロガーの接頭辞は `[DailyReportAPI]`。利用者 ID を書かない)。
|
|
119
|
+
- 閲覧者ごとのストリームの枠: 閲覧者 1 人がワーカーのプロセス 1 つで同時に持てる SSE と ids のストリームは合わせて 32 本 (`DAILY_REPORT_STREAMS_PER_VIEWER`: ビュー 1 つの 2 本 × 16 ビュー)。枠をすべて持つ閲覧者の次のストリームは、本体の仕事を始めずに 503 (`Retry-After: 5`。SSE は本文 `Too many streams`、ids のストリームは `{"error":{"message":"Too many streams"}}`) で断り、枠はストリームが終わる後始末で返す。
|
|
120
|
+
`HEAD` は枠を取らずに確かめるだけ。行は閲覧者の窓ごとに最初の `503 <sse|ids-stream> viewer=<内部 ID> reason=streams_per_viewer` と、窓の終わりの `streams_per_viewer_suppressed count=<N> since=<…> viewer=<内部 ID> routes=sse:<n>,ids-stream:<n>` の 2 行まで (warn。既定のロガーの接頭辞は `[DailyReportStreams]`)。以前は 1 人の閲覧者の 2,000 本の同時の SSE をどれも受け、それぞれが 60 秒ごとに可視集合を解決し直した (毎秒約 33 回の認可の問い合わせ)。
|
|
121
|
+
|
|
122
|
+
### Breaking
|
|
123
|
+
|
|
124
|
+
- action の 200 の答えの日報の ID (`reportHubId`) と消したコメントの ID (`deletedCommentId`) は、SSE のイベントと同じ JSON の数 (1 から 2^53 − 1 までの整数)。以前は 10 進の文字だった。
|
|
125
|
+
Migration: 答えを自分で読むホストは、2 つの ID を数として読む (`parseDailyReportActionResult` で読めば型が合う)。答えを返す代役 (テストの stub など) は ID を数で返す。
|
|
126
|
+
- server の `jsonResponseWithETag(request, cookie, payload, status = 200)` は 5 番目の引数 (ロガー) を持たず、ログを書かない。
|
|
127
|
+
Migration: ロガーを渡していた呼び出しは引数を外し、必要な記録は呼び出し側が自分のロガーで書く。
|
|
128
|
+
- キャッシュを迂回する読み取りの閲覧者ごとの上限 (上の Added): 1 人の閲覧者が 1 つのワーカーへ 1 分に 60 件を超えて `forceRefresh=true` を送ると 429。
|
|
129
|
+
Migration: パッケージのクライアント以外から `forceRefresh=true` を送るホストは 429 を失敗として扱い、`Retry-After` の後に送り直す。
|
|
130
|
+
- 閲覧者ごとのストリームの枠 (上の Added): 1 人の閲覧者が 1 つのワーカーで 32 本を超えて SSE と ids のストリームを同時に開くと 503。
|
|
131
|
+
Migration: パッケージのクライアント以外からストリームを開くホストは、使い終えたストリームを閉じ、503 を一時的な失敗として `Retry-After` の後に開き直す。
|
|
132
|
+
- ピアの `@aiquants/virtualscroll` の下限を 3.14.0 へ上げた (`peer-floors.json`)。両ビューが 3.14.0 の変更に頼る所は無いが、この版の試験はすべて 3.14.0 の上で通したので、公開する範囲 (`^3.14.0`) と文書の下限をそれに合わせた。
|
|
133
|
+
Migration: `@aiquants/virtualscroll` を 3.14.0 以降へ上げる。
|
|
134
|
+
|
|
5
135
|
## 0.33.0 (2026-10-07)
|
|
6
136
|
|
|
7
137
|
0.32.0 の続き: 一覧の末尾の近くの削除で錨の日報が跳ばないこと、action の照合用 ID を 2 つの正準の形だけにすること、SSE のエントリをプロセスで 1 度だけ読むことと 1 回の読み取りをバイトの予算で縛ること、action の閲覧者ごとのレートの上限、ids ストリームのアイテムの publish をトランジションの優先度で届けることと、見出しの件数とビューの本体を配置の境界にすること、action と JSON のエンドポイントの共有のワイヤの契約、後で呼ばれるタイマーを持たない期限の記録、原本の HEAD の大きさの契約。どれも README の該当の節が今の振る舞いを述べる。
|