Skip to content

feat: TCNASDP認証の自動リフレッシュ機能#63

Merged
9c5s merged 16 commits intomainfrom
feat/auth-refresh
Apr 8, 2026
Merged

feat: TCNASDP認証の自動リフレッシュ機能#63
9c5s merged 16 commits intomainfrom
feat/auth-refresh

Conversation

@9c5s
Copy link
Copy Markdown
Owner

@9c5s 9c5s commented Apr 8, 2026

Summary

Bridgeの認証タイムアウト(~100秒)を回避するため、TCNASDP認証シーケンスを定期的に再実行してLICENSE: EXTを維持する自動リフレッシュ機能を実装する。

  • AuthState型に"refreshing"を追加し、再認証中の状態を観測可能にする
  • autoReauth/reauthInterval設定と公開reauth()メソッドを追加する
  • 初回認証成功時に自動タイマーを起動し、disconnect時に確実に停止する
  • single-flight保証で多重呼び出しを防止する

主な変更

ファイル 変更内容
src/auth.ts AuthState型に"refreshing"追加
src/tcnet.ts 再認証ロジック全体 (+134行)
tests/auth.test.ts 再認証テスト19件追加 (+263行)
docs/wiki/Implementation-Status.md 認証状態・イベント・設定ドキュメント更新

設計判断

  • sendAuthSequenceを呼ばない: executeReauthではresetAuthSessionのみ実行し、BridgeがOptInブロードキャスト経由でトークンを再送するのを待つ。sendAuthSequencesessionToken===nullガードでresetAuthSessionを再呼出しして"refreshing"状態を上書きするため不使用
  • setInterval.unref(): disconnect忘れ時にプロセス終了をブロックしない
  • disconnect時のauthFailedemit: reauthPromise進行中にdisconnectした場合、resetAuthSessionauthFailedをemitしないため、明示的にemitしてPromiseを確実にrejectする

実機テスト結果 (Bridge 3.5 @ 192.168.0.10, 240秒間)

Test plan

  • 全223単体テストがパス (npx vitest run --project unit)
  • TypeScript型チェッククリーン (npx tsgo --noEmit)
  • ESLint 0エラー (npm run lint:ts)
  • ビルド成功 (npm run build)
  • 実機テスト: 240秒間のLICENSE: EXT維持を確認

9c5s added 11 commits April 8, 2026 20:04
認証の自動リフレッシュ機能の基盤として、AuthState型に
"refreshing"状態を追加し、TCNetConfigurationにautoReauth
(デフォルトtrue)とreauthInterval(デフォルト60000ms)を追加する。
resetAuthSession + sendAuthSequenceの既存フローに合流する
再認証ロジックを実装する。single-flight保証付き。
executeReauthでresetAuthSession後にstate="refreshing"を設定し、
ユーザーが再認証中を観測可能にする。
handleAuthPacketのcmd=1受理条件にrefreshingを追加する。
認証成功後に自動再認証タイマーを起動する仕組みを追加する。
autoReauth=trueかつreauthInterval>=10000の場合のみ起動する。
手動で認証をリフレッシュするための公開APIを追加する。
single-flight保証付きで、進行中の再認証にはPromiseを共有する。
- executeReauthのonAuthから冗長な_authState代入を削除
  テスト側でhandleAuthPacketの実フローを忠実にシミュレートする
- startAutoReauthのsetIntervalにunref()を追加
  disconnect忘れ時にプロセス終了をブロックしない
- T1 [Critical]: disconnectSocketsでreauthPromise進行中なら
  authFailedをemitしてPromiseを確実にrejectする
- T2 [High]: executeReauthのcatchでリスナー・タイマーを
  cleanupしsendAuthSequence失敗時のリークを防止する
- T3 [Medium]: executeReauth内のsetTimeoutにunref()を追加し
  disconnect後のプロセス終了ブロックを防止する
