@livestore/sync-electric 0.3.0-dev.11 → 0.3.0-dev.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.d.ts +62 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -12
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/src/index.ts +27 -16
package/dist/index.d.ts
CHANGED
|
@@ -1,39 +1,74 @@
|
|
|
1
|
-
import type { SyncBackend } from '@livestore/common';
|
|
1
|
+
import type { SyncBackend, SyncBackendOptionsBase } from '@livestore/common';
|
|
2
2
|
import type { Scope } from '@livestore/utils/effect';
|
|
3
3
|
import { Effect, Schema } from '@livestore/utils/effect';
|
|
4
4
|
export declare const syncBackend: any;
|
|
5
5
|
export declare const ApiPushEventPayload: Schema.TaggedStruct<"sync-electric.PushEvent", {
|
|
6
|
-
|
|
7
|
-
batch: Schema.Array$<Schema.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
roomId: typeof Schema.String;
|
|
7
|
+
batch: Schema.Array$<Schema.SchemaClass<{
|
|
8
|
+
readonly id: {
|
|
9
|
+
readonly global: number;
|
|
10
|
+
readonly local: number;
|
|
11
|
+
};
|
|
12
|
+
readonly mutation: string;
|
|
13
|
+
readonly args: any;
|
|
14
|
+
readonly parentId: {
|
|
15
|
+
readonly global: number;
|
|
16
|
+
readonly local: number;
|
|
17
|
+
};
|
|
18
|
+
}, {
|
|
19
|
+
readonly id: {
|
|
20
|
+
readonly global: number;
|
|
21
|
+
readonly local: number;
|
|
22
|
+
};
|
|
23
|
+
readonly mutation: string;
|
|
24
|
+
readonly args: any;
|
|
25
|
+
readonly parentId: {
|
|
26
|
+
readonly global: number;
|
|
27
|
+
readonly local: number;
|
|
28
|
+
};
|
|
29
|
+
}, never>>;
|
|
13
30
|
}>;
|
|
14
31
|
export declare const ApiInitRoomPayload: Schema.TaggedStruct<"sync-electric.InitRoom", {
|
|
15
|
-
|
|
32
|
+
roomId: typeof Schema.String;
|
|
16
33
|
}>;
|
|
17
34
|
export declare const ApiPayload: Schema.Union<[Schema.TaggedStruct<"sync-electric.PushEvent", {
|
|
18
|
-
|
|
19
|
-
batch: Schema.Array$<Schema.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
35
|
+
roomId: typeof Schema.String;
|
|
36
|
+
batch: Schema.Array$<Schema.SchemaClass<{
|
|
37
|
+
readonly id: {
|
|
38
|
+
readonly global: number;
|
|
39
|
+
readonly local: number;
|
|
40
|
+
};
|
|
41
|
+
readonly mutation: string;
|
|
42
|
+
readonly args: any;
|
|
43
|
+
readonly parentId: {
|
|
44
|
+
readonly global: number;
|
|
45
|
+
readonly local: number;
|
|
46
|
+
};
|
|
47
|
+
}, {
|
|
48
|
+
readonly id: {
|
|
49
|
+
readonly global: number;
|
|
50
|
+
readonly local: number;
|
|
51
|
+
};
|
|
52
|
+
readonly mutation: string;
|
|
53
|
+
readonly args: any;
|
|
54
|
+
readonly parentId: {
|
|
55
|
+
readonly global: number;
|
|
56
|
+
readonly local: number;
|
|
57
|
+
};
|
|
58
|
+
}, never>>;
|
|
25
59
|
}>, Schema.TaggedStruct<"sync-electric.InitRoom", {
|
|
26
|
-
|
|
60
|
+
roomId: typeof Schema.String;
|
|
27
61
|
}>]>;
|
|
28
62
|
export declare const syncBackendOptions: <TOptions extends SyncBackendOptions>(options: TOptions) => TOptions;
|
|
29
|
-
export interface SyncBackendOptions {
|
|
63
|
+
export interface SyncBackendOptions extends SyncBackendOptionsBase {
|
|
64
|
+
type: 'electric';
|
|
30
65
|
/**
|
|
31
66
|
* The host of the Electric server
|
|
32
67
|
*
|
|
33
68
|
* @example "https://localhost:3000"
|
|
34
69
|
*/
|
|
35
70
|
electricHost: string;
|
|
36
|
-
|
|
71
|
+
roomId: string;
|
|
37
72
|
/**
|
|
38
73
|
* The POST endpoint to push events to
|
|
39
74
|
*
|
|
@@ -42,10 +77,17 @@ export interface SyncBackendOptions {
|
|
|
42
77
|
*/
|
|
43
78
|
pushEventEndpoint: string;
|
|
44
79
|
}
|
|
80
|
+
interface LiveStoreGlobalElectric {
|
|
81
|
+
syncBackend: SyncBackendOptions;
|
|
82
|
+
}
|
|
83
|
+
declare global {
|
|
84
|
+
interface LiveStoreGlobal extends LiveStoreGlobalElectric {
|
|
85
|
+
}
|
|
86
|
+
}
|
|
45
87
|
type SyncMetadata = {
|
|
46
88
|
offset: string;
|
|
47
89
|
shapeId: string;
|
|
48
90
|
};
|
|
49
|
-
export declare const makeSyncBackend: ({ electricHost,
|
|
91
|
+
export declare const makeSyncBackend: ({ electricHost, roomId, pushEventEndpoint, }: SyncBackendOptions) => Effect.Effect<SyncBackend<SyncMetadata>, never, Scope.Scope>;
|
|
50
92
|
export {};
|
|
51
93
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAI5E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAGL,MAAM,EAKN,MAAM,EAGP,MAAM,yBAAyB,CAAA;AA4BhC,eAAO,MAAM,WAAW,EAAS,GAAG,CAAA;AAEpC,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;EAG9B,CAAA;AAEF,eAAO,MAAM,kBAAkB;;EAE7B,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAwD,CAAA;AAE/E,eAAO,MAAM,kBAAkB,GAAI,QAAQ,SAAS,kBAAkB,WAAW,QAAQ,aAAY,CAAA;AAErG,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IAChE,IAAI,EAAE,UAAU,CAAA;IAChB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAED,UAAU,uBAAuB;IAC/B,WAAW,EAAE,kBAAkB,CAAA;CAChC;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,eAAgB,SAAQ,uBAAuB;KAAG;CAC7D;AAED,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE,MAAM,CAAA;IAEd,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,eAAe,iDAIzB,kBAAkB,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAgI/E,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ Also see: https://github.com/electric-sql/electric/blob/main/packages/typescript
|
|
|
14
14
|
const ResponseItem = Schema.Struct({
|
|
15
15
|
/** Postgres path (e.g. "public.events/1") */
|
|
16
16
|
key: Schema.optional(Schema.String),
|
|
17
|
-
value: Schema.optional(MutationEvent.
|
|
17
|
+
value: Schema.optional(MutationEvent.EncodedAny),
|
|
18
18
|
headers: Schema.Record({ key: Schema.String, value: Schema.Any }),
|
|
19
19
|
offset: Schema.optional(Schema.String),
|
|
20
20
|
});
|
|
@@ -26,18 +26,18 @@ const ResponseHeaders = Schema.Struct({
|
|
|
26
26
|
});
|
|
27
27
|
export const syncBackend = {};
|
|
28
28
|
export const ApiPushEventPayload = Schema.TaggedStruct('sync-electric.PushEvent', {
|
|
29
|
-
|
|
30
|
-
batch: Schema.Array(MutationEvent.
|
|
29
|
+
roomId: Schema.String,
|
|
30
|
+
batch: Schema.Array(MutationEvent.EncodedAny),
|
|
31
31
|
});
|
|
32
32
|
export const ApiInitRoomPayload = Schema.TaggedStruct('sync-electric.InitRoom', {
|
|
33
|
-
|
|
33
|
+
roomId: Schema.String,
|
|
34
34
|
});
|
|
35
35
|
export const ApiPayload = Schema.Union(ApiPushEventPayload, ApiInitRoomPayload);
|
|
36
36
|
export const syncBackendOptions = (options) => options;
|
|
37
|
-
export const makeSyncBackend = ({ electricHost,
|
|
38
|
-
const endpointUrl = `${electricHost}/v1/shape/events_${
|
|
37
|
+
export const makeSyncBackend = ({ electricHost, roomId, pushEventEndpoint, }) => Effect.gen(function* () {
|
|
38
|
+
const endpointUrl = `${electricHost}/v1/shape/events_${roomId}`;
|
|
39
39
|
const isConnected = yield* SubscriptionRef.make(true);
|
|
40
|
-
const initRoom = HttpClientRequest.schemaBodyJson(ApiInitRoomPayload)(HttpClientRequest.post(pushEventEndpoint), ApiInitRoomPayload.make({
|
|
40
|
+
const initRoom = HttpClientRequest.schemaBodyJson(ApiInitRoomPayload)(HttpClientRequest.post(pushEventEndpoint), ApiInitRoomPayload.make({ roomId })).pipe(Effect.andThen(HttpClient.execute));
|
|
41
41
|
// TODO check whether we still need this
|
|
42
42
|
const pendingPushDeferredMap = new Map();
|
|
43
43
|
const pull = (args) => Effect.gen(function* () {
|
|
@@ -75,9 +75,9 @@ export const makeSyncBackend = ({ electricHost, storeId, pushEventEndpoint, }) =
|
|
|
75
75
|
// if (listenForNew === false && items.length === 0) {
|
|
76
76
|
// return Option.none()
|
|
77
77
|
// }
|
|
78
|
-
const [newItems, pendingPushItems] = Chunk.fromIterable(items).pipe(Chunk.partition((item) => pendingPushDeferredMap.has(item.mutationEventEncoded.id)));
|
|
78
|
+
const [newItems, pendingPushItems] = Chunk.fromIterable(items).pipe(Chunk.partition((item) => pendingPushDeferredMap.has(eventIdToString(item.mutationEventEncoded.id))));
|
|
79
79
|
for (const item of pendingPushItems) {
|
|
80
|
-
const deferred = pendingPushDeferredMap.get(item.mutationEventEncoded.id);
|
|
80
|
+
const deferred = pendingPushDeferredMap.get(eventIdToString(item.mutationEventEncoded.id));
|
|
81
81
|
yield* Deferred.succeed(deferred, Option.getOrThrow(item.metadata));
|
|
82
82
|
}
|
|
83
83
|
return Option.some([newItems, Option.some(nextCursor)]);
|
|
@@ -88,20 +88,21 @@ export const makeSyncBackend = ({ electricHost, storeId, pushEventEndpoint, }) =
|
|
|
88
88
|
const deferreds = [];
|
|
89
89
|
for (const mutationEventEncoded of batch) {
|
|
90
90
|
const deferred = yield* Deferred.make();
|
|
91
|
-
pendingPushDeferredMap.set(mutationEventEncoded.id, deferred);
|
|
91
|
+
pendingPushDeferredMap.set(eventIdToString(mutationEventEncoded.id), deferred);
|
|
92
92
|
deferreds.push(deferred);
|
|
93
93
|
}
|
|
94
|
-
const resp = yield* HttpClientRequest.schemaBodyJson(ApiPushEventPayload)(HttpClientRequest.post(pushEventEndpoint), ApiPushEventPayload.make({
|
|
94
|
+
const resp = yield* HttpClientRequest.schemaBodyJson(ApiPushEventPayload)(HttpClientRequest.post(pushEventEndpoint), ApiPushEventPayload.make({ roomId, batch })).pipe(Effect.andThen(HttpClient.execute), Effect.andThen(HttpClientResponse.schemaBodyJson(Schema.Struct({ success: Schema.Boolean }))), Effect.scoped, Effect.mapError((cause) => InvalidPushError.make({ reason: { _tag: 'Unexpected', message: cause.toString() } })));
|
|
95
95
|
if (!resp.success) {
|
|
96
96
|
yield* InvalidPushError.make({ reason: { _tag: 'Unexpected', message: 'Push failed' } });
|
|
97
97
|
}
|
|
98
98
|
const metadata = yield* Effect.all(deferreds, { concurrency: 'unbounded' }).pipe(Effect.map((_) => _.map(Option.some)));
|
|
99
99
|
for (const mutationEventEncoded of batch) {
|
|
100
|
-
pendingPushDeferredMap.delete(mutationEventEncoded.id);
|
|
100
|
+
pendingPushDeferredMap.delete(eventIdToString(mutationEventEncoded.id));
|
|
101
101
|
}
|
|
102
102
|
return { metadata };
|
|
103
103
|
}),
|
|
104
104
|
isConnected,
|
|
105
105
|
};
|
|
106
106
|
});
|
|
107
|
+
const eventIdToString = (eventId) => `${eventId.global}_${eventId.local}`;
|
|
107
108
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEtE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAExD,OAAO,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,EACN,MAAM,EACN,MAAM,EACN,eAAe,GAChB,MAAM,yBAAyB,CAAA;AAEhC;;;;;;;;;EASE;AAEF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestore/sync-electric",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.2",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"sideEffects": false,
|
|
6
5
|
"exports": {
|
|
7
6
|
".": {
|
|
8
7
|
"types": "./dist/index.d.ts",
|
|
@@ -10,8 +9,8 @@
|
|
|
10
9
|
}
|
|
11
10
|
},
|
|
12
11
|
"dependencies": {
|
|
13
|
-
"@livestore/common": "0.3.0-dev.
|
|
14
|
-
"@livestore/utils": "0.3.0-dev.
|
|
12
|
+
"@livestore/common": "0.3.0-dev.2",
|
|
13
|
+
"@livestore/utils": "0.3.0-dev.2"
|
|
15
14
|
},
|
|
16
15
|
"devDependencies": {},
|
|
17
16
|
"publishConfig": {
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SyncBackend } from '@livestore/common'
|
|
1
|
+
import type { SyncBackend, SyncBackendOptionsBase } from '@livestore/common'
|
|
2
2
|
import { InvalidPullError, InvalidPushError } from '@livestore/common'
|
|
3
3
|
import type { EventId } from '@livestore/common/schema'
|
|
4
4
|
import { MutationEvent } from '@livestore/common/schema'
|
|
@@ -30,7 +30,7 @@ Also see: https://github.com/electric-sql/electric/blob/main/packages/typescript
|
|
|
30
30
|
const ResponseItem = Schema.Struct({
|
|
31
31
|
/** Postgres path (e.g. "public.events/1") */
|
|
32
32
|
key: Schema.optional(Schema.String),
|
|
33
|
-
value: Schema.optional(MutationEvent.
|
|
33
|
+
value: Schema.optional(MutationEvent.EncodedAny),
|
|
34
34
|
headers: Schema.Record({ key: Schema.String, value: Schema.Any }),
|
|
35
35
|
offset: Schema.optional(Schema.String),
|
|
36
36
|
})
|
|
@@ -45,26 +45,27 @@ const ResponseHeaders = Schema.Struct({
|
|
|
45
45
|
export const syncBackend = {} as any
|
|
46
46
|
|
|
47
47
|
export const ApiPushEventPayload = Schema.TaggedStruct('sync-electric.PushEvent', {
|
|
48
|
-
|
|
49
|
-
batch: Schema.Array(MutationEvent.
|
|
48
|
+
roomId: Schema.String,
|
|
49
|
+
batch: Schema.Array(MutationEvent.EncodedAny),
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
export const ApiInitRoomPayload = Schema.TaggedStruct('sync-electric.InitRoom', {
|
|
53
|
-
|
|
53
|
+
roomId: Schema.String,
|
|
54
54
|
})
|
|
55
55
|
|
|
56
56
|
export const ApiPayload = Schema.Union(ApiPushEventPayload, ApiInitRoomPayload)
|
|
57
57
|
|
|
58
58
|
export const syncBackendOptions = <TOptions extends SyncBackendOptions>(options: TOptions) => options
|
|
59
59
|
|
|
60
|
-
export interface SyncBackendOptions {
|
|
60
|
+
export interface SyncBackendOptions extends SyncBackendOptionsBase {
|
|
61
|
+
type: 'electric'
|
|
61
62
|
/**
|
|
62
63
|
* The host of the Electric server
|
|
63
64
|
*
|
|
64
65
|
* @example "https://localhost:3000"
|
|
65
66
|
*/
|
|
66
67
|
electricHost: string
|
|
67
|
-
|
|
68
|
+
roomId: string
|
|
68
69
|
/**
|
|
69
70
|
* The POST endpoint to push events to
|
|
70
71
|
*
|
|
@@ -74,6 +75,14 @@ export interface SyncBackendOptions {
|
|
|
74
75
|
pushEventEndpoint: string
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
interface LiveStoreGlobalElectric {
|
|
79
|
+
syncBackend: SyncBackendOptions
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
declare global {
|
|
83
|
+
interface LiveStoreGlobal extends LiveStoreGlobalElectric {}
|
|
84
|
+
}
|
|
85
|
+
|
|
77
86
|
type SyncMetadata = {
|
|
78
87
|
offset: string
|
|
79
88
|
// TODO move this into some kind of "global" sync metadata as it's the same for each event
|
|
@@ -82,21 +91,21 @@ type SyncMetadata = {
|
|
|
82
91
|
|
|
83
92
|
export const makeSyncBackend = ({
|
|
84
93
|
electricHost,
|
|
85
|
-
|
|
94
|
+
roomId,
|
|
86
95
|
pushEventEndpoint,
|
|
87
96
|
}: SyncBackendOptions): Effect.Effect<SyncBackend<SyncMetadata>, never, Scope.Scope> =>
|
|
88
97
|
Effect.gen(function* () {
|
|
89
|
-
const endpointUrl = `${electricHost}/v1/shape/events_${
|
|
98
|
+
const endpointUrl = `${electricHost}/v1/shape/events_${roomId}`
|
|
90
99
|
|
|
91
100
|
const isConnected = yield* SubscriptionRef.make(true)
|
|
92
101
|
|
|
93
102
|
const initRoom = HttpClientRequest.schemaBodyJson(ApiInitRoomPayload)(
|
|
94
103
|
HttpClientRequest.post(pushEventEndpoint),
|
|
95
|
-
ApiInitRoomPayload.make({
|
|
104
|
+
ApiInitRoomPayload.make({ roomId }),
|
|
96
105
|
).pipe(Effect.andThen(HttpClient.execute))
|
|
97
106
|
|
|
98
107
|
// TODO check whether we still need this
|
|
99
|
-
const pendingPushDeferredMap = new Map<
|
|
108
|
+
const pendingPushDeferredMap = new Map<string, Deferred.Deferred<SyncMetadata>>()
|
|
100
109
|
|
|
101
110
|
const pull = (args: Option.Option<SyncMetadata>) =>
|
|
102
111
|
Effect.gen(function* () {
|
|
@@ -148,11 +157,11 @@ export const makeSyncBackend = ({
|
|
|
148
157
|
// }
|
|
149
158
|
|
|
150
159
|
const [newItems, pendingPushItems] = Chunk.fromIterable(items).pipe(
|
|
151
|
-
Chunk.partition((item) => pendingPushDeferredMap.has(item.mutationEventEncoded.id)),
|
|
160
|
+
Chunk.partition((item) => pendingPushDeferredMap.has(eventIdToString(item.mutationEventEncoded.id))),
|
|
152
161
|
)
|
|
153
162
|
|
|
154
163
|
for (const item of pendingPushItems) {
|
|
155
|
-
const deferred = pendingPushDeferredMap.get(item.mutationEventEncoded.id)!
|
|
164
|
+
const deferred = pendingPushDeferredMap.get(eventIdToString(item.mutationEventEncoded.id))!
|
|
156
165
|
yield* Deferred.succeed(deferred, Option.getOrThrow(item.metadata))
|
|
157
166
|
}
|
|
158
167
|
|
|
@@ -180,13 +189,13 @@ export const makeSyncBackend = ({
|
|
|
180
189
|
const deferreds: Deferred.Deferred<SyncMetadata>[] = []
|
|
181
190
|
for (const mutationEventEncoded of batch) {
|
|
182
191
|
const deferred = yield* Deferred.make<SyncMetadata>()
|
|
183
|
-
pendingPushDeferredMap.set(mutationEventEncoded.id, deferred)
|
|
192
|
+
pendingPushDeferredMap.set(eventIdToString(mutationEventEncoded.id), deferred)
|
|
184
193
|
deferreds.push(deferred)
|
|
185
194
|
}
|
|
186
195
|
|
|
187
196
|
const resp = yield* HttpClientRequest.schemaBodyJson(ApiPushEventPayload)(
|
|
188
197
|
HttpClientRequest.post(pushEventEndpoint),
|
|
189
|
-
ApiPushEventPayload.make({
|
|
198
|
+
ApiPushEventPayload.make({ roomId, batch }),
|
|
190
199
|
).pipe(
|
|
191
200
|
Effect.andThen(HttpClient.execute),
|
|
192
201
|
Effect.andThen(HttpClientResponse.schemaBodyJson(Schema.Struct({ success: Schema.Boolean }))),
|
|
@@ -205,7 +214,7 @@ export const makeSyncBackend = ({
|
|
|
205
214
|
)
|
|
206
215
|
|
|
207
216
|
for (const mutationEventEncoded of batch) {
|
|
208
|
-
pendingPushDeferredMap.delete(mutationEventEncoded.id)
|
|
217
|
+
pendingPushDeferredMap.delete(eventIdToString(mutationEventEncoded.id))
|
|
209
218
|
}
|
|
210
219
|
|
|
211
220
|
return { metadata }
|
|
@@ -213,3 +222,5 @@ export const makeSyncBackend = ({
|
|
|
213
222
|
isConnected,
|
|
214
223
|
} satisfies SyncBackend<SyncMetadata>
|
|
215
224
|
})
|
|
225
|
+
|
|
226
|
+
const eventIdToString = (eventId: EventId.EventId) => `${eventId.global}_${eventId.local}`
|