Update to latest engine. Add sync-v2. Various fixes.
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
import { binToHex } from "@bitauth/libauth";
|
||||
import { serializeInvitation } from "@xo-cash/engine";
|
||||
import type { XOInvitation, XOInvitationCommit } from "@xo-cash/types";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const client = vi.hoisted(() => ({
|
||||
disconnect: vi.fn<() => Promise<void>>(),
|
||||
onError: undefined as ((error: Error) => void) | undefined,
|
||||
onMessage: undefined as ((message: string) => void) | undefined,
|
||||
read: vi.fn<(resourceId: string) => Promise<unknown>>(),
|
||||
subscribe: vi.fn<(resourceId: string) => Promise<void>>(),
|
||||
write:
|
||||
vi.fn<
|
||||
(resourceId: string, value: Record<string, unknown>) => Promise<unknown>
|
||||
>(),
|
||||
}));
|
||||
|
||||
vi.mock("../../src/utils/syncing/index.js", () => ({
|
||||
SSEClient: class {
|
||||
constructor(
|
||||
_url: string,
|
||||
_privateKey: unknown,
|
||||
options: {
|
||||
onError?: (error: Error) => void;
|
||||
onMessage?: (message: string) => void;
|
||||
},
|
||||
) {
|
||||
client.onError = options.onError;
|
||||
client.onMessage = options.onMessage;
|
||||
}
|
||||
|
||||
disconnect = client.disconnect;
|
||||
read = client.read;
|
||||
subscribe = client.subscribe;
|
||||
write = client.write;
|
||||
},
|
||||
}));
|
||||
|
||||
import { SyncServer } from "../../src/utils/sync-server.js";
|
||||
|
||||
const invitationIdentifier = "01".repeat(16);
|
||||
const templateIdentifier = "02".repeat(32);
|
||||
|
||||
function makeCommit(commitIdentifier: string): XOInvitationCommit {
|
||||
return {
|
||||
commitIdentifier,
|
||||
createdAtTimestamp: 1,
|
||||
data: {},
|
||||
} as XOInvitationCommit;
|
||||
}
|
||||
|
||||
function makeInvitation(
|
||||
commits: XOInvitationCommit[],
|
||||
createdAtTimestamp = 1,
|
||||
): XOInvitation {
|
||||
return {
|
||||
actionIdentifier: "send",
|
||||
commits,
|
||||
createdAtTimestamp,
|
||||
invitationIdentifier,
|
||||
templateIdentifier,
|
||||
};
|
||||
}
|
||||
|
||||
function invitationBlob(invitation: XOInvitation): Uint8Array {
|
||||
return new TextEncoder().encode(serializeInvitation(invitation));
|
||||
}
|
||||
|
||||
function encodeProtocolBlob(invitation: XOInvitation): string {
|
||||
return `<Uint8Array: ${binToHex(invitationBlob(invitation))}>`;
|
||||
}
|
||||
|
||||
describe("SyncServer v2 adapter", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
client.onError = undefined;
|
||||
client.onMessage = undefined;
|
||||
client.disconnect.mockResolvedValue();
|
||||
client.subscribe.mockResolvedValue();
|
||||
client.write.mockResolvedValue({});
|
||||
});
|
||||
|
||||
it("scopes connection and writes to one invitation resource", async () => {
|
||||
const sync = new SyncServer(
|
||||
"https://v2.sync.xo.harvmaster.com",
|
||||
invitationIdentifier,
|
||||
new Uint8Array(32).fill(1),
|
||||
);
|
||||
const invitation = makeInvitation([makeCommit("commit-a")]);
|
||||
|
||||
await sync.connect();
|
||||
await sync.publishInvitation(invitation);
|
||||
await sync.disconnect();
|
||||
|
||||
expect(client.subscribe).toHaveBeenCalledWith(invitationIdentifier);
|
||||
expect(client.write).toHaveBeenCalledWith(invitationIdentifier, invitation);
|
||||
expect(client.disconnect).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("merges signer instances returned by a v2 resource read", async () => {
|
||||
const older = makeInvitation([makeCommit("commit-a")], 1);
|
||||
const newer = makeInvitation([makeCommit("commit-b")], 2);
|
||||
client.read.mockResolvedValue([
|
||||
{
|
||||
blob: invitationBlob(older),
|
||||
publicKey: "02aa",
|
||||
resourceId: invitationIdentifier,
|
||||
timestamp: 1,
|
||||
},
|
||||
{
|
||||
blob: invitationBlob(newer),
|
||||
publicKey: "02bb",
|
||||
resourceId: invitationIdentifier,
|
||||
timestamp: 2,
|
||||
},
|
||||
]);
|
||||
const sync = new SyncServer(
|
||||
"https://v2.sync.xo.harvmaster.com",
|
||||
invitationIdentifier,
|
||||
new Uint8Array(32).fill(1),
|
||||
);
|
||||
|
||||
const invitation = await sync.getInvitation(invitationIdentifier);
|
||||
|
||||
expect(
|
||||
invitation?.commits.map((commit) => commit.commitIdentifier).sort(),
|
||||
).toEqual(["commit-a", "commit-b"]);
|
||||
expect(invitation?.createdAtTimestamp).toBe(2);
|
||||
});
|
||||
|
||||
it("translates live instance changes to the existing invitation event", () => {
|
||||
const updated = makeInvitation([makeCommit("commit-live")]);
|
||||
const sync = new SyncServer(
|
||||
"https://v2.sync.xo.harvmaster.com",
|
||||
invitationIdentifier,
|
||||
new Uint8Array(32).fill(1),
|
||||
);
|
||||
const messages: Array<{ event?: string; data: string }> = [];
|
||||
sync.on("message", (message) => messages.push(message));
|
||||
|
||||
client.onMessage?.(
|
||||
JSON.stringify({
|
||||
blob: encodeProtocolBlob(updated),
|
||||
publicKey: "02aa",
|
||||
resourceId: invitationIdentifier,
|
||||
timestamp: 2,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(messages).toHaveLength(1);
|
||||
expect(messages[0]?.event).toBe("invitation-updated");
|
||||
expect(messages[0]?.data).toBe(serializeInvitation(updated));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user