Skip to content

Commit 3942b9e

Browse files
CopilotJunyi-99
andauthored
feat: add ignoreUnknownFields to protobuf JSON parsing (#63)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Junyi-99 <14367694+Junyi-99@users.noreply.github.com>
1 parent 7112ddb commit 3942b9e

14 files changed

Lines changed: 107 additions & 12 deletions

File tree

webapp/_webapp/src/components/message-entry-container/tools/paper-score-comment/add-comments-button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { OverleafComment } from "../../../../pkg/gen/apiclient/project/v1/projec
44
import { useSocketStore } from "../../../../stores/socket-store";
55
import { addClickedOverleafComment, hasClickedOverleafComment } from "../../../../libs/helpers";
66
import { acceptComments } from "../../../../query/api";
7-
import { fromJson } from "@bufbuild/protobuf";
7+
import { fromJson } from "../../../../libs/protobuf-utils";
88
import { CommentsAcceptedRequestSchema } from "../../../../pkg/gen/apiclient/comment/v1/comment_pb";
99
import { useConversationStore } from "../../../../stores/conversation/conversation-store";
1010

webapp/_webapp/src/components/message-entry-container/tools/paper-score-comment/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { fromJson, JsonValue } from "@bufbuild/protobuf";
1+
import { JsonValue } from "@bufbuild/protobuf";
2+
import { fromJson } from "../../../../libs/protobuf-utils";
23
import { OverleafCommentSchema } from "../../../../pkg/gen/apiclient/project/v1/project_pb";
34
import { getProjectId } from "../../../../libs/helpers";
45
import { useEffect, useState } from "react";

webapp/_webapp/src/components/message-entry-container/tools/paper-score.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { PaperScoreResultSchema } from "../../../pkg/gen/apiclient/project/v1/project_pb";
2-
import { fromJson } from "@bufbuild/protobuf";
2+
import { fromJson } from "../../../libs/protobuf-utils";
33
import { LoadingIndicator } from "../../loading-indicator";
44
import { logError } from "../../../libs/logger";
55
import { cn } from "@heroui/react";

webapp/_webapp/src/hooks/useSendMessageStream.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
StreamPartEnd,
2626
} from "../pkg/gen/apiclient/chat/v2/chat_pb";
2727
import { MessageEntry, MessageEntryStatus } from "../stores/conversation/types";
28-
import { fromJson } from "@bufbuild/protobuf";
28+
import { fromJson } from "../libs/protobuf-utils";
2929
import { useConversationStore } from "../stores/conversation/conversation-store";
3030
import { useListConversationsQuery } from "../query";
3131
import { useSocketStore } from "../stores/socket-store";

