@aiquants/daily-report 0.20.0 → 0.20.1

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.
Files changed (115) hide show
  1. package/dist/client.d.mts +11 -706
  2. package/dist/client.d.ts +11 -706
  3. package/dist/client.js +0 -1
  4. package/dist/client.mjs +0 -1
  5. package/dist/index.d.mts +5 -197
  6. package/dist/index.d.ts +5 -197
  7. package/dist/index.js +0 -1
  8. package/dist/index.mjs +0 -1
  9. package/dist/logger-D3krZrNK.d.mts +0 -14
  10. package/dist/logger-D3krZrNK.d.ts +0 -14
  11. package/dist/server.d.mts +114 -744
  12. package/dist/server.d.ts +114 -744
  13. package/dist/server.js +0 -1
  14. package/dist/server.mjs +0 -1
  15. package/dist/sse-schema-BdUGThiz.d.ts +1025 -1009
  16. package/dist/sse-schema-ChSFm-4q.d.mts +1025 -1009
  17. package/dist/types-CqgYQgbH.d.mts +0 -34
  18. package/dist/types-CqgYQgbH.d.ts +0 -34
  19. package/package.json +7 -8
  20. package/dist/client.js.map +0 -1
  21. package/dist/client.mjs.map +0 -1
  22. package/dist/index.js.map +0 -1
  23. package/dist/index.mjs.map +0 -1
  24. package/dist/server.js.map +0 -1
  25. package/dist/server.mjs.map +0 -1
  26. package/src/client/components/business-day-thumb-overlay.tsx +0 -19
  27. package/src/client/components/daily-report-attachment-indicator.spec.tsx +0 -51
  28. package/src/client/components/daily-report-attachment-indicator.tsx +0 -45
  29. package/src/client/components/daily-report-attachment-list.spec.tsx +0 -94
  30. package/src/client/components/daily-report-attachment-list.tsx +0 -112
  31. package/src/client/components/daily-report-comment-item.tsx +0 -89
  32. package/src/client/components/daily-report-comment-section.tsx +0 -166
  33. package/src/client/components/daily-report-detail-list.tsx +0 -842
  34. package/src/client/components/daily-report-edit-form.tsx +0 -87
  35. package/src/client/components/daily-report-ids-stream-status.spec.tsx +0 -93
  36. package/src/client/components/daily-report-ids-stream-status.tsx +0 -67
  37. package/src/client/components/daily-report-list.tsx +0 -1232
  38. package/src/client/components/daily-report-page.spec.tsx +0 -119
  39. package/src/client/components/daily-report-page.tsx +0 -140
  40. package/src/client/components/daily-report-resize-panels.spec.tsx +0 -307
  41. package/src/client/components/daily-report-resolved-content.tsx +0 -207
  42. package/src/client/components/daily-report-scroll-restoration.spec.tsx +0 -422
  43. package/src/client/components/report-views.spec.tsx +0 -375
  44. package/src/client/components/unread-indicator.tsx +0 -13
  45. package/src/client/config-context.tsx +0 -184
  46. package/src/client/contexts/daily-report-action-context.spec.tsx +0 -433
  47. package/src/client/contexts/daily-report-action-context.tsx +0 -1147
  48. package/src/client/contexts/daily-report-error-context.spec.tsx +0 -66
  49. package/src/client/contexts/daily-report-error-context.tsx +0 -98
  50. package/src/client/hooks/use-animated-number.spec.ts +0 -103
  51. package/src/client/hooks/use-animated-number.ts +0 -69
  52. package/src/client/hooks/use-daily-report-comments.ts +0 -73
  53. package/src/client/hooks/use-daily-report-sse-connection.ts +0 -86
  54. package/src/client/hooks/use-daily-report.spec.ts +0 -546
  55. package/src/client/hooks/use-daily-report.ts +0 -549
  56. package/src/client/hooks/use-dynamic-viewport-height.ts +0 -127
  57. package/src/client/hooks/use-responsive-layout.spec.ts +0 -74
  58. package/src/client/hooks/use-responsive-layout.ts +0 -63
  59. package/src/client/route-helpers.spec.ts +0 -100
  60. package/src/client/route-helpers.ts +0 -61
  61. package/src/client/streaming/daily-report-ids-stream-client.spec.ts +0 -910
  62. package/src/client/streaming/daily-report-ids-stream-client.ts +0 -730
  63. package/src/client/streaming/daily-report-ids-stream-session.spec.ts +0 -401
  64. package/src/client/streaming/daily-report-ids-stream-session.ts +0 -319
  65. package/src/client/ui/button.tsx +0 -42
  66. package/src/client/ui/cn.ts +0 -14
  67. package/src/client/ui/input.tsx +0 -21
  68. package/src/client/ui/label.tsx +0 -16
  69. package/src/client/ui/switch.tsx +0 -19
  70. package/src/client/ui/tabs.tsx +0 -40
  71. package/src/client/ui/textarea.tsx +0 -19
  72. package/src/client/utils/constants.spec.ts +0 -96
  73. package/src/client/utils/constants.ts +0 -84
  74. package/src/client.ts +0 -28
  75. package/src/index.ts +0 -11
  76. package/src/lucide-icons.d.ts +0 -6
  77. package/src/server/authz.spec.ts +0 -57
  78. package/src/server/authz.ts +0 -99
  79. package/src/server/cache.spec.ts +0 -556
  80. package/src/server/cache.ts +0 -303
  81. package/src/server/etag.ts +0 -18
  82. package/src/server/external-source.ts +0 -60
  83. package/src/server/handlers.action.spec.ts +0 -44
  84. package/src/server/handlers.attachment.spec.ts +0 -470
  85. package/src/server/handlers.ids-stream.spec.ts +0 -618
  86. package/src/server/handlers.ts +0 -1638
  87. package/src/server/handlers.unauthorized-cookie.spec.ts +0 -187
  88. package/src/server/handlers.visibility.spec.ts +0 -774
  89. package/src/server/ports.ts +0 -222
  90. package/src/server/response.ts +0 -37
  91. package/src/server/schema.spec.ts +0 -30
  92. package/src/server/schema.ts +0 -344
  93. package/src/server/service.spec.ts +0 -1130
  94. package/src/server/service.ts +0 -2045
  95. package/src/server/sse-reader.spec.ts +0 -302
  96. package/src/server/sse-reader.ts +0 -267
  97. package/src/server/test-helpers/handlers-config.ts +0 -321
  98. package/src/server/transaction-retry.spec.ts +0 -63
  99. package/src/server/visibility.spec.ts +0 -403
  100. package/src/server/visibility.ts +0 -373
  101. package/src/server.spec.ts +0 -160
  102. package/src/server.ts +0 -131
  103. package/src/shared/business-date.spec.ts +0 -82
  104. package/src/shared/business-date.ts +0 -104
  105. package/src/shared/comment-adapter.spec.ts +0 -38
  106. package/src/shared/comment-adapter.ts +0 -80
  107. package/src/shared/ids-stream.spec.ts +0 -154
  108. package/src/shared/ids-stream.ts +0 -279
  109. package/src/shared/logger.ts +0 -47
  110. package/src/shared/sse-schema.spec.ts +0 -50
  111. package/src/shared/sse-schema.ts +0 -198
  112. package/src/shared/text-utils.spec.ts +0 -42
  113. package/src/shared/text-utils.ts +0 -65
  114. package/src/shared/types.ts +0 -109
  115. package/src/styles/standalone.entry.css +0 -51
