Skip to content
This repository has been archived by the owner on Oct 10, 2024. It is now read-only.

Commit

Permalink
Merge pull request #26 from xmtp/daniel-fix-reaction-form
Browse files Browse the repository at this point in the history
fix: normalize reaction encoding, support legacy form
  • Loading branch information
rygine authored Sep 5, 2023
2 parents 363e82c + 2f3617b commit 306037d
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-bananas-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@xmtp/content-type-reaction": patch
---

- Normalize Reaction content type encoding, support legacy format
42 changes: 42 additions & 0 deletions packages/content-type-reaction/src/Reaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,48 @@ describe("ReactionContentType", () => {
expect(ContentTypeReaction.versionMinor).toBe(0);
});

it("supports canonical and legacy form", () => {
const codec = new ReactionCodec();

// This is how clients send reactions now.
const canonicalEncoded = {
type: ContentTypeReaction,
content: new TextEncoder().encode(
JSON.stringify({
action: "added",
content: "smile",
reference: "abc123",
schema: "shortcode",
}),
),
};

// Previously, some clients sent reactions like this.
// So we test here to make sure we can still decode them.
const legacyEncoded = {
type: ContentTypeReaction,
parameters: {
action: "added",
reference: "abc123",
schema: "shortcode",
},
content: new TextEncoder().encode("smile"),
};

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const canonical = codec.decode(canonicalEncoded as any);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const legacy = codec.decode(legacyEncoded as any);
expect(canonical.action).toBe("added");
expect(legacy.action).toBe("added");
expect(canonical.content).toBe("smile");
expect(legacy.content).toBe("smile");
expect(canonical.reference).toBe("abc123");
expect(legacy.reference).toBe("abc123");
expect(canonical.schema).toBe("shortcode");
expect(legacy.schema).toBe("shortcode");
});

it("can send a reaction", async () => {
const aliceWallet = Wallet.createRandom();
const aliceClient = await Client.create(aliceWallet, { env: "local" });
Expand Down
41 changes: 24 additions & 17 deletions packages/content-type-reaction/src/Reaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type Reaction = {
schema: "unicode" | "shortcode" | "custom";
};

export type ReactionParameters = Pick<
type LegacyReactionParameters = Pick<
Reaction,
"action" | "reference" | "schema"
> & {
Expand All @@ -39,29 +39,36 @@ export class ReactionCodec implements ContentCodec<Reaction> {
return ContentTypeReaction;
}

encode(content: Reaction): EncodedContent<ReactionParameters> {
encode(reaction: Reaction): EncodedContent {
const { action, reference, schema, content } = reaction;
return {
type: ContentTypeReaction,
parameters: {
encoding: "UTF-8",
action: content.action,
reference: content.reference,
schema: content.schema,
},
content: new TextEncoder().encode(content.content),
parameters: {},
content: new TextEncoder().encode(
JSON.stringify({ action, reference, schema, content }),
),
};
}

decode(content: EncodedContent<ReactionParameters>): Reaction {
const { encoding } = content.parameters;
if (encoding && encoding !== "UTF-8") {
throw new Error(`unrecognized encoding ${encoding as string}`);
decode(encodedContent: EncodedContent): Reaction {
const decodedContent = new TextDecoder().decode(encodedContent.content);

// First try to decode it in the canonical form.
try {
const reaction = JSON.parse(decodedContent) as Reaction;
const { action, reference, schema, content } = reaction;
return { action, reference, schema, content };
} catch (e) {
// ignore, fall through to legacy decoding
}

// If that fails, try to decode it in the legacy form.
const parameters = encodedContent.parameters as LegacyReactionParameters;
return {
action: content.parameters.action,
reference: content.parameters.reference,
schema: content.parameters.schema,
content: new TextDecoder().decode(content.content),
action: parameters.action,
reference: parameters.reference,
schema: parameters.schema,
content: decodedContent,
};
}
}
2 changes: 1 addition & 1 deletion packages/content-type-reaction/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { ReactionCodec, ContentTypeReaction } from "./Reaction";
export type { Reaction, ReactionParameters } from "./Reaction";
export type { Reaction } from "./Reaction";

0 comments on commit 306037d

Please sign in to comment.