- T4 [Low]: reauthInterval=10000の境界値テストを追加する
- T5 [Low]: reauthFailedイベントの引数仕様をドキュメントに追記する
sendAuthSequenceはsessionToken===nullガードでresetAuthSessionを
呼び出すため、executeReauthで設定した"refreshing"状態が"none"に
上書きされていた。実機テストで以下の改善を確認:
- "refreshing"状態が正しく観測可能になった
- Bridgeのトークン再送が高速化(94s→2s)
- 全再認証が成功(修正前は1/3のみ成功)

BridgeはOptInブロードキャスト経由でトークンを再送するため、
resetAuthSessionによる状態リセットのみで再認証フローに合流できる。
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

🦋 Changeset detected

Latest commit: fb76ebb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@9c5s/node-tcnet Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1b2ec7c6-c39c-45a4-982f-030c73d782dc

📥 Commits

Reviewing files that changed from the base of the PR and between f98b6e6 and fb76ebb.

📒 Files selected for processing (1)
  • tests/auth.test.ts
📜 Recent review details
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2026-04-08T12:28:35.362Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 63
File: src/tcnet.ts:960-1010
Timestamp: 2026-04-08T12:28:35.362Z
Learning: In `src/tcnet.ts` (node-tcnet, TypeScript), the `cleanup?.()` call in the catch block of `executeReauth` is intentionally kept as defensive programming. The maintainer (9c5s) prefers this pattern because `removeListener`/`clearTimeout` are idempotent, so the redundant call costs nothing and provides safety against future changes to the control flow.

Applied to files:

  • tests/auth.test.ts
📚 Learning: 2026-03-24T19:15:40.455Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 41
File: src/utils.ts:94-94
Timestamp: 2026-03-24T19:15:40.455Z
Learning: In the `node-tcnet` repository (`src/utils.ts`), the project targets ES2022 + NodeNext and does not need to support Node.js 18.0.0. The temporary numeric `family` field (4/6) in `os.networkInterfaces()` introduced in Node.js 18.0.0 and fixed in 18.1.0 does not need to be handled. Suggesting numeric `family` handling for defensive programming is unnecessary for this project.

Applied to files:

  • tests/auth.test.ts
