@arcote.tech/arc 0.0.18 → 0.0.20

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.
@@ -14,7 +14,7 @@ export type Deserialize<Id extends ArcIdAny, Schema extends ArcObjectAny> = obje
14
14
  } & ReturnType<Schema["deserialize"]>>;
15
15
  type CollectionQueryBuilder<T extends ArcCollection<any, any, any>> = {
16
16
  all: () => ArcAllItemsQueryBuilder<T>;
17
- one: (id: util.GetType<T["id"]> | undefined) => ArcOneItemQueryBuilder<T>;
17
+ one: (id: util.GetType<T["id"]> | undefined | null) => ArcOneItemQueryBuilder<T>;
18
18
  };
19
19
  type CollectionCommandContext<Id extends ArcIdAny, Schema extends ArcObjectAny> = {
20
20
  one: (id: util.GetType<Id>) => Deserialize<Id, Schema>;
@@ -4,9 +4,9 @@ import type { ArcElement } from "./element";
4
4
  export declare class ArcOptional<E extends ArcElement> implements ArcElement {
5
5
  private parent;
6
6
  constructor(parent: E);
7
- parse(value: util.FirstArgument<E["parse"]> | undefined): ReturnType<E["parse"]> | undefined;
8
- serialize(value: util.FirstArgument<E["serialize"]> | undefined): ReturnType<E["serialize"]> | undefined;
9
- deserialize(value: util.FirstArgument<E["deserialize"]> | undefined): ReturnType<E["deserialize"]> | undefined;
7
+ parse(value: util.FirstArgument<E["parse"]> | null | undefined): ReturnType<E["parse"]> | null;
8
+ serialize(value: util.FirstArgument<E["serialize"]> | null | undefined): ReturnType<E["serialize"]> | null;
9
+ deserialize(value: util.FirstArgument<E["deserialize"]> | null | undefined): ReturnType<E["deserialize"]> | null;
10
10
  }
11
11
  export type ArcOptionalAny = ArcOptional<ArcAbstract>;
12
12
  //# sourceMappingURL=optional.d.ts.map
package/dist/index.js CHANGED
@@ -461,8 +461,10 @@ import { apply } from "mutative";
461
461
  function deepMerge(target, source) {
462
462
  const output = { ...target };
463
463
  for (const key in source) {
464
- if (source[key] === undefined)
464
+ if (source[key] === undefined) {
465
+ output[key] = undefined;
465
466
  continue;
467
+ }
466
468
  if (isObject(source[key]) && isObject(target[key])) {
467
469
  output[key] = deepMerge(target[key], source[key]);
468
470
  } else {
@@ -691,6 +693,7 @@ class ForkedDataStorage extends DataStorage {
691
693
  store: store.storeName,
692
694
  changes: store.changes
693
695
  }));
696
+ console.log(changes);
694
697
  await this.master.commitChanges(changes);
695
698
  }
696
699
  }
