Skip to content

Commit 8b72d1a

Browse files
authored
feat(zero-protocol): client-side of revised-cookie poke protocol (#3735)
1 parent 3ae4ae9 commit 8b72d1a

File tree

5 files changed

+88
-5
lines changed

5 files changed

+88
-5
lines changed

packages/zero-client/src/client/zero-poke-handler.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,9 @@ test('mergePokes with all optionals defined', () => {
13111311
],
13121312
},
13131313
],
1314+
pokeEnd: {
1315+
pokeID: 'poke1',
1316+
},
13141317
},
13151318
{
13161319
pokeStart: {
@@ -1346,6 +1349,9 @@ test('mergePokes with all optionals defined', () => {
13461349
],
13471350
},
13481351
],
1352+
pokeEnd: {
1353+
pokeID: 'poke2',
1354+
},
13491355
},
13501356
],
13511357
schema,
@@ -1505,6 +1511,9 @@ test('mergePokes sparse', () => {
15051511
},
15061512
},
15071513
],
1514+
pokeEnd: {
1515+
pokeID: 'poke1',
1516+
},
15081517
},
15091518
{
15101519
pokeStart: {
@@ -1533,6 +1542,9 @@ test('mergePokes sparse', () => {
15331542
],
15341543
},
15351544
],
1545+
pokeEnd: {
1546+
pokeID: 'poke2',
1547+
},
15361548
},
15371549
],
15381550
schema,
@@ -1601,6 +1613,64 @@ test('mergePokes sparse', () => {
16011613
});
16021614
});
16031615