webapp/_webapp/src/libs/apiclient.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from "axios";
2-
import { fromJson, JsonValue } from "@bufbuild/protobuf";
2+
import { JsonValue } from "@bufbuild/protobuf";
3+
import { fromJson } from "./protobuf-utils";
34
import { RefreshTokenResponseSchema } from "../pkg/gen/apiclient/auth/v1/auth_pb";
45
import { GetUserResponseSchema } from "../pkg/gen/apiclient/user/v1/user_pb";
56
import { EventEmitter } from "events";
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Test file to demonstrate that the protobuf-utils wrapper handles unknown fields gracefully.
3+
*
4+
* This test can be run manually to verify the fix. Since the project doesn't have
5+
* a test runner configured, this serves as documentation of the expected behavior.
6+
*
7+
* To test manually:
8+
* 1. Add a new field to a protobuf schema on the backend
9+
* 2. Deploy the backend
10+
* 3. Use an older version of the webapp (without regenerating protobuf files)
11+
* 4. Verify that the webapp doesn't crash when receiving the new field
12+
*/
13+
14+
import { fromJson } from "./protobuf-utils";
15+
import { MessageSchema } from "../pkg/gen/apiclient/chat/v2/chat_pb";
16+
17+
/**
18+
* Example: Testing that fromJson ignores unknown fields
19+
*
20+
* This would simulate a backend returning a message with a new field
21+
* that doesn't exist in the current schema.
22+
*/
23+
function testIgnoreUnknownFields() {
24+
// Simulate JSON response from backend with an extra field "newField"
25+
const jsonWithUnknownField = {
26+
messageId: "test-123",
27+
payload: {
28+
user: {
29+
content: "Hello",
30+
selectedText: "",
31+
newFieldThatDoesntExistYet: "This is a new field from a newer backend version",
32+
},
33+
},
34+
timestamp: "0",
35+
};
36+
37+
try {
38+
// This should NOT throw an error even though "newFieldThatDoesntExistYet" doesn't exist in the schema
39+
const message = fromJson(MessageSchema, jsonWithUnknownField);
40+
console.log("✓ Successfully parsed message with unknown field");
41+
console.log(" Message ID:", message.messageId);
42+
console.log(" User content:", message.payload.user?.content);
43+
return true;
44+
} catch (error) {
45+
console.error("✗ Failed to parse message with unknown field:", error);
46+
return false;
47+
}
48+
}
49+
50+
/**
51+
* Example: Testing that fromJson still validates required fields
52+
*/
53+
function testRequiredFieldsStillValidated() {
54+
// Missing required messageId field
55+
const invalidJson = {
56+
payload: {
57+
user: {
58+
content: "Hello",
59+
},
60+
},
61+
};
62+
63+
try {
64+
const message = fromJson(MessageSchema, invalidJson);
65+
console.log("✓ Parsed message (messageId will be empty string):", message.messageId);
66+
return true;
67+
} catch (error) {
68+
console.error("✗ Failed to parse message:", error);
69+
return false;
70+
}
71+
}
72+
73+
// Export test functions for manual testing
74+
export { testIgnoreUnknownFields, testRequiredFieldsStillValidated };
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { DescMessage, fromJson as bufFromJson, JsonValue } from "@bufbuild/protobuf";
2+
3+
/**
4+
* Wrapper around fromJson that ignores unknown fields to prevent crashes
5+
* when new fields are added to the schema.
6+
*
7+
* This allows forward compatibility - older webapp versions can work with
8+
* newer backend versions that introduce new fields.
9+
*/
10+
export function fromJson<Desc extends DescMessage>(
11+
schema: Desc,
12+
json: JsonValue,
13+
): InstanceType<Desc["message"]> {
14+
return bufFromJson(schema, json, {
15+
ignoreUnknownFields: true,
16+
});
17+
}

webapp/_webapp/src/query/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import {
5757
GetUserInstructionsRequest,
5858
} from "../pkg/gen/apiclient/user/v1/user_pb";
5959
import { PlainMessage } from "./types";
60-
import { fromJson } from "@bufbuild/protobuf";
60+
import { fromJson } from "../libs/protobuf-utils";
6161
import { processStream } from "./utils";
6262
import { CommentsAcceptedRequest, CommentsAcceptedResponseSchema } from "../pkg/gen/apiclient/comment/v1/comment_pb";
6363

webapp/_webapp/src/query/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { DescMessage, fromJson, JsonValue, JsonWriteOptions, toJson } from "@bufbuild/protobuf";
1+
import { DescMessage, JsonValue, JsonWriteOptions, toJson } from "@bufbuild/protobuf";
2+
import { fromJson } from "../libs/protobuf-utils";
23
import { logError } from "../libs/logger";
34
import { useDevtoolStore } from "../stores/devtool-store";
45

webapp/_webapp/src/stores/conversation/conversation-store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { create } from "zustand";
22
import { Conversation, ConversationSchema } from "../../pkg/gen/apiclient/chat/v2/chat_pb";
3-
import { fromJson } from "@bufbuild/protobuf";
3+
import { fromJson } from "../../libs/protobuf-utils";
44
import { useConversationUiStore } from "./conversation-ui-store";
55

66
interface ConversationStore {

0 commit comments

Comments
 (0)