📚 Learning: 2026-03-21T05:30:31.035Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:249-255
Timestamp: 2026-03-21T05:30:31.035Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacket.read()` (class defined at line 321, read() at line 330) converts the wire-format 1-based layer to 0-based by doing `this.layer = this.buffer.readUInt8(25) - 1`. In contrast, `TCNetRequestPacket.read()` (class defined at line 225, read() at line 231) does NOT subtract 1: `this.layer = this.buffer.readUInt8(25)`. Therefore, `dataPacket.layer` from a received `TCNetDataPacket` is already 0-based and correctly matches the 0-based key stored in `requestData()`. Flagging a missing `-1` in `TCNetDataPacket.read()` is a false positive.

Applied to files:

  • tests/auth.test.ts
🔇 Additional comments (6)
tests/auth.test.ts (6)

271-288: LGTM!

テストヘルパーメソッドが既存のパターンに従って適切に追加されています。private メソッドへのアクセスを提供し、再認証機能のテストを可能にしています。


454-499: LGTM!

過去のレビューで指摘された否定系テストの前提条件が正しく修正されています。connectedauthStateautoReauthreauthInterval の各ガード条件が独立して検証されており、タイマーの重複防止テストも適切です。


872-961: LGTM!

performReauth のテストが網羅的です。状態遷移(authenticatedrefreshingauthenticated/failed)、single-flight 動作、reauthenticated/reauthFailed イベント発火が適切にカバーされています。


963-1033: LGTM!

startAutoReauth の各ガード条件が独立して検証されています。境界値テスト(reauthInterval = 9999 で起動しない、= 10000 で起動する)が実装の < 10_000 条件と正確に対応しています。


1035-1077: LGTM!

public API reauth() のエラーケース(未認証、xteaCiphertext 未設定)と正常系が適切にテストされています。single-flight テストは async 関数の制約を考慮した設計になっています。


1079-1113: LGTM!

disconnectSockets のフローを手動でシミュレートしたテストが src/tcnet.ts の実装(stopAutoReauthauthFailed emit → resetAuthSession)と正確に対応しています。reauthPromise の reject と null 化が finally ブロックで行われることを検証しています。


Summary by CodeRabbit

  • New Features

    • 自動認証リフレッシュを追加(デフォルト有効 autoReauth=true、間隔既定 reauthInterval=60,000ms)
    • 手動で呼べる再認証メソッド reauth() を追加(単一実行保証)
    • 認証状態に "refreshing" を追加、イベントに reauthenticated / reauthFailed を追加
  • Documentation

    • 自動/手動リフレッシュの設定例とイベント仕様を追記
  • Tests

    • 自動リフレッシュと再認証の挙動・イベントを検証する包括的テストを追加

Walkthrough

TCNASDPの自動再認証が追加され、認証状態に "refreshing" を導入。TCNetConfigurationautoReauth / reauthInterval を追加し、TCNetClient.reauth()(single‑flight)と自動・手動リフレッシュ、関連イベントとテスト、ドキュメントが実装されました。

Changes

Cohort / File(s) Summary
認証状態定義
src/auth.ts
AuthState 型に "refreshing" を追加。
クライアント実装
src/tcnet.ts
AUTH_REFRESH_TIMEOUT 定数追加、TCNetConfigurationautoReauth: boolean = true / reauthInterval: number = 60_000 を追加。自動再認証タイマー管理(startAutoReauth/stopAutoReauth)、single‑flight な reauthPromiseperformReauth/executeReauth フロー、公開 reauth(timeoutMs?) メソッド、切断時クリーンアップ、handleAuthPacket"refreshing" 対応、reauthenticated/reauthFailed イベント追加。
テスト
tests/auth.test.ts
テスト用アクセサ/ラッパー追加と、自動再認証タイマー起動・抑止、performReauth の成功/失敗/単一フライト、公開 reauth() のバリデーション/成功/共有プロミス、切断時クリーンアップ等の大量テスト追加。
ドキュメント & リリース
docs/wiki/Implementation-Status.md, .changeset/auth-refresh.md
refreshing 状態と認証イベント(reauthenticated/reauthFailed)を記載。autoReauth/reauthInterval 設定例、手動 reauth() 呼び出し例、Changeset(minor)を追加。

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant TCNet as TCNetClient
    participant Timer as AutoReauthTimer
    participant Bridge as Bridge
    participant Events as AuthEvents

    Note over TCNet: 初期認証成功
    Client->>TCNet: authenticate()
    TCNet->>TCNet: _authState = "authenticated"
    TCNet->>Timer: startAutoReauth()
    Timer->>Timer: setInterval(reauthInterval)
    TCNet->>Events: emit authenticated

    Note over TCNet: 自動再認証サイクル
    loop Every reauthInterval
        Timer->>TCNet: performReauth()
        alt _authState == "authenticated" and no in-flight
            TCNet->>TCNet: _authState = "refreshing"
            TCNet->>Bridge: request token refresh
            Bridge->>TCNet: AppData (cmd=1) with token
            alt Token valid
                TCNet->>TCNet: _authState = "authenticated"
                TCNet->>Events: emit reauthenticated
            else Token invalid / timeout
                TCNet->>TCNet: _authState = "failed"
                TCNet->>Events: emit reauthFailed (Error)
            end
        else Skip
            Note over TCNet: 非認証または既存の in‑flight の場合はスキップ
        end
    end

    Note over TCNet: 手動再認証
    Client->>TCNet: reauth()
    alt 条件成立 (authenticated & xtea configured)
        TCNet->>TCNet: reuse or start executeReauth()
        TCNet->>Events: emit reauthenticated / reauthFailed
    else Error
        TCNet-->>Client: Promise rejection
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • PR #50: 同様に AuthState と認証フロー拡張(型・認証処理の変更)を扱っており直接関連。
  • PR #31: src/tcnet.ts 周りで設定追加や接続ライフサイクル変更を行っており相互影響の可能性が高い。
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PRタイトル「feat: TCNASDP認証の自動リフレッシュ機能」は、変更セットの主要な変更内容(自動リフレッシュ機能の実装)を正確に要約しており、チェンジセット全体を的確に表現している。
Description check ✅ Passed PR説明は変更内容(AuthState型の拡張、設定オプション追加、自動タイマー実装、single-flight保証)と設計判断を詳細に説明し、実機テスト結果も含めて完全に関連している。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/auth-refresh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an automatic and manual re-authentication mechanism for TCNASDP sessions to maintain the 'LICENSE: EXT' state. Changes include a new 'refreshing' state, configuration options for auto-refresh intervals, and event emitters for re-authentication success or failure. Feedback focuses on improving the robustness of the reauth method by checking for existing promises before state validation, preserving the bridgeIsWindows cache during refreshes to avoid redundant OS detection, and documenting the minimum interval constraint for automatic re-authentication.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tcnet.ts`:
- Around line 959-1004: The catch block in executeReauth redundantly calls
cleanup?.() even though doCleanup is already invoked by onAuth/onFail/timeout;
remove the redundant cleanup?.() invocation from the catch block to avoid
duplicate cleanup calls. Specifically, edit executeReauth to keep the cleanup
variable and doCleanup closure used by the authPromise listeners (onAuth,
onFail) and the timeout, but delete the extra cleanup?.() call inside the catch
where this.emit("reauthFailed", ...) and throw err remain; ensure
removeListener/clearTimeout are only performed via doCleanup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 90a349b2-8321-445f-9c5b-925c599e49ca