1616+
test('mergePokes with cookie revisions', () => {
1617+
expect(
1618+
mergePokes(
1619+
[
1620+
{
1621+
pokeStart: {
1622+
pokeID: 'poke1',
1623+
baseCookie: '3',
1624+
cookie: '5',
1625+
schemaVersions: {minSupportedVersion: 1, maxSupportedVersion: 1},
1626+
},
1627+
parts: [
1628+
{
1629+
pokeID: 'poke1',
1630+
lastMutationIDChanges: {c1: 1, c2: 2},
1631+
},
1632+
],
1633+
pokeEnd: {
1634+
pokeID: 'poke1',
1635+
cookie: '3', // Never mind, back to 3
1636+
},
1637+
},
1638+
{
1639+
pokeStart: {
1640+
pokeID: 'poke2',
1641+
baseCookie: '3',
1642+
cookie: '7',
1643+
schemaVersions: {minSupportedVersion: 1, maxSupportedVersion: 1},
1644+
},
1645+
parts: [
1646+
{
1647+
pokeID: 'poke2',
1648+
lastMutationIDChanges: {c4: 3},
1649+
},
1650+
],
1651+
pokeEnd: {
1652+
pokeID: 'poke2',
1653+
cookie: '6', // Not 7, but 6.
1654+
},
1655+
},
1656+
],
1657+
schema,
1658+
serverToClient(schema.tables),
1659+
),
1660+
).toEqual({
1661+
baseCookie: '3',
1662+
pullResponse: {
1663+
cookie: '6',
1664+
lastMutationIDChanges: {
1665+
c1: 1,
1666+
c2: 2,
1667+
c4: 3,
1668+
},
1669+
patch: [],
1670+
},
1671+
});
1672+
});
1673+
16041674
test('mergePokes throws error on cookie gaps', () => {
16051675
expect(() => {
16061676
mergePokes(
@@ -1618,6 +1688,9 @@ test('mergePokes throws error on cookie gaps', () => {
16181688
lastMutationIDChanges: {c1: 1, c2: 2},
16191689
},
16201690
],
1691+
pokeEnd: {
1692+
pokeID: 'poke1',
1693+
},
16211694
},
16221695
{
16231696
pokeStart: {
@@ -1632,6 +1705,9 @@ test('mergePokes throws error on cookie gaps', () => {
16321705
lastMutationIDChanges: {c4: 3},
16331706
},
16341707
],
1708+
pokeEnd: {
1709+
pokeID: 'poke2',
1710+
},
16351711
},
16361712
],
16371713
schema,

packages/zero-client/src/client/zero-poke-handler.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
type PokeAccumulator = {
3333
readonly pokeStart: PokeStartBody;
3434
readonly parts: PokePartBody[];
35+
readonly pokeEnd: PokeEndBody;
3536
};
3637

3738
/**
@@ -48,7 +49,7 @@ export class PokeHandler {
4849
readonly #onPokeError: () => void;
4950
readonly #clientID: ClientID;
5051
readonly #lc: LogContext;
51-
#receivingPoke: PokeAccumulator | undefined = undefined;
52+
#receivingPoke: Omit<PokeAccumulator, 'pokeEnd'> | undefined = undefined;
5253
readonly #pokeBuffer: PokeAccumulator[] = [];
5354
#pokePlaybackLoopRunning = false;
5455
#lastRafPerfTimestamp = 0;
@@ -117,7 +118,7 @@ export class PokeHandler {
117118
this.#receivingPoke = undefined;
118119
return;
119120
}
120-
this.#pokeBuffer.push(this.#receivingPoke);
121+
this.#pokeBuffer.push({...this.#receivingPoke, pokeEnd});
121122
this.#receivingPoke = undefined;
122123
if (!this.#pokePlaybackLoopRunning) {
123124
this.#startPlaybackLoop();
@@ -207,7 +208,8 @@ export function mergePokes(
207208
return undefined;
208209
}
209210
const {baseCookie} = pokeBuffer[0].pokeStart;
210-
const {cookie} = pokeBuffer[pokeBuffer.length - 1].pokeStart;
211+
const lastPoke = pokeBuffer[pokeBuffer.length - 1];
212+
const cookie = lastPoke.pokeEnd.cookie ?? lastPoke.pokeStart.cookie;
211213
const mergedPatch: PatchOperationInternal[] = [];
212214
const mergedLastMutationIDChanges: Record<string, number> = {};
213215

packages/zero-protocol/src/ast.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,5 +607,5 @@ test('protocol version', () => {
607607
// old code will not understand the new schema, bump the
608608
// PROTOCOL_VERSION and update the expected values.
609609
expect(hash).toEqual('2zzy9s2lcdcms');
610-
expect(PROTOCOL_VERSION).toEqual(4);
610+
expect(PROTOCOL_VERSION).toEqual(5);
611611
});

packages/zero-protocol/src/poke.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ export const pokePartBodySchema = v.object({
6767

6868
export const pokeEndBodySchema = v.object({
6969
pokeID: v.string(),
70+
// If present, this should be the cookie stored with the client,
71+
// instead of the cookie presented in pokeStart.
72+
// TODO: Consider making this required and removing it from pokeStart.
73+
cookie: versionSchema.optional(),
7074
// If `true`, the poke with id `pokeID` should be discarded without
7175
// applying it.
7276
cancel: v.boolean().optional(),

packages/zero-protocol/src/protocol-version.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {assert} from '../../shared/src/asserts.ts';
1212
* release. The server (`zero-cache`) must be deployed before clients start
1313
* running the new code.
1414
*/
15-
export const PROTOCOL_VERSION = 4;
15+
export const PROTOCOL_VERSION = 5;
1616

1717
/**
1818
* The minimum protocol version supported by the server. The contract for
@@ -23,6 +23,7 @@ export const PROTOCOL_VERSION = 4;
2323
* from protocol versions before `MIN_SERVER_SUPPORTED_PROTOCOL_VERSION` are
2424
* closed with a `VersionNotSupported` error.
2525
*/
26+
// TODO: Bump to 5 before returning responses with pokeEnd.cookie.
2627
export const MIN_SERVER_SUPPORTED_PROTOCOL_VERSION = 2;
2728

2829
assert(MIN_SERVER_SUPPORTED_PROTOCOL_VERSION < PROTOCOL_VERSION);

0 commit comments

Comments
 (0)