@memrosetta/sync-client 0.1.0 → 0.1.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/index.d.ts +20 -1
- package/dist/index.js +43 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ declare class Outbox {
|
|
|
7
7
|
constructor(db: Database.Database);
|
|
8
8
|
addOp(op: SyncOp): void;
|
|
9
9
|
getPending(): readonly SyncOp[];
|
|
10
|
+
countPending(): number;
|
|
10
11
|
markPushed(opIds: readonly string[]): void;
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -27,12 +28,27 @@ interface SyncClientConfig {
|
|
|
27
28
|
readonly serverUrl: string;
|
|
28
29
|
readonly apiKey: string;
|
|
29
30
|
readonly deviceId: string;
|
|
31
|
+
readonly userId: string;
|
|
30
32
|
}
|
|
31
33
|
interface SyncClientPushResponse {
|
|
32
34
|
readonly pushed: number;
|
|
33
35
|
readonly results: readonly SyncPushResult[];
|
|
34
36
|
readonly highWatermark: number;
|
|
35
37
|
}
|
|
38
|
+
interface SyncStatusTimestamps {
|
|
39
|
+
readonly attemptAt: string | null;
|
|
40
|
+
readonly successAt: string | null;
|
|
41
|
+
}
|
|
42
|
+
interface SyncClientStatus {
|
|
43
|
+
readonly enabled: true;
|
|
44
|
+
readonly serverUrl: string;
|
|
45
|
+
readonly userId: string;
|
|
46
|
+
readonly deviceId: string;
|
|
47
|
+
readonly pendingOps: number;
|
|
48
|
+
readonly lastPush: SyncStatusTimestamps;
|
|
49
|
+
readonly lastPull: SyncStatusTimestamps;
|
|
50
|
+
readonly cursor: number;
|
|
51
|
+
}
|
|
36
52
|
declare class SyncClient {
|
|
37
53
|
private readonly db;
|
|
38
54
|
private readonly config;
|
|
@@ -42,12 +58,15 @@ declare class SyncClient {
|
|
|
42
58
|
initialize(): void;
|
|
43
59
|
getOutbox(): Outbox;
|
|
44
60
|
getInbox(): Inbox;
|
|
61
|
+
getStatus(): SyncClientStatus;
|
|
45
62
|
push(): Promise<SyncClientPushResponse>;
|
|
46
63
|
pull(): Promise<number>;
|
|
47
64
|
getState(key: string): string | null;
|
|
48
65
|
setState(key: string, value: string): void;
|
|
66
|
+
private getCursor;
|
|
67
|
+
private setCursor;
|
|
49
68
|
}
|
|
50
69
|
|
|
51
70
|
declare function ensureSyncSchema(db: Database.Database): void;
|
|
52
71
|
|
|
53
|
-
export { Inbox, Outbox, SyncClient, ensureSyncSchema };
|
|
72
|
+
export { Inbox, Outbox, SyncClient, type SyncClientConfig, type SyncClientPushResponse, type SyncClientStatus, type SyncStatusTimestamps, ensureSyncSchema };
|
package/dist/index.js
CHANGED
|
@@ -56,6 +56,10 @@ var Outbox = class {
|
|
|
56
56
|
const rows = this.db.prepare("SELECT * FROM sync_outbox WHERE pushed_at IS NULL ORDER BY created_at ASC").all();
|
|
57
57
|
return rows.map(rowToSyncOp);
|
|
58
58
|
}
|
|
59
|
+
countPending() {
|
|
60
|
+
const row = this.db.prepare("SELECT COUNT(*) as count FROM sync_outbox WHERE pushed_at IS NULL").get();
|
|
61
|
+
return row.count;
|
|
62
|
+
}
|
|
59
63
|
markPushed(opIds) {
|
|
60
64
|
if (opIds.length === 0) return;
|
|
61
65
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -129,13 +133,33 @@ var SyncClient = class {
|
|
|
129
133
|
getInbox() {
|
|
130
134
|
return this.inbox;
|
|
131
135
|
}
|
|
136
|
+
getStatus() {
|
|
137
|
+
return {
|
|
138
|
+
enabled: true,
|
|
139
|
+
serverUrl: this.config.serverUrl,
|
|
140
|
+
userId: this.config.userId,
|
|
141
|
+
deviceId: this.config.deviceId,
|
|
142
|
+
pendingOps: this.outbox.countPending(),
|
|
143
|
+
lastPush: {
|
|
144
|
+
attemptAt: this.getState("last_push_attempt_at"),
|
|
145
|
+
successAt: this.getState("last_push_success_at")
|
|
146
|
+
},
|
|
147
|
+
lastPull: {
|
|
148
|
+
attemptAt: this.getState("last_pull_attempt_at"),
|
|
149
|
+
successAt: this.getState("last_pull_success_at")
|
|
150
|
+
},
|
|
151
|
+
cursor: this.getCursor()
|
|
152
|
+
};
|
|
153
|
+
}
|
|
132
154
|
async push() {
|
|
155
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
156
|
+
this.setState("last_push_attempt_at", now);
|
|
133
157
|
const pending = this.outbox.getPending();
|
|
134
158
|
if (pending.length === 0) {
|
|
159
|
+
this.setState("last_push_success_at", now);
|
|
135
160
|
return { pushed: 0, results: [], highWatermark: 0 };
|
|
136
161
|
}
|
|
137
|
-
const
|
|
138
|
-
const baseCursor = baseCursorStr ? parseInt(baseCursorStr, 10) : 0;
|
|
162
|
+
const baseCursor = this.getCursor();
|
|
139
163
|
const wireOps = pending.map((op) => ({
|
|
140
164
|
...op,
|
|
141
165
|
payload: typeof op.payload === "string" ? JSON.parse(op.payload) : op.payload
|
|
@@ -160,7 +184,8 @@ var SyncClient = class {
|
|
|
160
184
|
const { results, highWatermark } = body.data;
|
|
161
185
|
const pushedIds = results.filter((r) => r.status === "accepted" || r.status === "duplicate").map((r) => r.opId);
|
|
162
186
|
this.outbox.markPushed(pushedIds);
|
|
163
|
-
this.
|
|
187
|
+
this.setCursor(highWatermark);
|
|
188
|
+
this.setState("last_push_success_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
164
189
|
return {
|
|
165
190
|
pushed: pushedIds.length,
|
|
166
191
|
results,
|
|
@@ -168,10 +193,11 @@ var SyncClient = class {
|
|
|
168
193
|
};
|
|
169
194
|
}
|
|
170
195
|
async pull() {
|
|
171
|
-
|
|
172
|
-
const since =
|
|
196
|
+
this.setState("last_pull_attempt_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
197
|
+
const since = this.getCursor();
|
|
173
198
|
const params = new URLSearchParams({
|
|
174
|
-
since: String(since)
|
|
199
|
+
since: String(since),
|
|
200
|
+
userId: this.config.userId
|
|
175
201
|
});
|
|
176
202
|
const url = `${this.config.serverUrl}/sync/pull?${params.toString()}`;
|
|
177
203
|
const response = await fetch(url, {
|
|
@@ -188,7 +214,8 @@ var SyncClient = class {
|
|
|
188
214
|
if (ops.length > 0) {
|
|
189
215
|
this.inbox.addOps(ops);
|
|
190
216
|
}
|
|
191
|
-
this.
|
|
217
|
+
this.setCursor(nextCursor);
|
|
218
|
+
this.setState("last_pull_success_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
192
219
|
return ops.length;
|
|
193
220
|
}
|
|
194
221
|
getState(key) {
|
|
@@ -198,6 +225,15 @@ var SyncClient = class {
|
|
|
198
225
|
setState(key, value) {
|
|
199
226
|
this.db.prepare("INSERT OR REPLACE INTO sync_state (key, value) VALUES (?, ?)").run(key, value);
|
|
200
227
|
}
|
|
228
|
+
getCursor() {
|
|
229
|
+
const cursorStr = this.getState("last_cursor") ?? this.getState("pull_cursor");
|
|
230
|
+
return cursorStr ? parseInt(cursorStr, 10) : 0;
|
|
231
|
+
}
|
|
232
|
+
setCursor(cursor) {
|
|
233
|
+
const value = String(cursor);
|
|
234
|
+
this.setState("last_cursor", value);
|
|
235
|
+
this.setState("pull_cursor", value);
|
|
236
|
+
}
|
|
201
237
|
};
|
|
202
238
|
export {
|
|
203
239
|
Inbox,
|