📥 Commits

Reviewing files that changed from the base of the PR and between b6748a6 and 949b261.

📒 Files selected for processing (4)
  • docs/wiki/Implementation-Status.md
  • src/auth.ts
  • src/tcnet.ts
  • tests/auth.test.ts
📜 Review details
🔇 Additional comments (13)
src/auth.ts (1)

24-24: LGTM!

"refreshing" 状態の追加は適切です。既存の消費者コードは通常 "authenticated""failed" をチェックするため、後方互換性が維持されています。

docs/wiki/Implementation-Status.md (1)

80-107: LGTM!

ドキュメントは実装と一致しており、新しい認証状態、イベント、設定項目、APIの使用例が適切に記載されています。

tests/auth.test.ts (5)

271-288: LGTM!

テストヘルパーメソッドは既存のパターンと一貫しており、再認証機能の内部状態へのアクセスを適切に提供しています。


455-496: LGTM!

自動再認証タイマーの起動条件とタイマーの重複防止に関するテストが適切に実装されています。クリーンアップも正しく行われています。


869-941: LGTM!

performReauth のテストは主要なシナリオを網羅しています。single-flight保証、状態遷移、イベント発火のテストが適切に実装されています。


943-991: LGTM!

タイマーのライフサイクルテストは境界値(9999/10000)を含め、起動・停止の動作を適切に検証しています。


993-1069: LGTM!

公開API reauth() のエラーケースと成功ケース、single-flight動作、およびdisconnect時のクリーンアップ動作のテストが適切に実装されています。

src/tcnet.ts (6)

58-65: LGTM!

設定項目のデフォルト値は適切です。reauthInterval(60秒)はBridgeのタイムアウト(約100秒)より十分短く、実機テストで検証済みとのことで安心です。


253-258: LGTM!

disconnect時のクリーンアップ順序が適切です。authFailedを先に発火してからresetAuthSessionを呼ぶことで、進行中のreauthPromiseが確実にrejectされます。


914-933: LGTM!

タイマー管理が適切に実装されています。重複防止ガード、unref()によるプロセス終了への影響回避、最小間隔(10秒)の制限が適切です。


