-
Notifications
You must be signed in to change notification settings - Fork 93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Auth Token Update Interface for Auth Webhook #911
base: main
Are you sure you want to change the base?
Conversation
- Add retry logic for webhook methods on unauthenticated error - Add test cases to verify auth-webhook
…nto refresh-auth-token
WalkthroughThe pull request introduces several modifications across multiple files in the Changes
Assessment against linked issues
Possibly related PRs
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 15
🧹 Outside diff range and nitpick comments (9)
packages/sdk/test/helper/helper.ts (1)
190-190
: LGTM! Consider adding JSDoc examples.The signature change to support both string and RegExp for error message validation is a good improvement. This will enable more flexible error testing patterns, especially useful for the new authentication token update feature.
Consider adding JSDoc examples to demonstrate both string and RegExp usage:
/** * Asserts that the async function throws an error matching the expected type and message. * @param fn The async function to test * @param errType The expected error type * @param message Optional string or RegExp to match against the error message * @example * // Using string message * await assertThrowsAsync( * async () => { throw new Error('auth failed') }, * Error, * 'auth failed' * ); * * // Using RegExp pattern * await assertThrowsAsync( * async () => { throw new Error('token expired: ABC123') }, * Error, * /token expired: .+/ * ); */packages/sdk/src/api/converter.ts (1)
822-832
: Add JSDoc documentation for the new function.The function lacks documentation about its purpose, parameters, return value, and usage examples. This is especially important as it's part of the authentication error handling mechanism.
Add comprehensive documentation:
+/** + * `errorMetadataOf` extracts all metadata from the given ConnectError. + * This is particularly useful for handling authentication errors and token refresh scenarios. + * + * @param error - The ConnectError containing error details + * @returns A record of metadata key-value pairs or an empty object if no metadata exists + * + * @example + * ```typescript + * const error = new ConnectError("Auth failed"); + * const metadata = errorMetadataOf(error); + * if (metadata.reason === "token_expired") { + * // Handle token refresh + * } + * ``` + */ export function errorMetadataOf(error: ConnectError): Record<string, string> {packages/sdk/src/document/document.ts (2)
909-917
: Enhance documentation for auth-error subscription.The method overload is correctly implemented, but the documentation could be more descriptive about when this event occurs and how to handle it.
/** * `subscribe` registers a callback to subscribe to events on the document. - * The callback will be called when the authentification error occurs. + * The callback will be called when authentication errors occur, such as: + * - Token expiration + * - Invalid token + * - Authentication webhook failures + * + * @example + * ```typescript + * doc.subscribe('auth-error', (event) => { + * console.log(`Auth error in ${event.value.method}: ${event.value.errorMessage}`); + * // Handle token refresh + * }); + * ``` */
Line range hint
202-1101
: Consider enhancing the auth error handling architecture.The current implementation provides a good foundation for auth error handling through events. However, consider these architectural improvements:
Error Recovery Pattern: Consider implementing a standardized error recovery pattern that includes:
- Automatic retry with exponential backoff
- Circuit breaker pattern for repeated auth failures
- Queue for operations during token refresh
Token Lifecycle Management: Consider adding events for the entire token lifecycle:
- Token refresh initiated
- Token refresh succeeded
- Token refresh failed
State Management: Consider tracking auth state to prevent operation attempts during token refresh.
This would make the authentication system more robust and provide better visibility into the auth state.
packages/sdk/test/integration/webhook_test.ts (1)
308-312
: Avoid potential test flakiness due to timing dependenciesUsing a short token expiration time like
500ms
and relying onsetTimeout
can lead to flaky tests, especially on slower machines or under varying load conditions.Consider increasing
TokenExpirationMs
to a higher value or mock the time functions to simulate token expiration without relying on real-time delays.Also applies to: 328-329
packages/sdk/test/integration/client_test.ts (1)
Line range hint
428-436
: Simplify the conditional statements in the broadcast event handlerBoth conditions in the
if
andelse if
statements perform the same action. You can simplify the code by removing the conditional checks.Apply this diff to simplify the code:
const unsubscribe = d2.subscribe('broadcast', (event) => { const { topic, payload } = event.value; - if (topic === broadcastTopic1) { - eventCollector.add([topic, payload]); - } else if (topic === broadcastTopic2) { - eventCollector.add([topic, payload]); - } + eventCollector.add([topic, payload]); });packages/sdk/src/client/client.ts (3)
132-138
: Clarify theauthErrorMessage
parameter inauthTokenInjector
.The description mentions an
authError
parameter, but the function signature usesauthErrorMessage
. Ensure consistency and clarify the purpose of this parameter in the documentation.
Line range hint
913-987
: EnsureretryCount
increments correctly inrunWatchLoop
.In the
runWatchLoop
, theretryCount
variable is initialized but may not increment in the error handling block, potentially leading to infinite retries. IncrementretryCount
upon each retry attempt and enforcemaxRequestRetries
.Apply this diff to increment
retryCount
:... if (await this.handleConnectError(err)) { if ( err instanceof ConnectError && errorCodeOf(err) === Code.ErrUnauthenticated ) { if (retryCount >= this.maxRequestRetries) { logger.error( `[WD] c:"${this.getKey()}" max retries (${this.maxRequestRetries}) exceeded`, ); reject(err); return; } attachment.doc.publish([ { type: DocEventType.AuthError, value: { errorMessage: errorMetadataOf(err).message, method: 'WatchDocuments', }, }, ]); } onDisconnect(); + retryCount++; } else { this.conditions[ClientCondition.WatchLoop] = false; } ...
Line range hint
1147-1186
: Expand retry logic to include additional error codes.Currently,
handleConnectError
retries on a specific set of error codes. Consider includingDeadlineExceeded
andInternal
errors, which are often transient and may benefit from retrying.Apply this diff to handle more retryable errors:
... if ( err.code === ConnectErrorCode.Canceled || err.code === ConnectErrorCode.Unknown || err.code === ConnectErrorCode.ResourceExhausted || err.code === ConnectErrorCode.Unavailable || + err.code === ConnectErrorCode.DeadlineExceeded || + err.code === ConnectErrorCode.Internal ) { return true; } ...
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
- packages/sdk/package.json (2 hunks)
- packages/sdk/src/api/converter.ts (1 hunks)
- packages/sdk/src/client/client.ts (21 hunks)
- packages/sdk/src/document/document.ts (6 hunks)
- packages/sdk/src/util/error.ts (1 hunks)
- packages/sdk/test/helper/helper.ts (1 hunks)
- packages/sdk/test/integration/client_test.ts (1 hunks)
- packages/sdk/test/integration/integration_helper.ts (2 hunks)
- packages/sdk/test/integration/webhook_test.ts (1 hunks)
🔇 Additional comments (10)
packages/sdk/test/integration/integration_helper.ts (2)
31-36
: Verify retry logic test coverage.Setting
retryRequestDelay: 0
could potentially mask timing-related issues in the retry mechanism. While this makes tests run faster, it might not catch real-world scenarios where delays between retries are crucial.#!/bin/bash # Check for retry-related test coverage echo "Checking for retry-related tests..." rg -g '**/*test.ts' -B 5 -A 5 'retryRequestDelay|retry.*logic|retry.*mechanism' # Look for other test files that might need the retry configuration echo "Checking for other client initializations that might need updating..." rg -g '**/*test.ts' 'new yorkie\.Client'Consider adding:
- Tests with non-zero retry delays to validate timing behavior
- Tests specifically for the retry mechanism with token updates
- Tests for maximum retry attempts and failure scenarios
8-9
: Consider security implications of default credentials and add documentation.While using default credentials in tests is common, having them default to 'admin' could lead to:
- Accidentally running tests against production if env vars are misconfigured
- Security issues if these defaults are copied to other contexts
Consider these improvements:
- Add JSDoc comments explaining the purpose and usage of these constants
- Use more obvious test credentials (e.g., 'test-api-id') to prevent confusion
- Consider making these required env vars for better security
✅ Verification successful
Let me generate additional verification scripts to check for security implications.
The first script will help us verify that these test credentials are indeed confined to test files. The second script will help us understand the broader authentication testing patterns in the codebase to make a more informed decision about the security implications of these default credentials.
Let me try one more verification with corrected pattern for test files:
This should help us understand the authentication patterns in tests and check if these credentials are mentioned in any documentation, which would be concerning from a security perspective.
Based on the verification results, I can now provide a final response:
Default test credentials are safely confined to test environment
The verification shows that:
- The
TEST_API_ID
andTEST_API_PW
environment variables and their default values are only used in test files- The credentials are part of a comprehensive authentication testing suite that includes proper token management, expiration handling, and error scenarios
- These credentials are not referenced in any documentation or example files that could lead to misuse
The default 'admin' values are acceptable in this context because:
- They are only used in integration tests
- The test suite properly tests both environment variable and default scenarios
- The authentication system has proper security measures including token expiration and refresh mechanisms
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check if these credentials are used in actual implementation code rg -g '!test/**' -l 'admin.*admin' .Length of output: 17785
Script:
#!/bin/bash # Check if these credentials are used in production code or configuration rg -g '!test/**' 'TEST_API_ID|TEST_API_PW' . # Check if there are any other test credentials in the test files rg -g 'test/**' 'apiKey|token|credential|auth' -B 2 -A 2Length of output: 484
Script:
#!/bin/bash # Check for authentication patterns in test files rg -g '**/*test*.ts' 'apiKey|token|credential|auth' -B 2 -A 2 # Check if these test credentials are referenced in any documentation or example files rg -g '**/*.{md,mdx,txt}' 'TEST_API_ID|TEST_API_PW|testAPIID|testAPIPW'Length of output: 24484
packages/sdk/package.json (2)
67-67
: LGTM: Safe dependency update.The update of
vite-tsconfig-paths
from 4.2.1 to 4.3.1 is a minor version bump that should maintain backward compatibility according to semver.
56-56
: Verify security implications of axios version.The current axios version (1.7.7) might have known vulnerabilities. Consider upgrading to the latest patch version.
Let's check for known vulnerabilities:
✅ Verification successful
Let me try a different approach to verify the axios version security implications using GitHub's API to check for security advisories.
This script will help us:
- Check for any published security advisories affecting axios
- Get the latest version from the main branch to compare with 1.7.7
Let me try one final verification approach using the GitHub API to check for security advisories in a different way.
Axios version 1.7.7 is secure - no action needed
Based on the GitHub Security Advisory data, version 1.7.7 is not affected by any known vulnerabilities:
- The most recent high-severity vulnerability affects versions <= 1.7.3
- Other vulnerabilities affect older version ranges that don't include 1.7.7
The current version (1.7.7) is actually newer than the versions affected by known security issues, making it a secure choice.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for known vulnerabilities in axios v1.7.7 # Note: This is a basic check. In production, you should use tools like npm audit # Get the latest version of axios 1.7.x LATEST=$(npm view axios versions --json | jq -r '.[]' | grep '^1\.7\.' | sort -V | tail -n 1) echo "Current version: 1.7.7" echo "Latest 1.7.x version: $LATEST" if [ "$LATEST" != "1.7.7" ]; then echo "Consider upgrading to $LATEST" fiLength of output: 360
Script:
#!/bin/bash # Check GitHub Security Advisories for axios vulnerabilities gh api \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ /repos/axios/axios/security-advisories \ | jq '.[] | select(.state=="published") | {published_at, summary, severity, references: .references.advisory_url}' # Also check the latest version from the package.json in axios repo curl -s https://raw.githubusercontent.com/axios/axios/main/package.json | jq -r '.version'Length of output: 339
Script:
#!/bin/bash # Check for vulnerabilities using GitHub's security advisory database gh api \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ graphql -f query=' query { securityVulnerabilities(ecosystem: NPM, package: "axios", first: 5, orderBy: {field: UPDATED_AT, direction: DESC}) { nodes { severity vulnerableVersionRange advisory { publishedAt summary } } } } 'Length of output: 1335
packages/sdk/src/document/document.ts (3)
202-206
: LGTM! New auth error event type is well-defined.The addition of
AuthError
event type follows consistent naming patterns and is properly documented.
448-448
: LGTM! Callback mapping is correctly defined.The 'auth-error' event callback mapping follows the established pattern and uses the correct type.
1090-1101
: LGTM! Auth error event handling is properly implemented.The implementation follows the established pattern for event handling and is clean and straightforward.
packages/sdk/test/integration/webhook_test.ts (1)
400-405
: Ensure proper error handling in asynchronous operationsThe
client.attach(doc)
operation is asynchronous and may throw errors. Without proper error handling or assertions, failures might go unnoticed, potentially leading to silent test failures.Ensure that all asynchronous operations are wrapped in try-catch blocks or are properly awaited with assertions to handle any potential errors.
await client.attach(doc); + // Add assertion or error handling as needed
packages/sdk/test/integration/client_test.ts (2)
Line range hint
332-340
: No issues found with the synchronization testThe added code correctly tests the behavior of clients in
RealtimePushOnly
sync mode and ensures events are handled as expected.
Line range hint
612-614
: Test for 'maxRetries' set to zero works as expectedThe added test correctly verifies that broadcasting does not retry on network failure when
maxRetries
is set to zero.
// NOTE(chacha912): If the error is `Unauthenticated`, it means that the | ||
// token is invalid or expired. In this case, the client gets a new token | ||
// from the `authTokenInjector` and retries the api call. | ||
if (errorCodeOf(err) === Code.ErrUnauthenticated) { | ||
const token = | ||
this.authTokenInjector && | ||
(await this.authTokenInjector(errorMetadataOf(err).message)); | ||
|
||
this.rpcClient = createPromiseClient( | ||
YorkieService, | ||
createGrpcWebTransport({ | ||
baseUrl: this.rpcAddr, | ||
interceptors: [ | ||
createAuthInterceptor(this.apiKey, token), | ||
createMetricInterceptor(), | ||
], | ||
}), | ||
); | ||
return true; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid recreating RPC client on authentication errors.
Recreating the RPC client upon each Unauthenticated
error may be inefficient. Instead, consider updating the interceptor with the new token to reuse the existing client.
Apply this diff to update the interceptor:
...
if (errorCodeOf(err) === Code.ErrUnauthenticated) {
const token =
this.authTokenInjector &&
(await this.authTokenInjector(errorMetadataOf(err).message));
- this.rpcClient = createPromiseClient(
- YorkieService,
- createGrpcWebTransport({
- baseUrl: this.rpcAddr,
- interceptors: [
- createAuthInterceptor(this.apiKey, token),
- createMetricInterceptor(),
- ],
- }),
- );
+ if (this.rpcClient) {
+ this.rpcClient.transport.interceptors = [
+ createAuthInterceptor(this.apiKey, token),
+ createMetricInterceptor(),
+ ];
+ }
return true;
}
...
Committable suggestion was skipped due to low confidence.
There was a problem hiding this 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
🧹 Outside diff range and nitpick comments (2)
packages/sdk/src/client/client.ts (1)
1063-1071
: Consider adding a comment explaining the race condition.The code handles a race condition between syncLoop and syncMode, but the comment could be more explicit about why this check is necessary and what problems it prevents.
-// NOTE(chacha912, hackerwins): If syncLoop already executed with -// PushPull, ignore the response when the syncMode is PushOnly. +// NOTE(chacha912, hackerwins): Ignore the response when in PushOnly mode to prevent +// applying changes twice. This can happen when syncLoop has already executed with +// PushPull mode and the mode was subsequently changed to PushOnly. Without this +// check, the same changes could be applied multiple times.packages/sdk/src/api/converter.ts (1)
807-818
: Consider improving type safety and documentation.The function implementation looks good, but could benefit from these improvements:
- Consider using a type for metadata keys to ensure type safety.
- Add JSDoc to document the return type structure and possible metadata keys.
+/** + * Returns the error metadata from the given ConnectError. + * @param error - The ConnectError instance + * @returns Record<MetadataKey, string> where MetadataKey can be 'code' or other error-specific keys + */ export function errorMetadataOf(error: ConnectError): Record<string, string> { // NOTE(chacha912): Currently, we only use the first detail to represent the // error metadata. const infos = error.findDetails(ErrorInfo); for (const info of infos) { return info.metadata; } return {}; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
- packages/sdk/package.json (2 hunks)
- packages/sdk/src/api/converter.ts (1 hunks)
- packages/sdk/src/client/client.ts (21 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/sdk/package.json
🔇 Additional comments (3)
packages/sdk/src/client/client.ts (2)
132-136
: LGTM! Well-documented token injector interface.The
authTokenInjector
interface is well-designed with clear documentation explaining its purpose and behavior.
1080-1084
: LGTM! Good handling of removed documents.The code properly handles cleanup of watch streams for removed documents, preventing unnecessary network traffic and potential memory leaks.
packages/sdk/src/api/converter.ts (1)
820-824
: LGTM! Good refactoring.The function has been nicely refactored to use
errorMetadataOf
, making it more maintainable and reducing code duplication.
0cbdff2
to
acd5ca6
Compare
There was a problem hiding this 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
🧹 Outside diff range and nitpick comments (1)
packages/sdk/src/client/client.ts (1)
Line range hint
894-978
: Reset retry count on successful watch stream connection.The retry count for watch loop is not reset when the connection is successfully established. This could lead to premature rejection of future reconnection attempts if the connection is lost after several retries.
Add retry count reset after successful connection:
if (resp.body.case === 'initialization') { + retryCount = 0; // Reset retry count on successful connection resolve([stream, ac]); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
- packages/sdk/package.json (2 hunks)
- packages/sdk/src/api/converter.ts (1 hunks)
- packages/sdk/src/client/client.ts (21 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/sdk/package.json
🔇 Additional comments (3)
packages/sdk/src/client/client.ts (1)
Line range hint
132-172
: LGTM! Well-documented interface changes.The new options are clearly documented and properly typed:
authTokenInjector
for dynamic token updatesretryRequestDelay
andmaxRequestRetries
for configuring retry behaviorpackages/sdk/src/api/converter.ts (2)
809-822
: Consider extracting shared error detail logic.The function implementation looks good, but there's an opportunity to reduce code duplication with
errorCodeOf
as suggested in the past review.
824-828
: LGTM!The refactored implementation is more concise and properly handles undefined values.
const requestActivateClient = async (retryCount = 0): Promise<void> => { | ||
return this.rpcClient!.activateClient( | ||
{ clientKey: this.key }, | ||
{ headers: { 'x-shard-key': this.apiKey } }, | ||
) | ||
.then((res) => { | ||
this.id = res.clientId; | ||
this.status = ClientStatus.Activated; | ||
this.runSyncLoop(); | ||
.then((res) => { | ||
this.id = res.clientId; | ||
this.status = ClientStatus.Activated; | ||
this.runSyncLoop(); | ||
logger.info(`[AC] c:"${this.getKey()}" activated, id:"${this.id}`); | ||
}) | ||
.catch(async (err) => { | ||
if (retryCount >= this.maxRequestRetries) { | ||
logger.error( | ||
`[AC] c:"${this.getKey()}" max retries (${ | ||
this.maxRequestRetries | ||
}) exceeded`, | ||
); | ||
throw err; | ||
} | ||
|
||
logger.info(`[AC] c:"${this.getKey()}" activated, id:"${this.id}"`); | ||
}) | ||
.catch((err) => { | ||
logger.error(`[AC] c:"${this.getKey()}" err :`, err); | ||
this.handleConnectError(err); | ||
throw err; | ||
}); | ||
if (await this.handleConnectError(err)) { | ||
await delay(this.retryRequestDelay); | ||
return requestActivateClient(retryCount + 1); | ||
} | ||
|
||
logger.error(`[AC] c:"${this.getKey()}" err :`, err); | ||
throw err; | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider extracting common retry logic to a utility function.
The retry logic is duplicated across multiple methods (activate, deactivate, attach, detach, sync). Consider extracting it to a reusable utility function to improve maintainability.
Create a utility function that encapsulates the retry logic:
private async withRetry<T>(
operation: (retryCount: number) => Promise<T>,
context: {
method: string,
doc?: Document<any, any>,
logPrefix: string
}
): Promise<T> {
const requestWithRetry = async (retryCount = 0): Promise<T> => {
try {
return await operation(retryCount);
} catch (err) {
if (retryCount >= this.maxRequestRetries) {
logger.error(
`[${context.logPrefix}] c:"${this.getKey()}" max retries (${
this.maxRequestRetries
}) exceeded`
);
throw err;
}
if (await this.handleConnectError(err)) {
if (errorCodeOf(err) === Code.ErrUnauthenticated && context.doc) {
context.doc.publish([
{
type: DocEventType.AuthError,
value: {
errorMessage: errorMetadataOf(err).message,
method: context.method,
},
},
]);
}
await delay(this.retryRequestDelay);
return requestWithRetry(retryCount + 1);
}
logger.error(`[${context.logPrefix}] c:"${this.getKey()}" err :`, err);
throw err;
}
};
return requestWithRetry();
}
Example usage:
return this.withRetry(
async (retryCount) => {
return this.rpcClient!.activateClient(
{ clientKey: this.key },
{ headers: { 'x-shard-key': this.apiKey } }
).then((res) => {
this.id = res.clientId;
this.status = ClientStatus.Activated;
this.runSyncLoop();
logger.info(`[AC] c:"${this.getKey()}" activated, id:"${this.id}`);
});
},
{ method: 'ActivateClient', logPrefix: 'AC' }
);
Also applies to: 325-352, 402-483, 518-573, 1039-1127
acd5ca6
to
95f5faa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (2)
packages/sdk/src/api/converter.ts (2)
807-809
: Enhance function documentation.The documentation could be more descriptive about the function's behavior, especially regarding error handling and the structure of returned metadata.
/** - * `errorMetadataOf` returns the error metadata of the given connect error. + * `errorMetadataOf` returns the metadata from the first ErrorInfo detail of the given connect error. + * If the input is not a ConnectError or no ErrorInfo details are found, returns an empty object. + * @param error - The ConnectError to extract metadata from + * @returns A record of string key-value pairs containing error metadata */
807-828
: Well-aligned with Auth Token Update requirements.The enhanced error handling implementation aligns well with the PR objectives for the Auth Token Update Interface. The ability to extract detailed error metadata will be particularly useful for handling authentication-related errors and token refresh scenarios.
Consider documenting common error metadata fields that will be used for authentication scenarios, particularly those related to token expiration and refresh requirements.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
- packages/sdk/package.json (2 hunks)
- packages/sdk/src/api/converter.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/sdk/package.json
🔇 Additional comments (1)
packages/sdk/src/api/converter.ts (1)
824-828
: LGTM! Good refactoring.The function has been effectively refactored to reuse
errorMetadataOf
, addressing the code duplication issue from previous reviews.
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- packages/sdk/src/document/document.ts (6 hunks)
🔇 Additional comments (5)
packages/sdk/src/document/document.ts (5)
202-206
: LGTM! The new DocEventType enum value is well-defined.The
AuthError
enum value follows the established naming pattern and has a clear descriptive comment.
227-228
: LGTM! The DocEvent type union is correctly updated.The AuthErrorEvent is properly added to the DocEvent type union.
451-451
: LGTM! The DocEventCallbackMap is correctly updated.The 'auth-error' mapping is properly added with the correct callback type.
1093-1104
: LGTM! The subscribe implementation is well-structured.The implementation correctly follows the established pattern for event subscriptions.
424-430
: 🛠️ Refactor suggestionConsider enhancing AuthErrorEvent with additional error details.
The current interface could be improved to better handle token expiration scenarios and provide more context for debugging:
The previous review suggestion is still valid. Apply this diff to enhance error information:
export interface AuthErrorEvent extends BaseDocEvent { type: DocEventType.AuthError; value: { errorMessage: string; method: 'AttachDocument' | 'DetachDocument' | 'PushPull' | 'WatchDocuments'; + code?: string; + details?: Record<string, unknown>; }; }
What this PR does / why we need it?
authTokenInjector
function instead of a static tokenclient
: activate, deactivatedocument
: attach, detach, pushpull, watchAny background context you want to provide?
1. Token Refresh Support
Added a new
authTokenInjector
interface that enables token refresh based on authentication error messages.When a
401(Unauthenticated)
error occurs, the SDK calls theauthTokenInjector
with the error message to obtain a new authToken and retries the request.2. Retry Configuration
Introduced new options to control retry behavior for failed authentication requests:
3. Updated Webhook Response Format
Modified the webhook response format: yorkie-team/yorkie#1037
{allowed: boolean, reason: string}
{code: number, message: string}
Supported response codes:
200
: OK (Allowed)401
: Unauthenticated403
: Permission Denied403
errors and invalid webhook response formats will throw errors immediately without attempting token refresh.4. Authentication Error Event Notifications
Added support for monitoring authentication errors through event subscriptions:
401
response is received from the webhookclient.subscribe()
structure for client-related webhook error notifications?What are the relevant tickets?
Fixes yorkie-team/yorkie#996
Checklist
Summary by CodeRabbit
Summary by CodeRabbit
Release Notes
New Features
AuthError
events.errorMetadataOf
function for improved error detail retrieval.Client
class with token refresh functionality and retry logic for connection errors.axios
,express
, and@types/express
, to support enhanced functionality.Bug Fixes
Tests
Chores
vite-tsconfig-paths
, to improve development and build processes.