@@ -733,6 +736,7 @@ class MasterStoreState extends StoreState {
733
736
  if (change.type === "modify") {
734
737
  const existing = await transaction.findById(this.storeName, change.id);
735
738
  const updated = existing ? deepMerge(existing, change.data) : { _id: change.id, ...change.data };
739
+ console.log("updated", updated);
736
740
  await transaction.set(this.storeName, updated);
737
741
  const item = this.deserialize ? this.deserialize(updated) : updated;
738
742
  this.items.set(change.id, item);
@@ -890,17 +894,17 @@ class ArcOptional {
890
894
  }
891
895
  parse(value) {
892
896
  if (!value)
893
- return;
897
+ return null;
894
898
  return this.parent.parse(value);
895
899
  }
896
900
  serialize(value) {
897
901
  if (value)
898
902
  return this.parent.serialize(value);
899
- return;
903
+ return null;
900
904
  }
901
905
  deserialize(value) {
902
906
  if (!value)
903
- return;
907
+ return null;
904
908
  return this.parent.deserialize(value);
905
909
  }
906
910
  }
@@ -1210,9 +1214,7 @@ class RTCClient {
1210
1214
  reconnectAttempts = 0;
1211
1215
  maxReconnectAttempts = 5;
1212
1216
  syncProgressCallback;
1213
- syncResolve;
1214
1217
  syncPromise = null;
1215
- pendingStoreChanges = [];
1216
1218
  constructor(storage) {
1217
1219
  this.storage = storage;
1218
1220
  }
@@ -1220,13 +1222,54 @@ class RTCClient {
1220
1222
  if (this.syncPromise)
1221
1223
  return this.syncPromise;
1222
1224
  this.syncProgressCallback = progressCallback;
1223
- this.syncPromise = new Promise((resolve) => {
1224
- this.syncResolve = resolve;
1225
- this.connect();
1226
- });
1225
+ this.syncPromise = this.performSync();
1227
1226
  return this.syncPromise;
1228
1227
  }
1229
- async connect() {
1228
+ async performSync() {
1229
+ this.connectWebSocket();
1230
+ const arcState = await this.storage.getStore("state").findById("$arc", (a) => a);
1231
+ const response = await fetch(`/ws/sync?lastSync=${arcState?.lastSyncDate || ""}`, {
1232
+ method: "GET",
1233
+ headers: {
1234
+ "Content-Type": "application/json"
1235
+ }
1236
+ });
1237
+ if (!response.ok) {
1238
+ throw new Error("Sync failed");
1239
+ }
1240
+ const { results, syncDate } = await response.json();
1241
+ const pendingStoreChanges = [];
1242
+ for (const { store, items } of results) {
1243
+ this.syncProgressCallback?.({ store, size: items.length });
1244
+ const storeState = this.storage.getStore(store);
1245
+ if (!storeState) {
1246
+ console.error(`Store ${store} not found`);
1247
+ continue;
1248
+ }
1249
+ const changes = items.map((item) => {
1250
+ if (item.deleted) {
1251
+ return {
1252
+ type: "delete",
1253
+ id: item._id
1254
+ };
1255
+ }
1256
+ return {
1257
+ type: "set",
1258
+ data: item
1259
+ };
1260
+ });
1261
+ pendingStoreChanges.push(storeState.applyChanges(changes));
1262
+ }
1263
+ await Promise.all(pendingStoreChanges);
1264
+ const stateStorage = this.storage.getStore("state");
1265
+ await stateStorage.applyChanges([
1266
+ {
1267
+ type: "set",
1268
+ data: { _id: "$arc", lastSyncDate: syncDate }
1269
+ }
1270
+ ]);
1271
+ }
1272
+ async connectWebSocket() {
1230
1273
  this._socket = new WebSocket(`wss://${window.location.host}/ws`);
1231
1274
  this.openSocket = new Promise((resolve) => {
1232
1275
  this._socket.addEventListener("open", () => {
@@ -1234,7 +1277,6 @@ class RTCClient {
1234
1277
  resolve(this._socket);
1235
1278
  });
1236
1279
  });
1237
- const arcState = await this.storage.getStore("state").findById("$arc", (a) => a);
1238
1280
  this._socket.addEventListener("message", (e) => {
1239
1281
  this.onMessage(JSON.parse(e.data));
1240
1282
  });
@@ -1243,17 +1285,13 @@ class RTCClient {
1243
1285
  console.error("WebSocket closed", e);
1244
1286
  this.reconnect();
1245
1287
  });
1246
- this.sendMessage({
1247
- type: "sync",
1248
- lastDate: arcState?.lastSyncDate || null
1249
- });
1250
1288
  }
1251
1289
  reconnect() {
1252
1290
  if (this.reconnectAttempts < this.maxReconnectAttempts) {
1253
1291
  const timeout = Math.pow(2, this.reconnectAttempts) * 1000;
1254
1292
  setTimeout(() => {
1255
1293
  this.reconnectAttempts++;
1256
- this.connect();
1294
+ this.connectWebSocket();
1257
1295
  }, timeout);
1258
1296
  } else {
1259
1297
  console.error("Max reconnect attempts reached. Giving up.");
@@ -1267,44 +1305,6 @@ class RTCClient {
1267
1305
  }
1268
1306
  onMessage(message) {
1269
1307
  switch (message.type) {
1270
- case "sync-result":
1271
- {
1272
- const { store, items } = message;
1273
- this.syncProgressCallback?.({ store, size: items.length });
1274
- const storeState = this.storage.getStore(store);
1275
- if (!storeState) {
1276
- console.error(`Store ${store} not found`);
1277
- return;
1278
- }
1279
- const changes = items.map((item) => {
1280
- if (item.deleted) {
1281
- return {
1282
- type: "delete",
1283
- id: item._id
1284
- };
1285
- }
1286
- return {
1287
- type: "set",
1288
- data: item
1289
- };
1290
- });
1291
- this.pendingStoreChanges.push(storeState.applyChanges(changes));
1292
- }
1293
- break;
1294
- case "sync-done":
1295
- Promise.all(this.pendingStoreChanges).then(() => {
1296
- const stateStorage = this.storage.getStore("state");
1297
- stateStorage.applyChanges([
1298
- {
1299
- type: "set",
1300
- data: { _id: "$arc", lastSyncDate: message.date }
1301
- }
1302
- ]).then(() => {
1303
- this.pendingStoreChanges = [];
1304
- this.syncResolve?.();
1305
- });
1306
- });
1307
- break;
1308
1308
  case "state-changes":
1309
1309
  this.storage.applyChanges(message.changes);
1310
1310
  break;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
7
- "version": "0.0.18",
7
+ "version": "0.0.20",
8
8
  "private": false,
9
9
  "author": "Przemysław Krasiński [arcote.tech]",
10
10
  "description": "Arc is a framework designed to align code closely with business logic, streamlining development and enhancing productivity.",