940-948: LGTM!

single-flight保証が正しく実装されています。reauthPromisefinallyブロックで確実にクリアされます。


1083-1086: LGTM!

"refreshing"状態の追加により、再認証中もBridgeからのトークン受信を正しく処理できます。sessionToken === nullのガードと組み合わせて安全です。


1141-1152: LGTM!

公開API reauth() は適切な事前条件チェックとsingle-flight保証を備えています。"refreshing"状態も許可することで、進行中の再認証Promiseを共有できます。

9c5s added 2 commits April 8, 2026 21:22
- reauth()でreauthPromiseチェックをstate チェックの前に移動し、
  再認証中のpending状態でもPromiseを返せるようにする
- reauthIntervalのJSDocに10000ms下限の制約を明記する
- executeReauthでresetAuthSession()の代わりに必要な状態のみ
  個別リセットしbridgeIsWindowsキャッシュを保持する
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tcnet.ts`:
- Around line 1005-1008: catch ブロックで再認証失敗時に authenticationState が "refreshing"
のまま残っているので、cleanup 実行前に現在の bridgeIsWindows を保持しつつ this.authenticationState
を少なくとも "failed" に戻してください(handleAuthPacket が "failed"
を処理できるためこれで監視側の誤認を防げます)。その後で cleanup?.()、this.emit("reauthFailed", ...)、throw
err の順に続けるように修正してください。参照箇所: authenticationState, bridgeIsWindows,
handleAuthPacket, this.emit("reauthFailed", ...).
- Around line 915-925: startAutoReauth currently starts the interval without
re-checking the live connection/auth state, so add a guard at the start of
startAutoReauth to verify the instance is still connected/authenticated (e.g.
check this.connected / this.authenticated or call an existing
isConnected()/isAuthenticated() method) before creating reauthIntervalId; if the
connection is not active, do not set reauthIntervalId or call unref(); keep
existing checks for config.autoReauth and config.reauthInterval and ensure
performReauth is still invoked inside the interval when appropriate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bb185069-a642-4966-b78d-a24e2b368056

📥 Commits

Reviewing files that changed from the base of the PR and between 949b261 and c2f6a17.

📒 Files selected for processing (2)
  • .changeset/auth-refresh.md
  • src/tcnet.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-04-08T12:28:35.362Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 63
File: src/tcnet.ts:960-1010
Timestamp: 2026-04-08T12:28:35.362Z
Learning: In `src/tcnet.ts` (node-tcnet, TypeScript), the `cleanup?.()` call in the catch block of `executeReauth` is intentionally kept as defensive programming. The maintainer (9c5s) prefers this pattern because `removeListener`/`clearTimeout` are idempotent, so the redundant call costs nothing and provides safety against future changes to the control flow.

Applied to files:

  • .changeset/auth-refresh.md
  • src/tcnet.ts
🔇 Additional comments (1)
src/tcnet.ts (1)

1147-1157: single-flight の入口順序はこのままで良いです

reauthPromise を認証状態チェックより先に返しているので、"refreshing" 遷移後の後続呼び出しも同じ Promise を共有できます。

- startAutoReauthに接続・認証状態ガードを追加
  authenticatedリスナー内でdisconnect等が呼ばれた場合に
  不要なタイマー起動を防止する
- executeReauthのcatchでrefreshing状態をfailedに回復
  タイムアウト等の失敗後にauthenticationStateが永遠に
  refreshingのまま残る問題を修正する
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tcnet.ts`:
- Around line 952-959: The JSDoc for executeReauth() is incorrect: it says the
function rejoins the existing flow via resetAuthSession + sendAuthSequence, but
the implementation intentionally avoids calling resetAuthSession and
sendAuthSequence to preserve the refreshing state; update the JSDoc on
executeReauth() to describe the actual behavior (that it maintains the
refreshing flag, does not call resetAuthSession/sendAuthSequence, registers
listeners before triggering any remote response to avoid missed events, and
waits for authenticated/authFailed events or timeoutMs), and reference the
refreshing flag, resetAuthSession, sendAuthSequence, and executeReauth in the
description so future authors won't revert the current flow.