@@ -1,187 +0,0 @@
1
- /**
2
- * Unauthorized responses must carry the session-destroy Set-Cookie.
3
- * 未認証応答はセッション破棄の Set-Cookie を必ず載せること。
4
- *
5
- * このファイルが存在する理由: `@aiquants/auth-react-router` v0.8.0 で `failureRedirect: null` の
6
- * 契約が変わり、期限切れ + リフレッシュ失敗の経路が「リダイレクトを throw する」から
7
- * 「`{ cookie }` を返す」になった。呼び出し側がこの `cookie` を捨てると、**サーバーは破棄した
8
- * つもりでブラウザには無効なセッションが残り続ける**。以後のリクエストは毎回リフレッシュを
9
- * 試みて失敗し、ユーザーはログインし直すまで壊れた状態から抜けられない。
10
- *
11
- * 落とすのは 1 行の削除で足り、応答コード (401) は変わらないため、ステータスだけを見る
12
- * テストでは検出できない。ここで各エンドポイントの Set-Cookie を明示的に固定する。
13
- */
14
-
15
- import { readFile } from "node:fs/promises"
16
- import path from "node:path"
17
- import { fileURLToPath } from "node:url"
18
- import { describe, expect, it } from "vitest"
19
- import { createDailyReportHandlers } from "./handlers"
20
- import { makeHandlersFixture } from "./test-helpers/handlers-config"
21
-
22
- /** 期限切れセッションの破棄で返る Set-Cookie を模した値。 */
23
- const DESTROY_COOKIE = "__session=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT"
24
-
25
- /**
26
- * 封印テストが走査する実装ファイル。
27
- * このテスト自身の位置から解決する (cwd 依存にすると、パッケージルート以外から
28
- * 実行した瞬間に走査対象を見失って封印が静かに空振りする)。
29
- */
30
- const HANDLERS_SOURCE_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "handlers.ts")
31
-
32
- /** トークン更新で再発行される Set-Cookie を模した値 (破棄ではなく更新)。 */
33
- const REFRESH_COOKIE = "__session=refreshed; Path=/; HttpOnly"
34
-
35
- /** 未認証かつ破棄 cookie 有りのハンドラ群を組む。 */
36
- const unauthenticatedHandlers = () => createDailyReportHandlers(makeHandlersFixture({ user: null, cookie: DESTROY_COOKIE }).config)
37
-
38
- /** 未認証だがセッション破棄を伴わない (cookie 無し) ハンドラ群を組む。 */
39
- const unauthenticatedWithoutCookie = () => createDailyReportHandlers(makeHandlersFixture({ user: null }).config)
40
-
41
- const args = (url: string, endpoint: string, method = "GET") => ({
42
- request: new Request(url, { method }),
43
- params: { endpoint },
44
- })
45
-
46
- describe("未認証 401 応答の Set-Cookie 転送", () => {
47
- it("apiAction は破棄 cookie を 401 に載せる", async () => {
48
- const res = await unauthenticatedHandlers().api.action(args("http://localhost/daily_report/api/action", "action", "POST"))
49
- expect(res.status).toBe(401)
50
- expect(res.headers.get("Set-Cookie")).toBe(DESTROY_COOKIE)
51
- // 既存の契約 (JSON 応答) は維持する
52
- expect(res.headers.get("Content-Type")).toBe("application/json")
53
- })
54
-
55
- it("sseLoader は破棄 cookie を 401 に載せる", async () => {
56
- const res = await unauthenticatedHandlers().sse.loader(args("http://localhost/daily_report/sse/report", "report"))
57
- expect(res.status).toBe(401)
58
- expect(res.headers.get("Set-Cookie")).toBe(DESTROY_COOKIE)
59
- })
60
-
61
- it("破棄が発生していない未認証では Set-Cookie を付けない (無い cookie を捏造しない)", async () => {
62
- const handlers = unauthenticatedWithoutCookie()
63
- const action = await handlers.api.action(args("http://localhost/daily_report/api/action", "action", "POST"))
64
- const sse = await handlers.sse.loader(args("http://localhost/daily_report/sse/report", "report"))
65
- expect(action.status).toBe(401)
66
- expect(sse.status).toBe(401)
67
- expect(action.headers.get("Set-Cookie")).toBeNull()
68
- expect(sse.headers.get("Set-Cookie")).toBeNull()
69
- })
70
- })
71
- describe("認証済み応答の Set-Cookie 転送", () => {
72
- /** 認証済み + トークン更新 cookie 有りのハンドラ群を組む。 */
73
- const refreshedHandlers = () => createDailyReportHandlers(makeHandlersFixture({ cookie: DESTROY_COOKIE }).config)
74
-
75
- it("apiAction は成功系でない分岐でも更新 cookie を載せる", async () => {
76
- // 30 箇所ある return のうち 1 つでも付け忘れると、ブラウザは期限切れトークンを持ち続け、
77
- // 以後のリクエストが毎回リフレッシュを試みて収束しない。出口 1 箇所で付けることで担保する
78
- const res = await refreshedHandlers().api.action({
79
- request: new Request("http://localhost/daily_report/api/unknown", { method: "POST" }),
80
- params: { endpoint: "unknown" },
81
- })
82
- expect(res.status).toBe(404)
83
- expect(res.headers.get("Set-Cookie")).toBe(DESTROY_COOKIE)
84
- })
85
-
86
- it("更新が無ければ Set-Cookie を付けない", async () => {
87
- const res = await createDailyReportHandlers(makeHandlersFixture({}).config).api.action({
88
- request: new Request("http://localhost/daily_report/api/unknown", { method: "POST" }),
89
- params: { endpoint: "unknown" },
90
- })
91
- expect(res.status).toBe(404)
92
- expect(res.headers.get("Set-Cookie")).toBeNull()
93
- })
94
-
95
- // #2356 は apiAction の全応答へ cookie を載せたが、sseLoader は 401 だけで止まっていた。
96
- // トークンが更新されたリクエストがたまたま SSE 接続だと、更新後のトークンがブラウザへ
97
- // 届かず以降のリクエストが毎回リフレッシュをやり直す。SSE は長命なぶん更新を担いやすい
98
- describe("sseLoader は 401 以外の応答でもセッション cookie を運ぶ", () => {
99
- /** 認証済み + トークン更新 cookie 有りのハンドラ群を組む。 */
100
- const refreshedHandlers = (overrides: Parameters<typeof makeHandlersFixture>[0] = {}) => createDailyReportHandlers(makeHandlersFixture({ cookie: REFRESH_COOKIE, ...overrides }).config)
101
-
102
- it("内部ユーザー ID を解決できない 403 でも運ぶ", async () => {
103
- const res = await refreshedHandlers({ internalUserId: null }).sse.loader(args("http://localhost/daily_report/sse/updates", "updates"))
104
- expect(res.status).toBe(403)
105
- expect(res.headers.get("Set-Cookie")).toBe(REFRESH_COOKIE)
106
- })
107
-
108
- it("未知エンドポイントの 404 でも運ぶ", async () => {
109
- const res = await refreshedHandlers().sse.loader(args("http://localhost/daily_report/sse/unknown", "unknown"))
110
- expect(res.status).toBe(404)
111
- expect(res.headers.get("Set-Cookie")).toBe(REFRESH_COOKIE)
112
- })
113
-
114
- it("ストリーム開始の 200 でも運ぶ (SSE 本来のヘッダーは維持する)", async () => {
115
- const res = await refreshedHandlers().sse.loader(args("http://localhost/daily_report/sse/updates", "updates"))
116
- expect(res.status).toBe(200)
117
- expect(res.headers.get("Set-Cookie")).toBe(REFRESH_COOKIE)
118
- expect(res.headers.get("Content-Type")).toBe("text/event-stream")
119
- expect(res.headers.get("Cache-Control")).toBe("no-cache, no-transform")
120
- await res.body?.cancel()
121
- })
122
-
123
- it("更新が無ければ Set-Cookie を付けない (無い cookie を捏造しない)", async () => {
124
- const res = await createDailyReportHandlers(makeHandlersFixture({}).config).sse.loader(args("http://localhost/daily_report/sse/updates", "updates"))
125
- expect(res.headers.get("Set-Cookie")).toBeNull()
126
- await res.body?.cancel()
127
- })
128
- })
129
-
130
- // apiAction の 30 箇所の応答はすべて単一の `respond` ヘルパーを通る。個別に 30 本の
131
- // テストを置くより、**ヘルパーを迂回する応答が無いこと**を構造で封印する方が確実である
132
- // (1 箇所だけ直接 `jsonData(...)` を返す変更が入っても、状態を作れるエンドポイントの
133
- // テストしか無ければ気づけない)。ソースを AST ではなく素直に走査するのは、対象が
134
- // 「この関数の中で return されている呼び出しの名前」という単純な性質だからである。
135
- describe("apiAction の応答経路の封印", () => {
136
- it("apiAction 内に respond を迂回する応答が存在しない", async () => {
137
- const source = await readFile(HANDLERS_SOURCE_PATH, "utf-8")
138
- const start = source.indexOf("const respond = (payload: unknown")
139
- expect(start).toBeGreaterThan(0)
140
- // apiAction の本体は respond 定義から次のトップレベル関数宣言まで
141
- const rest = source.slice(start + 10)
142
- const nextDecl = rest.search(/\n {4}const \w+ = async \(/)
143
- const apiActionBody = source.slice(start, nextDecl >= 0 ? start + 10 + nextDecl : source.length)
144
-
145
- // 応答を作る**あらゆる形**を拾う。`jsonData` / `data` だけを見ていると
146
- // `new Response(...)` や `jsonResponseWithETag(...)` での迂回を見逃す
147
- // (どちらも同ファイル内で実際に使われている構文である)
148
- const bypasses = [...apiActionBody.matchAll(/return\s+(new\s+Response|jsonData|jsonResponseWithETag|data)\s*\(/g)].map((m) => m[0].replace(/\s+/g, " "))
149
- expect(bypasses, `respond を通さない応答が ${bypasses.length} 件ある。cookie が落ちるので respond を使うこと`).toEqual([])
150
- // 走査が空振りしていないことも確かめる (対象を取り違えたら封印は無意味)
151
- expect(apiActionBody.match(/respond\(/g)?.length ?? 0).toBeGreaterThan(20)
152
- })
153
-
154
- it("respond は setCookie を必ず渡す", async () => {
155
- const source = await readFile(HANDLERS_SOURCE_PATH, "utf-8")
156
- // 完全一致で固定すると無害な整形で落ちる。「respond の定義が setCookie を
157
- // 渡していること」だけを見る (空白や改行の入り方には依存しない)
158
- // 定義の開始から `setCookie` を含む呼び出しの閉じ括弧までを、改行の入り方に依存せず取る
159
- const declaration = source.match(/const respond = \([\s\S]{0,400}?jsonData\([\s\S]{0,200}?\)/)?.[0] ?? ""
160
- expect(declaration, "respond の定義が見つからない (封印が空振りしている)").toContain("jsonData")
161
- expect(declaration, "respond が setCookie を渡していない").toContain("setCookie: cookie")
162
- })
163
- })
164
-
165
- // apiAction には外側 try/catch が無く、`respond` を通らない例外 (service / DB / Redis の失敗) が
166
- // ハンドラの外へ抜けていた。抜けると 500 にセッション cookie が載らず、トークン更新が
167
- // ブラウザへ届かない。apiLoader は元から同じ形で包んでいた
168
- describe("apiAction は例外経路でもセッション cookie を運ぶ", () => {
169
- it("service の例外は 500 の JSON になり、更新 cookie を載せる", async () => {
170
- const handlers = createDailyReportHandlers(makeHandlersFixture({ cookie: REFRESH_COOKIE, userIdLookupError: new Error("db pool exhausted (injected)") }).config)
171
- const res = await handlers.api.action(args("http://localhost/daily_report/api/action", "action", "POST"))
172
-
173
- expect(res.status).toBe(500)
174
- expect(res.headers.get("Set-Cookie")).toBe(REFRESH_COOKIE)
175
- expect(res.headers.get("Content-Type")).toBe("application/json")
176
- })
177
-
178
- it("未認証で例外が起きても破棄 cookie を落とさない", async () => {
179
- // 未認証は例外より前に返るが、cookie の転送経路が同じであることを固定する
180
- const handlers = createDailyReportHandlers(makeHandlersFixture({ user: null, cookie: DESTROY_COOKIE, userIdLookupError: new Error("db pool exhausted (injected)") }).config)
181
- const res = await handlers.api.action(args("http://localhost/daily_report/api/action", "action", "POST"))
182
-
183
- expect(res.status).toBe(401)
184
- expect(res.headers.get("Set-Cookie")).toBe(DESTROY_COOKIE)
185
- })
186
- })
187
- })