@aiquants/daily-report 0.18.0 → 0.18.2
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/README.md +2 -2
- package/dist/client.d.mts +6 -3
- package/dist/client.d.ts +6 -3
- package/dist/client.js +5 -5
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +5 -5
- package/dist/client.mjs.map +1 -1
- package/dist/server.d.mts +17 -7
- package/dist/server.d.ts +17 -7
- package/dist/server.js +10 -10
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +10 -10
- package/dist/server.mjs.map +1 -1
- package/dist/styles/daily-report.standalone.css +1 -1
- package/package.json +6 -4
- package/src/client/components/daily-report-list.tsx +199 -80
- package/src/client/components/daily-report-resize-panels.spec.tsx +305 -0
- package/src/client/hooks/use-responsive-layout.ts +34 -27
- package/src/server/handlers.ts +218 -176
- package/src/server/handlers.unauthorized-cookie.spec.ts +187 -0
- package/src/server/ports.ts +6 -1
- package/src/server/service.spec.ts +1 -1
- package/src/server/test-helpers/handlers-config.ts +16 -3
- package/src/server.spec.ts +7 -7
|
@@ -0,0 +1,187 @@
|
|
|
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
|
+
})
|
package/src/server/ports.ts
CHANGED
|
@@ -53,7 +53,12 @@ export type DailyReportAuthResult = {
|
|
|
53
53
|
* `failureRedirect` が文字列の場合、未認証時は実装側で redirect を throw すること。
|
|
54
54
|
* null の場合は throw せず `user` 無しで解決する。
|
|
55
55
|
*/
|
|
56
|
-
export
|
|
56
|
+
export interface DailyReportAuthenticate {
|
|
57
|
+
/** 失敗時は必ずリダイレクトを throw するため、正常復帰時の `user` は常に存在する。 */
|
|
58
|
+
(request: Request, options: { failureRedirect: string }): Promise<{ user: { id: string }; cookie?: string }>
|
|
59
|
+
/** リダイレクトを発生させないモード。未認証では `user` を持たない結果が返る。 */
|
|
60
|
+
(request: Request, options: { failureRedirect: null }): Promise<DailyReportAuthResult>
|
|
61
|
+
}
|
|
57
62
|
|
|
58
63
|
/**
|
|
59
64
|
* Per-dimension visible source types (report body vs. comments).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SQL } from "drizzle-orm"
|
|
2
2
|
import { bigint, MsSqlDialect, mssqlSchema, nvarchar, primaryKey } from "drizzle-orm/mssql-core"
|
|
3
|
-
import { describe, expect, it } from "vitest"
|
|
3
|
+
import { describe, expect, it, vi } from "vitest"
|
|
4
4
|
import { createEpochStore, SqlResultCache } from "./cache"
|
|
5
5
|
import { defineDailyReportSchema } from "./schema"
|
|
6
6
|
import { createDailyReportService, type DailyReportDb, type DailyReportHubRow, formatDateValue } from "./service"
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* 本番コードからは import されない (テスト専用)。
|
|
9
9
|
*/
|
|
10
10
|
import type { DailyReportHandlersConfig } from "../handlers"
|
|
11
|
-
import type { DailyReportAttachmentBytes, DailyReportAttachmentError, DailyReportIdCodec, DailyReportRedisProvider, DailyReportResolveVisibleSourceTypes, DailyReportVisibilityResolveContext, DailyReportVisibilityResolveReason } from "../ports"
|
|
11
|
+
import type { DailyReportAttachmentBytes, DailyReportAttachmentError, DailyReportAuthenticate, DailyReportIdCodec, DailyReportRedisProvider, DailyReportResolveVisibleSourceTypes, DailyReportVisibilityResolveContext, DailyReportVisibilityResolveReason } from "../ports"
|
|
12
12
|
import type { DailyReportService } from "../service"
|
|
13
13
|
import type { DailyReportSseReader, StreamEntry } from "../sse-reader"
|
|
14
14
|
import type { DailyReportViewerScope, VisibleSourceTypeSet } from "../visibility"
|
|
@@ -40,6 +40,8 @@ export type HandlersFixtureOptions = {
|
|
|
40
40
|
cookie?: string
|
|
41
41
|
/** 外部 ID → 内部 ID の解決結果。 */
|
|
42
42
|
internalUserId?: number | null
|
|
43
|
+
/** `getUserIdByExternalId` を失敗させる (ハンドラ外側の例外処理を踏むため)。 */
|
|
44
|
+
userIdLookupError?: Error
|
|
43
45
|
/** 認可判定の結果。null なら不可視 (404 相当)。 */
|
|
44
46
|
attachment?: TestAttachmentRow | null
|
|
45
47
|
/** 読み取りポートの応答。 */
|
|
@@ -140,7 +142,10 @@ export const makeHandlersFixture = (options: HandlersFixtureOptions = {}): { con
|
|
|
140
142
|
const readResult: DailyReportAttachmentBytes | DailyReportAttachmentError = options.readResult ?? { ok: true, bytes: new Uint8Array(new ArrayBuffer(3)), contentType: null }
|
|
141
143
|
|
|
142
144
|
const service = {
|
|
143
|
-
getUserIdByExternalId: async () =>
|
|
145
|
+
getUserIdByExternalId: async () => {
|
|
146
|
+
if (options.userIdLookupError) throw options.userIdLookupError
|
|
147
|
+
return internalUserId
|
|
148
|
+
},
|
|
144
149
|
clearCache: async () => {
|
|
145
150
|
calls.clearCache += 1
|
|
146
151
|
},
|
|
@@ -214,7 +219,15 @@ export const makeHandlersFixture = (options: HandlersFixtureOptions = {}): { con
|
|
|
214
219
|
}
|
|
215
220
|
|
|
216
221
|
const base: DailyReportHandlersConfig = {
|
|
217
|
-
|
|
222
|
+
// ポート契約に忠実に振る舞わせる: failureRedirect が文字列のとき未認証は redirect を throw し、
|
|
223
|
+
// null のときだけ user 無しで解決する。単に `user: undefined` を返すと、実装が決して
|
|
224
|
+
// 返さない形をフェイクだけが作り出し、呼び出し側の到達不能な分岐を温存してしまう
|
|
225
|
+
authenticate: (async (_request: Request, authOptions: { failureRedirect: string } | { failureRedirect: null }) => {
|
|
226
|
+
if (!user && authOptions.failureRedirect !== null) {
|
|
227
|
+
throw new Response(null, { status: 302, headers: { Location: authOptions.failureRedirect } })
|
|
228
|
+
}
|
|
229
|
+
return { user: user ?? undefined, cookie: options.cookie }
|
|
230
|
+
}) as DailyReportAuthenticate,
|
|
218
231
|
resolveVisibleSourceTypes: options.resolveVisibleSourceTypes
|
|
219
232
|
? async (request: Request, context: DailyReportVisibilityResolveContext) => {
|
|
220
233
|
calls.resolveVisibleSourceTypes += 1
|
package/src/server.spec.ts
CHANGED
|
@@ -21,7 +21,7 @@ const clearCacheArgs = () => {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/** redis 未注入警告をテスト出力へ撒かない静音ロガー。 */
|
|
24
|
-
const silentLogger = { info: () => {}, warn: () => {}, error: () => {} }
|
|
24
|
+
const silentLogger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} }
|
|
25
25
|
|
|
26
26
|
const makeServer = (enableDevCacheClear?: boolean) =>
|
|
27
27
|
createDailyReportServer({
|
|
@@ -30,7 +30,7 @@ const makeServer = (enableDevCacheClear?: boolean) =>
|
|
|
30
30
|
userTable: testUsers,
|
|
31
31
|
resolveUserId: async () => 8,
|
|
32
32
|
encodeUserId: (id) => `ENC${id}`,
|
|
33
|
-
authenticate: async () => ({ user: { id: "ext-8" }, cookie:
|
|
33
|
+
authenticate: async () => ({ user: { id: "ext-8" }, cookie: undefined }),
|
|
34
34
|
draftLabelName: "draft",
|
|
35
35
|
enableDevCacheClear,
|
|
36
36
|
logger: silentLogger,
|
|
@@ -61,7 +61,7 @@ describe("createDailyReportServer: resolveVisibleSourceTypes の結線", () => {
|
|
|
61
61
|
userTable: testUsers,
|
|
62
62
|
resolveUserId: async () => 8,
|
|
63
63
|
encodeUserId: (id) => `ENC${id}`,
|
|
64
|
-
authenticate: async () => ({ user: { id: "ext-8" }, cookie:
|
|
64
|
+
authenticate: async () => ({ user: { id: "ext-8" }, cookie: undefined }),
|
|
65
65
|
draftLabelName: "draft",
|
|
66
66
|
resolveVisibleSourceTypes,
|
|
67
67
|
logger: silentLogger,
|
|
@@ -99,7 +99,7 @@ describe("createDailyReportServer: knownSourceTypes", () => {
|
|
|
99
99
|
userTable: testUsers,
|
|
100
100
|
resolveUserId: async () => 8,
|
|
101
101
|
encodeUserId: (id) => `ENC${id}`,
|
|
102
|
-
authenticate: async () => ({ user: { id: "ext-8" }, cookie:
|
|
102
|
+
authenticate: async () => ({ user: { id: "ext-8" }, cookie: undefined }),
|
|
103
103
|
draftLabelName: "draft",
|
|
104
104
|
externalSources: [
|
|
105
105
|
{ sourceType: "NI", table: {}, idColumn: tables.hub.id, mapRow: () => ({}) },
|
|
@@ -117,7 +117,7 @@ describe("createDailyReportServer: knownSourceTypes", () => {
|
|
|
117
117
|
userTable: testUsers,
|
|
118
118
|
resolveUserId: async () => 8,
|
|
119
119
|
encodeUserId: (id) => `ENC${id}`,
|
|
120
|
-
authenticate: async () => ({ user: { id: "ext-8" }, cookie:
|
|
120
|
+
authenticate: async () => ({ user: { id: "ext-8" }, cookie: undefined }),
|
|
121
121
|
draftLabelName: "draft",
|
|
122
122
|
})
|
|
123
123
|
|
|
@@ -130,7 +130,7 @@ describe("redis 未注入の起動警告", () => {
|
|
|
130
130
|
const makeRecordingLogger = () => {
|
|
131
131
|
const warns: unknown[][] = []
|
|
132
132
|
return {
|
|
133
|
-
logger: { info: () => {}, warn: (...args: unknown[]) => void warns.push(args), error: () => {} },
|
|
133
|
+
logger: { debug: () => {}, info: () => {}, warn: (...args: unknown[]) => void warns.push(args), error: () => {} },
|
|
134
134
|
warns,
|
|
135
135
|
}
|
|
136
136
|
}
|
|
@@ -141,7 +141,7 @@ describe("redis 未注入の起動警告", () => {
|
|
|
141
141
|
userTable: testUsers,
|
|
142
142
|
resolveUserId: async () => 8,
|
|
143
143
|
encodeUserId: (id: number) => `ENC${id}`,
|
|
144
|
-
authenticate: async () => ({ user: { id: "ext-8" }, cookie:
|
|
144
|
+
authenticate: async () => ({ user: { id: "ext-8" }, cookie: undefined }),
|
|
145
145
|
draftLabelName: "draft",
|
|
146
146
|
})
|
|
147
147
|
|