In `@tests/auth.test.ts`:
- Around line 1057-1070: The test must assert that the second call shares the
exact same Promise as the first (not just that both eventually resolve); update
the test around AuthTestClient and its callReauth() calls to add a strict
identity assertion (e.g., expect(p1).toBe(p2) or Object.is(p1, p2)) before
awaiting Promise.all, then keep the existing emission and await to ensure both
resolve. Ensure you reference the existing variables p1 and p2 from the test so
the identity check guarantees single-flight behavior.
- Around line 469-477: The failing negative tests never reach the auto-reauth
guard because other preconditions aren't set; update the tests using
AuthTestClient to explicitly satisfy all unrelated guards before testing the
target guard: set the client to connected (e.g., client.connected = true or call
a helper that marks it connected) and set authenticationState to "authenticated"
where needed, then set config.autoReauth = false and invoke
callHandleAuth(createErrorPacket(...)); for the other case (lines ~975-1000)
likewise ensure authenticationState === "authenticated" and connected is true so
only the autoReauth/reauthInterval behavior is being verified; use
getReauthIntervalId() to assert no timer started or clear any pre-set interval
IDs before the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 60c4473b-03b9-495d-94db-02990948f6a6

📥 Commits

Reviewing files that changed from the base of the PR and between c2f6a17 and 558c39c.

📒 Files selected for processing (2)
  • src/tcnet.ts
  • tests/auth.test.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2026-04-08T12:28:35.362Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 63
File: src/tcnet.ts:960-1010
Timestamp: 2026-04-08T12:28:35.362Z
Learning: In `src/tcnet.ts` (node-tcnet, TypeScript), the `cleanup?.()` call in the catch block of `executeReauth` is intentionally kept as defensive programming. The maintainer (9c5s) prefers this pattern because `removeListener`/`clearTimeout` are idempotent, so the redundant call costs nothing and provides safety against future changes to the control flow.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-27T08:24:18.571Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 50
File: src/network.ts:1010-1024
Timestamp: 2026-03-27T08:24:18.571Z
Learning: In the `node-tcnet` repository (`src/network.ts`), `Buffer.allocUnsafe()` is never used — only `Buffer.alloc()` is used throughout the codebase. Reserved fields in packet `write()` methods do not need explicit zero-initialization because `Buffer.alloc()` always zero-initializes. Suggesting defensive zero-writes for reserved packet offsets is unnecessary (YAGNI) for this codebase.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-24T19:15:40.455Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 41
File: src/utils.ts:94-94
Timestamp: 2026-03-24T19:15:40.455Z
Learning: In the `node-tcnet` repository (`src/utils.ts`), the project targets ES2022 + NodeNext and does not need to support Node.js 18.0.0. The temporary numeric `family` field (4/6) in `os.networkInterfaces()` introduced in Node.js 18.0.0 and fixed in 18.1.0 does not need to be handled. Suggesting numeric `family` handling for defensive programming is unnecessary for this project.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T05:30:31.035Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:249-255
Timestamp: 2026-03-21T05:30:31.035Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacket.read()` (class defined at line 321, read() at line 330) converts the wire-format 1-based layer to 0-based by doing `this.layer = this.buffer.readUInt8(25) - 1`. In contrast, `TCNetRequestPacket.read()` (class defined at line 225, read() at line 231) does NOT subtract 1: `this.layer = this.buffer.readUInt8(25)`. Therefore, `dataPacket.layer` from a received `TCNetDataPacket` is already 0-based and correctly matches the 0-based key stored in `requestData()`. Flagging a missing `-1` in `TCNetDataPacket.read()` is a false positive.

Applied to files:

  • src/tcnet.ts

- executeReauthのJSDocを実装に合わせて更新する
  (resetAuthSession/sendAuthSequenceを呼ばない設計の説明)
- 否定系テストで意図したガード以外の前提条件を満たすよう修正
  (connected/authState設定を追加し、対象ガードのみ検証)
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/auth.test.ts`:
- Around line 898-912: The test comment is inaccurate: the early return in
performReauth can be caused by this.reauthPromise being set and/or
this._authState transitioning to "refreshing"; update the test comment in the
"single-flight: reauthPromiseが存在する間は2回目がskipされる" case to state that the second
call is skipped because performReauth sets this.reauthPromise (and the client’s
_authState becomes "refreshing"), or make the test deterministic by explicitly
asserting which condition (reauthPromise vs _authState) is responsible;
reference AuthTestClient, callPerformReauth, performReauth, reauthPromise and
_authState when modifying the comment or test assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e603a312-81ac-4763-82a3-9b79f487f556

📥 Commits

Reviewing files that changed from the base of the PR and between 558c39c and f98b6e6.

📒 Files selected for processing (2)
  • src/tcnet.ts
  • tests/auth.test.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2026-04-08T12:28:35.362Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 63
File: src/tcnet.ts:960-1010
Timestamp: 2026-04-08T12:28:35.362Z
Learning: In `src/tcnet.ts` (node-tcnet, TypeScript), the `cleanup?.()` call in the catch block of `executeReauth` is intentionally kept as defensive programming. The maintainer (9c5s) prefers this pattern because `removeListener`/`clearTimeout` are idempotent, so the redundant call costs nothing and provides safety against future changes to the control flow.

Applied to files:

  • tests/auth.test.ts
  • src/tcnet.ts
📚 Learning: 2026-03-27T08:24:18.571Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 50
File: src/network.ts:1010-1024
Timestamp: 2026-03-27T08:24:18.571Z
Learning: In the `node-tcnet` repository (`src/network.ts`), `Buffer.allocUnsafe()` is never used — only `Buffer.alloc()` is used throughout the codebase. Reserved fields in packet `write()` methods do not need explicit zero-initialization because `Buffer.alloc()` always zero-initializes. Suggesting defensive zero-writes for reserved packet offsets is unnecessary (YAGNI) for this codebase.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-24T19:15:40.455Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 41
File: src/utils.ts:94-94
Timestamp: 2026-03-24T19:15:40.455Z
Learning: In the `node-tcnet` repository (`src/utils.ts`), the project targets ES2022 + NodeNext and does not need to support Node.js 18.0.0. The temporary numeric `family` field (4/6) in `os.networkInterfaces()` introduced in Node.js 18.0.0 and fixed in 18.1.0 does not need to be handled. Suggesting numeric `family` handling for defensive programming is unnecessary for this project.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T05:30:31.035Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:249-255
Timestamp: 2026-03-21T05:30:31.035Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacket.read()` (class defined at line 321, read() at line 330) converts the wire-format 1-based layer to 0-based by doing `this.layer = this.buffer.readUInt8(25) - 1`. In contrast, `TCNetRequestPacket.read()` (class defined at line 225, read() at line 231) does NOT subtract 1: `this.layer = this.buffer.readUInt8(25)`. Therefore, `dataPacket.layer` from a received `TCNetDataPacket` is already 0-based and correctly matches the 0-based key stored in `requestData()`. Flagging a missing `-1` in `TCNetDataPacket.read()` is a false positive.

Applied to files:

  • src/tcnet.ts
🔇 Additional comments (12)
tests/auth.test.ts (5)

1063-1076: テストは正しく動作しています

過去レビューでexpect(p2).toBe(p1)の追加が提案されましたが、実際にはこのアサーションは失敗します。

理由:

  • reauth()async関数なので、常に新しいPromiseを返す
  • p1performReauth()から返されるPromise
  • p2this.reauthPromiseをreturnするが、async関数なので新しいPromiseでラップされる
  • したがってp1 !== p2(オブジェクト参照は異なる)

現在のテストは両方のPromiseが正常に解決することを検証しており、single-flight動作(1つの認証操作のみが実行される)を正しくテストしています。コメントの「両方同じPromiseを共有する」は「同じ認証操作を共有する」という意味で理解すべきです。


271-288: LGTM!

テストヘルパーメソッドの追加により、privateメンバーへのアクセスが適切にカプセル化されています。src/tcnet.tsのprivateメンバー名(reauthPromise, reauthIntervalId, _authState等)と一致しています。


455-499: LGTM!

初回認証成功時のautoReauthタイマー起動テストが適切です:

  • connectedauthStateの前提条件を設定(過去レビューで対応済み)
  • タイマーの起動/非起動を検証
  • 重複呼び出し時のタイマー一意性を検証
  • テスト後のクリーンアップ(callStopAutoReauth)も行われています

963-1033: LGTM!

startAutoReauth/stopAutoReauthのテストが網羅的です:

  • 正常起動のテスト
  • 各ガード条件(未接続、autoReauth=false、reauthInterval下限)のテスト
  • 下限ちょうど(10000ms)での起動確認
  • 停止後のintervalIdクリア確認

1079-1113: LGTM!

disconnect時のreauthクリーンアップテストがdisconnectSocketsの実フローを正しく再現しています:

  1. stopAutoReauth()でタイマー停止
  2. reauthPromise存在時にauthFailedをemit
  3. resetAuthSession()でセッションリセット

in-flight promiseのrejectとreauthPromiseのクリアを検証しています。

src/tcnet.ts (7)

13-13: LGTM!

AUTH_REFRESH_TIMEOUT = 100_000 (100秒) はBridgeの認証タイムアウト(約100秒)に対応しており、適切な値です。


58-66: LGTM!

設定オプションの追加は適切です。JSDocに10000ms未満の制限とデフォルト値の理由が明記されており、実機テストで実証された値を使用しています。


254-259: LGTM!

disconnectSocketsでのreauthクリーンアップロジックは適切です:

  1. stopAutoReauth()でタイマーを先に停止
  2. reauthPromiseが進行中の場合はauthFailedをemitしてPromiseをreject可能にする
  3. その後resetAuthSession()で認証状態をリセット

この順序により、in-flightのreauthPromiseが確実にrejectされます。


915-927: LGTM!

startAutoReauthのガード条件が正しく実装されています:

  • !this.connected || this._authState !== "authenticated" で接続・認証状態を確認(過去レビューで対応済み)
  • !this.config.autoReauth || this.config.reauthInterval < 10_000 で設定値を確認
  • this.reauthIntervalId で重複タイマー防止
  • unref() でNode.jsプロセスの終了を妨げない

937-950: LGTM!

performReauthのsingle-flight実装が正しいです:

  • _authState !== "authenticated" || this.reauthPromise で二重実行を防止
  • finallyブロックでreauthPromiseを確実にクリア

952-1018: LGTM!

executeReauthの実装が適切です:

  • JSDocが実装に合わせて更新されている(過去レビューで対応済み)
  • bridgeIsWindowsキャッシュを保持して毎回のOS判定pingを回避
  • refreshing状態に遷移し、Bridgeからのtoken再送を待つ設計
  • 失敗時は_authStatefailedに戻して自然回復を可能にする(過去レビューで対応済み)
  • cleanup?.()はremoveListener/clearTimeoutの冪等性により防御的プログラミングとして意図的に保持(learning)

1146-1166: LGTM!

公開API reauth() の実装が適切です:

  • xteaCiphertextの検証
  • 進行中のreauthPromiseがある場合はそれを返す(single-flight)
  • 認証状態の検証
  • performReauth()への委譲

@9c5s 9c5s merged commit 2ca8965 into main Apr 8, 2026
2 checks passed
@9c5s 9c5s deleted the feat/auth-refresh branch April 8, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant