@evolu/common 7.2.2 → 7.2.3
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/src/Object.d.ts +16 -1
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +16 -1
- package/dist/src/Order.d.ts +2 -1
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +1 -0
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +5 -11
- package/dist/src/local-first/Diff.js +2 -2
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +8 -5
- package/dist/src/local-first/Protocol.d.ts +1 -1
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +2 -2
- package/dist/src/local-first/Sync.d.ts +2 -4
- package/dist/src/local-first/Sync.d.ts.map +1 -1
- package/dist/src/local-first/Sync.js +87 -109
- package/dist/src/local-first/Timestamp.d.ts +13 -0
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +14 -1
- package/package.json +1 -1
- package/src/Object.ts +20 -1
- package/src/Order.ts +2 -1
- package/src/local-first/Db.ts +5 -12
- package/src/local-first/Diff.ts +2 -2
- package/src/local-first/Evolu.ts +12 -4
- package/src/local-first/Protocol.ts +3 -3
- package/src/local-first/Sync.ts +92 -136
- package/src/local-first/Timestamp.ts +14 -1
package/dist/src/Object.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ type StringKeyOf<T> = Extract<keyof T, string>;
|
|
|
24
24
|
*
|
|
25
25
|
* ```ts
|
|
26
26
|
* type UserId = string & { readonly __brand: "UserId" };
|
|
27
|
-
* const users
|
|
27
|
+
* const users = createRecord<UserId, string>();
|
|
28
28
|
* const entries = objectToEntries(users); // [UserId, string][]
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
@@ -37,5 +37,20 @@ export declare const objectToEntries: <T extends Record<string, any>>(record: T)
|
|
|
37
37
|
export declare const mapObject: <K extends string, V, U>(record: ReadonlyRecord<K, V>, fn: (value: V, key: K) => U) => ReadonlyRecord<K, U>;
|
|
38
38
|
/** Conditionally excludes a property from an object. */
|
|
39
39
|
export declare const excludeProp: <T extends object, K extends keyof T>(obj: T, prop: K, condition?: boolean) => typeof condition extends true ? T : Omit<T, K>;
|
|
40
|
+
/**
|
|
41
|
+
* Creates a prototype-less object typed as `Record<K, V>`.
|
|
42
|
+
*
|
|
43
|
+
* Use this function when you need a plain record without a prototype chain
|
|
44
|
+
* (e.g. when keys are controlled by external sources) to avoid prototype
|
|
45
|
+
* pollution and accidental collisions with properties like `__proto__`.
|
|
46
|
+
*
|
|
47
|
+
* Example:
|
|
48
|
+
*
|
|
49
|
+
* ```ts
|
|
50
|
+
* const values = createRecord<string, SqliteValue>();
|
|
51
|
+
* values["__proto__"] = someValue; // safe, no prototype pollution
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare const createRecord: <K extends string = string, V = unknown>() => Record<K, V>;
|
|
40
55
|
export {};
|
|
41
56
|
//# sourceMappingURL=Object.d.ts.map
|
package/dist/src/Object.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Object.d.ts","sourceRoot":"","sources":["../../src/Object.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,OAAO,KACb,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAC2B,CAAC;AAE9D;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAG5E,KAAK,WAAW,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3D,QAAQ,CAAC,KACR,aAAa,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAGK,CAAC;AAE1D;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,EAC9C,QAAQ,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5B,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAC1B,cAAc,CAAC,CAAC,EAAE,CAAC,CAMK,CAAC;AAE5B,wDAAwD;AACxD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAC7D,KAAK,CAAC,EACN,MAAM,CAAC,EACP,YAAY,OAAO,KAClB,OAAO,SAAS,SAAS,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAM/C,CAAC"}
|
|
1
|
+
{"version":3,"file":"Object.d.ts","sourceRoot":"","sources":["../../src/Object.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,OAAO,KACb,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAC2B,CAAC;AAE9D;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAG5E,KAAK,WAAW,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3D,QAAQ,CAAC,KACR,aAAa,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAGK,CAAC;AAE1D;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,EAC9C,QAAQ,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5B,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAC1B,cAAc,CAAC,CAAC,EAAE,CAAC,CAMK,CAAC;AAE5B,wDAAwD;AACxD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAC7D,KAAK,CAAC,EACN,MAAM,CAAC,EACP,YAAY,OAAO,KAClB,OAAO,SAAS,SAAS,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAM/C,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,OAAO,OAAK,MAAM,CAC5E,CAAC,EACD,CAAC,CACqC,CAAC"}
|
package/dist/src/Object.js
CHANGED
|
@@ -18,7 +18,7 @@ export const isPlainObject = (value) => Object.prototype.toString.call(value) ==
|
|
|
18
18
|
*
|
|
19
19
|
* ```ts
|
|
20
20
|
* type UserId = string & { readonly __brand: "UserId" };
|
|
21
|
-
* const users
|
|
21
|
+
* const users = createRecord<UserId, string>();
|
|
22
22
|
* const entries = objectToEntries(users); // [UserId, string][]
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
@@ -40,3 +40,18 @@ export const excludeProp = (obj, prop, condition) => {
|
|
|
40
40
|
const { [prop]: _, ...rest } = obj;
|
|
41
41
|
return rest;
|
|
42
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Creates a prototype-less object typed as `Record<K, V>`.
|
|
45
|
+
*
|
|
46
|
+
* Use this function when you need a plain record without a prototype chain
|
|
47
|
+
* (e.g. when keys are controlled by external sources) to avoid prototype
|
|
48
|
+
* pollution and accidental collisions with properties like `__proto__`.
|
|
49
|
+
*
|
|
50
|
+
* Example:
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* const values = createRecord<string, SqliteValue>();
|
|
54
|
+
* values["__proto__"] = someValue; // safe, no prototype pollution
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export const createRecord = () => Object.create(null);
|
package/dist/src/Order.d.ts
CHANGED
|
@@ -81,5 +81,6 @@ export declare const orderNumber: Order<number>;
|
|
|
81
81
|
* ```
|
|
82
82
|
*/
|
|
83
83
|
export declare const orderBigInt: Order<bigint>;
|
|
84
|
-
|
|
84
|
+
/** An {@link Order} for Uint8Array. */
|
|
85
|
+
export declare const orderUint8Array: Order<Uint8Array>;
|
|
85
86
|
//# sourceMappingURL=Order.d.ts.map
|
package/dist/src/Order.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Order.d.ts","sourceRoot":"","sources":["../../src/Order.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC;AAEnD;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,GACrB,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,KAAG,KAAK,CAAC,CAAC,CAER,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GACtB,CAAC,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAG,KAAK,CAAC,CAAC,CAEhB,CAAC;AAEhB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,MAAM,CAAgC,CAAC;AAEvE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,eAAuC,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,eAAuC,CAAC;AAEhE,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,UAAU,
|
|
1
|
+
{"version":3,"file":"Order.d.ts","sourceRoot":"","sources":["../../src/Order.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC;AAEnD;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,GACrB,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,KAAG,KAAK,CAAC,CAAC,CAER,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GACtB,CAAC,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAG,KAAK,CAAC,CAAC,CAEhB,CAAC;AAEhB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,MAAM,CAAgC,CAAC;AAEvE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,eAAuC,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,eAAuC,CAAC;AAEhE,uCAAuC;AACvC,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,UAAU,CAU7C,CAAC"}
|
package/dist/src/Order.js
CHANGED
|
@@ -65,6 +65,7 @@ export const orderNumber = createOrder((a, b) => a < b);
|
|
|
65
65
|
* ```
|
|
66
66
|
*/
|
|
67
67
|
export const orderBigInt = createOrder((a, b) => a < b);
|
|
68
|
+
/** An {@link Order} for Uint8Array. */
|
|
68
69
|
export const orderUint8Array = (a, b) => {
|
|
69
70
|
if (a.byteLength > b.byteLength)
|
|
70
71
|
return 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/local-first/Db.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../../src/local-first/Db.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,8 +18,11 @@ export const defaultDbConfig = {
|
|
|
18
18
|
maxDrift: 5 * 60 * 1000,
|
|
19
19
|
enableLogging: false,
|
|
20
20
|
};
|
|
21
|
-
export const createDbWorkerForPlatform = (platformDeps) => createInitializedWorkerWithHandlers({
|
|
22
|
-
|
|
21
|
+
export const createDbWorkerForPlatform = (platformDeps) => createInitializedWorkerWithHandlers({
|
|
22
|
+
init: createInit(platformDeps),
|
|
23
|
+
handlers,
|
|
24
|
+
});
|
|
25
|
+
const createInit = (platformDeps) => async (initMessage, postMessage) => {
|
|
23
26
|
platformDeps.console.enabled = initMessage.config.enableLogging ?? false;
|
|
24
27
|
const sqliteResult = await createSqlite(platformDeps)(initMessage.config.name, {
|
|
25
28
|
memory: initMessage.config.inMemory ?? false,
|
|
@@ -41,15 +44,6 @@ const createDbWorkerDeps = (platformDeps) => async (initMessage, postMessage) =>
|
|
|
41
44
|
const currentVersion = sqlite.exec(sql `select protocolVersion from evolu_version limit 1;`);
|
|
42
45
|
if (!currentVersion.ok)
|
|
43
46
|
return currentVersion;
|
|
44
|
-
// TODO: Handle version migrations here if needed
|
|
45
|
-
// const [{ protocolVersion }] = protocolVersionResult.value.rows;
|
|
46
|
-
// if (protocolVersion < currentProtocolVersion) {
|
|
47
|
-
// const migrateResult = migrateDatabase({ sqlite })(
|
|
48
|
-
// protocolVersion,
|
|
49
|
-
// currentProtocolVersion
|
|
50
|
-
// );
|
|
51
|
-
// if (!migrateResult.ok) return migrateResult;
|
|
52
|
-
// }
|
|
53
47
|
const configResult = sqlite.exec(sql `
|
|
54
48
|
select
|
|
55
49
|
clock,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRandomBytes } from "../Crypto.js";
|
|
2
|
-
import { isPlainObject } from "../Object.js";
|
|
2
|
+
import { createRecord, isPlainObject } from "../Object.js";
|
|
3
3
|
import { orderUint8Array } from "../Order.js";
|
|
4
4
|
import { createId, String } from "../Type.js";
|
|
5
5
|
export const applyPatches = (patches, current) => patches.reduce((next, patch) => {
|
|
@@ -89,7 +89,7 @@ const parse = (obj) => {
|
|
|
89
89
|
return obj;
|
|
90
90
|
};
|
|
91
91
|
const parseObject = (obj) => {
|
|
92
|
-
const result =
|
|
92
|
+
const result = createRecord();
|
|
93
93
|
for (const key in obj) {
|
|
94
94
|
result[key] = parse(obj[key]);
|
|
95
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Evolu.d.ts","sourceRoot":"","sources":["../../../src/local-first/Evolu.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIhD,OAAO,
|
|
1
|
+
{"version":3,"file":"Evolu.d.ts","sourceRoot":"","sources":["../../../src/local-first/Evolu.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { pack } from "msgpackr";
|
|
2
2
|
import { dedupeArray, isNonEmptyArray, isNonEmptyReadonlyArray, } from "../Array.js";
|
|
3
|
-
import { assertNonEmptyReadonlyArray } from "../Assert.js";
|
|
3
|
+
import { assert, assertNonEmptyReadonlyArray } from "../Assert.js";
|
|
4
4
|
import { createCallbacks } from "../Callbacks.js";
|
|
5
5
|
import { eqArrayNumber } from "../Eq.js";
|
|
6
6
|
import { exhaustiveCheck } from "../Function.js";
|
|
7
7
|
import { createInstances } from "../Instances.js";
|
|
8
8
|
import { err, ok } from "../Result.js";
|
|
9
|
-
import { isSqlMutation, SqliteBoolean, } from "../Sqlite.js";
|
|
9
|
+
import { isSqlMutation, SqliteBoolean, sqliteBooleanToBoolean, } from "../Sqlite.js";
|
|
10
10
|
import { createStore } from "../Store.js";
|
|
11
11
|
import { createId, } from "../Type.js";
|
|
12
12
|
import { defaultDbConfig } from "./Db.js";
|
|
@@ -193,13 +193,16 @@ const createEvoluInstance = (deps) => (schema, config) => {
|
|
|
193
193
|
}
|
|
194
194
|
else {
|
|
195
195
|
const { id: _, isDeleted, ...values } = result.value;
|
|
196
|
-
const dbChange =
|
|
196
|
+
const dbChange = {
|
|
197
197
|
table,
|
|
198
198
|
id,
|
|
199
199
|
values,
|
|
200
200
|
isInsert: kind === "insert" || kind === "upsert",
|
|
201
|
-
isDelete: SqliteBoolean.is(isDeleted)
|
|
202
|
-
|
|
201
|
+
isDelete: SqliteBoolean.is(isDeleted)
|
|
202
|
+
? sqliteBooleanToBoolean(isDeleted)
|
|
203
|
+
: null,
|
|
204
|
+
};
|
|
205
|
+
assert(DbChange.is(dbChange), `Invalid DbChange for table '${table}': Please check schema type errors.`);
|
|
203
206
|
mutateMicrotaskQueue.push([
|
|
204
207
|
{ ...dbChange, ownerId: options?.ownerId },
|
|
205
208
|
options?.onComplete,
|
|
@@ -166,7 +166,7 @@ import { EncryptionKey, RandomBytesDep, SymmetricCryptoDecryptError, SymmetricCr
|
|
|
166
166
|
import { Result } from "../Result.js";
|
|
167
167
|
import { SqliteValue } from "../Sqlite.js";
|
|
168
168
|
import { NonNegativeInt, PositiveInt } from "../Type.js";
|
|
169
|
-
import {
|
|
169
|
+
import { Owner, OwnerError, OwnerId, OwnerWriteKey } from "./Owner.js";
|
|
170
170
|
import { BaseRange, CrdtMessage, DbChange, EncryptedCrdtMessage, EncryptedDbChange, FingerprintRange, RangeType, SkipRange, StorageDep } from "./Storage.js";
|
|
171
171
|
import { NodeId, Timestamp } from "./Timestamp.js";
|
|
172
172
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Protocol.d.ts","sourceRoot":"","sources":["../../../src/local-first/Protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgKG;AAoBH,OAAO,EAA2B,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EACL,MAAM,EAMP,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,aAAa,EACb,cAAc,EACd,2BAA2B,EAC3B,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAItB,OAAO,EAAW,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAaL,cAAc,EAEd,WAAW,EAEZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,
|
|
1
|
+
{"version":3,"file":"Protocol.d.ts","sourceRoot":"","sources":["../../../src/local-first/Protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgKG;AAoBH,OAAO,EAA2B,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EACL,MAAM,EAMP,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,aAAa,EACb,cAAc,EACd,2BAA2B,EAC3B,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAItB,OAAO,EAAW,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAaL,cAAc,EAEd,WAAW,EAEZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,KAAK,EACL,UAAU,EACV,OAAO,EAGP,aAAa,EAEd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,SAAS,EACT,WAAW,EACX,QAAQ,EACR,oBAAoB,EACpB,iBAAiB,EAEjB,gBAAgB,EAIhB,SAAS,EAET,SAAS,EACT,UAAU,EAEX,MAAM,cAAc,CAAC;AACtB,OAAO,EAIL,MAAM,EACN,SAAS,EAKV,MAAM,gBAAgB,CAAC;AAaxB;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,iUAG7B,CAAC;AAEP,MAAM,MAAM,sBAAsB,GAAG,OAAO,sBAAsB,CAAC,IAAI,CAAC;AAExE;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,EACX,sBAAsB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,qTAA+B,CAAC;AACzE,MAAM,MAAM,4BAA4B,GACtC,OAAO,4BAA4B,CAAC,IAAI,CAAC;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,EACpC,4BAA4B,CAAC;AAEzC,8BAA8B;AAC9B,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAAC;AAEpE,8BAA8B;AAC9B,eAAO,MAAM,eAAe,8CAA4B,CAAC;AAEzD,eAAO,MAAM,WAAW;IACtB,wEAAwE;;IAExE,yEAAyE;;IAEzE,0EAA0E;;CAElE,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEzE,eAAO,MAAM,iBAAiB;IAC5B,8CAA8C;;IAE9C,2CAA2C;;IAE3C,+CAA+C;;CAEvC,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAC1B,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAE7D,eAAO,MAAM,iBAAiB;;IAE5B,gDAAgD;;IAEhD,6CAA6C;;IAE7C,6CAA6C;;IAE7C,4CAA4C;;CAEpC,CAAC;AAEX,KAAK,iBAAiB,GACpB,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAE7D,MAAM,MAAM,aAAa,GACrB,oBAAoB,GACpB,wBAAwB,GACxB,qBAAqB,GACrB,kBAAkB,GAClB,iBAAiB,GACjB,kBAAkB,GAClB,8BAA8B,CAAC;AAEnC;;;GAGG;AACH,MAAM,WAAW,oBAAqB,SAAQ,UAAU;IACtD,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,4DAA4D;AAC5D,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,mFAAmF;AACnF,MAAM,WAAW,qBAAsB,SAAQ,UAAU;IACvD,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;CACrC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,IAAI,EAAE,gCAAgC,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qCAAqC,GAC/C,MAAM,cAAc,GAAG,kBAAkB,MAExC,OAAO,KAAK,EACZ,UAAU,qBAAqB,CAAC,WAAW,CAAC,EAC5C,UAAU,sBAAsB,KAC/B,eAoDF,CAAC;AAEJ,kDAAkD;AAClD,eAAO,MAAM,4BAA4B,GACtC,MAAM,UAAU,MAEf,SAAS,OAAO,EAChB,mBAAmB,gBAAgB,KAClC,eAAe,GAAG,IAoBpB,CAAC;AAEJ,eAAO,MAAM,mCAAmC,GAC9C,SAAS,OAAO,KACf,eAIU,CAAC;AAEd;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC;IAEnE,QAAQ,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAE7D,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC;IAEtC,QAAQ,CAAC,+BAA+B,EAAE,CACxC,UAAU,EAAE,gBAAgB,EAC5B,OAAO,EAAE,oBAAoB,GAAG,IAAI,KACjC,OAAO,CAAC;IAEb,QAAQ,CAAC,QAAQ,EAAE,CACjB,KAAK,EAAE,SAAS,GAAG,gBAAgB,GAAG,mCAAmC,KACtE,IAAI,CAAC;IAEV,QAAQ,CAAC,MAAM,EAAE,MAAM,eAAe,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,WAAW,CAAC;CACrC;AAED,eAAO,MAAM,2BAA2B,GACtC,SAAS,OAAO,EAChB,SAAS;IACP,QAAQ,CAAC,YAAY,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IAC3D,QAAQ,CAAC,aAAa,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC;CACnC,GAAG,CACA;IACE,QAAQ,CAAC,WAAW,EAAE,OAAO,WAAW,CAAC,OAAO,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CAC9C,GACD;IACE,QAAQ,CAAC,WAAW,EAAE,OAAO,WAAW,CAAC,QAAQ,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;CACvC,GACD;IACE,QAAQ,CAAC,WAAW,EAAE,OAAO,WAAW,CAAC,SAAS,CAAC;CACpD,CACJ,KACA,qBAsLF,CAAC;AAEF,MAAM,WAAW,mCAAoC,SAAQ,SAAS;IACpE,QAAQ,CAAC,IAAI,EAAE,OAAO,SAAS,CAAC,UAAU,CAAC;IAC3C,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,cAAc,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED,eAAO,MAAM,sBAAsB,QAAO,gBAwDzC,CAAC;AAoCF,MAAM,WAAW,mCAAmC;IAClD,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,aAAa,GAAG,IAAI,CAAC;IAEzD,aAAa,CAAC,EAAE,4BAA4B,CAAC;IAE7C,sBAAsB;IACtB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,MAAM,kCAAkC,GAC1C;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GAChE;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAEnC,eAAO,MAAM,4BAA4B,GACtC,MAAM,UAAU,MAEf,cAAc,UAAU,EACxB,UAAS,mCAAwC,KAChD,OAAO,CACR,MAAM,CACJ,kCAAkC,EAChC,wBAAwB,GACxB,iBAAiB,GACjB,oBAAoB,GACpB,kBAAkB,GAClB,qBAAqB,GACrB,kBAAkB,CACrB,CA4GF,CAAC;AAEJ,MAAM,WAAW,kCAAkC;IACjD,8CAA8C;IAC9C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAEvC,iDAAiD;IACjD,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC,0DAA0D;IAC1D,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAEjE,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,aAAa,CAAC,EAAE,4BAA4B,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;CACnC;AAED,eAAO,MAAM,2BAA2B,GACrC,MAAM,UAAU,MAEf,cAAc,UAAU,EACxB,UAAS,kCAAuC;AAChD,sBAAsB;AACtB,sDAAyB,KACxB,OAAO,CACR,MAAM,CAAC,iCAAiC,EAAE,wBAAwB,CAAC,CAoJpE,CAAC;AA4aJ;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,QAAQ,MAAM,KAAG,IAE7D,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,KAAG,MAqB7C,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,EACd,OAAO,aAAa,CAAC,OAAO,CAAC,KAC5B,IAQF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,EACd,OAAO,WAAW,KACjB,aAAa,CAAC,OAAO,CAOvB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,GAClC,MAAM,kBAAkB,MACxB,SAAS,WAAW,EAAE,KAAK,aAAa,KAAG,iBAwC3C,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAClC,MAAM,kBAAkB,MAEvB,SAAS,oBAAoB,EAC7B,KAAK,aAAa,KACjB,MAAM,CACP,QAAQ,EACN,2BAA2B,GAC3B,wBAAwB,GACxB,8BAA8B,CA8DjC,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,MAAM,EACd,KAAK,cAAc,KAClB,IAoBF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,KAAG,cAiBrD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,OAAO,SAAS,CAAC,GAAG,CAAC,KAAG,IAEpE,CAAC;AAEF,eAAO,MAAM,YAAY,WAvBoB,MAAM,KAAG,cAuBN,CAAC;AAEjD,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,OAAO,MAAM,KAAG,IAI5D,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,KAAG,MAI7C,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,QAAQ,MAAM,KAAG,IAE7D,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,KAAG,MAG7C,CAAC;AAMF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;CA2BpB,CAAC;AAEX,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,EAAE,OAAO,WAAW,KAAG,IAoFtE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,KAAG,WAyDlD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,GACtC,kBAAkB,eAAe,EACjC,cAAc,OAAO,KACpB,OAOF,CAAC"}
|
|
@@ -182,7 +182,7 @@ import { bytesToHex, bytesToUtf8, createBuffer, hexToBytes, utf8ToBytes, } from
|
|
|
182
182
|
import { createPadmePadding, } from "../Crypto.js";
|
|
183
183
|
import { eqArrayNumber } from "../Eq.js";
|
|
184
184
|
import { computeBalancedBuckets } from "../Number.js";
|
|
185
|
-
import { objectToEntries } from "../Object.js";
|
|
185
|
+
import { createRecord, objectToEntries } from "../Object.js";
|
|
186
186
|
import { err, ok } from "../Result.js";
|
|
187
187
|
import { Base64Url, base64UrlToUint8Array, between, DateIso, Id, idBytesToId, idBytesTypeValueLength, idToIdBytes, Int, Json, jsonToJsonValue, NonNegativeInt, Number, PositiveInt, uint8ArrayToBase64Url, } from "../Type.js";
|
|
188
188
|
import { ownerIdToOwnerIdBytes, ownerWriteKeyLength, } from "./Owner.js";
|
|
@@ -1195,7 +1195,7 @@ export const decryptAndDecodeDbChange = (deps) => (message, key) => {
|
|
|
1195
1195
|
const table = decodeString(buffer);
|
|
1196
1196
|
const id = decodeId(buffer);
|
|
1197
1197
|
const length = decodeLength(buffer);
|
|
1198
|
-
const values =
|
|
1198
|
+
const values = createRecord();
|
|
1199
1199
|
for (let i = 0; i < length; i++) {
|
|
1200
1200
|
const column = decodeString(buffer);
|
|
1201
1201
|
const value = decodeSqliteValue(buffer);
|
|
@@ -6,13 +6,12 @@ import { RandomDep } from "../Random.js";
|
|
|
6
6
|
import { Result } from "../Result.js";
|
|
7
7
|
import { SqliteDep, SqliteError } from "../Sqlite.js";
|
|
8
8
|
import { TimeDep } from "../Time.js";
|
|
9
|
-
import { DateIso } from "../Type.js";
|
|
10
9
|
import { CreateWebSocketDep } from "../WebSocket.js";
|
|
11
10
|
import type { AppOwnerDep, PostMessageDep } from "./Db.js";
|
|
12
|
-
import { AppOwner, Owner,
|
|
11
|
+
import { AppOwner, Owner, OwnerTransport, ReadonlyOwner } from "./Owner.js";
|
|
13
12
|
import { ProtocolError, ProtocolInvalidDataError, ProtocolTimestampMismatchError } from "./Protocol.js";
|
|
14
13
|
import { MutationChange } from "./Schema.js";
|
|
15
|
-
import { BaseSqliteStorage,
|
|
14
|
+
import { BaseSqliteStorage, Storage } from "./Storage.js";
|
|
16
15
|
import { Millis, Timestamp, TimestampConfigDep, TimestampCounterOverflowError, TimestampDriftError, TimestampTimeOutOfRangeError } from "./Timestamp.js";
|
|
17
16
|
export interface Sync extends Disposable {
|
|
18
17
|
/**
|
|
@@ -64,7 +63,6 @@ export interface ClientStorageDep {
|
|
|
64
63
|
readonly storage: ClientStorage;
|
|
65
64
|
}
|
|
66
65
|
export declare const applyLocalOnlyChange: (deps: SqliteDep & TimeDep & AppOwnerDep) => (change: MutationChange) => Result<void, SqliteError>;
|
|
67
|
-
export declare const applyMessageToTimestampAndHistoryTables: (deps: ClientStorageDep & SqliteDep) => (ownerId: OwnerIdBytes, message: CrdtMessage, strategy: StorageInsertTimestampStrategy, date: DateIso) => Result<void, SqliteError>;
|
|
68
66
|
/**
|
|
69
67
|
* TODO: Rework for the new owners API.
|
|
70
68
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sync.d.ts","sourceRoot":"","sources":["../../../src/local-first/Sync.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Sync.d.ts","sourceRoot":"","sources":["../../../src/local-first/Sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { firstInArray, isNonEmptyReadonlyArray, } from "../Array.js";
|
|
2
|
-
import { assert } from "../Assert.js";
|
|
1
|
+
import { appendToArray, firstInArray, isNonEmptyReadonlyArray, } from "../Array.js";
|
|
2
|
+
import { assert, assertNonEmptyReadonlyArray } from "../Assert.js";
|
|
3
3
|
import { eqArrayNumber } from "../Eq.js";
|
|
4
4
|
import { createTransferableError } from "../Error.js";
|
|
5
5
|
import { constFalse, constTrue } from "../Function.js";
|
|
6
|
-
import { objectToEntries } from "../Object.js";
|
|
6
|
+
import { createRecord, objectToEntries } from "../Object.js";
|
|
7
7
|
import { createResources } from "../Resources.js";
|
|
8
8
|
import { err, ok } from "../Result.js";
|
|
9
|
-
import { booleanToSqliteBoolean, sql, SqliteBoolean, sqliteBooleanToBoolean,
|
|
9
|
+
import { booleanToSqliteBoolean, sql, SqliteBoolean, sqliteBooleanToBoolean, } from "../Sqlite.js";
|
|
10
10
|
import { createMutex } from "../Task.js";
|
|
11
|
-
import { idBytesToId, idToIdBytes, } from "../Type.js";
|
|
11
|
+
import { Boolean, idBytesToId, idToIdBytes, } from "../Type.js";
|
|
12
12
|
import { ownerIdBytesToOwnerId, ownerIdToOwnerIdBytes, } from "./Owner.js";
|
|
13
13
|
import { applyProtocolMessageAsClient, createProtocolMessageForSync, createProtocolMessageForUnsubscribe, createProtocolMessageFromCrdtMessages, decryptAndDecodeDbChange, encodeAndEncryptDbChange, SubscriptionFlags, } from "./Protocol.js";
|
|
14
14
|
import { createBaseSqliteStorage, DbChange, getOwnerUsage, getTimestampInsertStrategy, updateOwnerUsage, } from "./Storage.js";
|
|
@@ -271,11 +271,6 @@ const createClientStorage = (deps) => (config) => {
|
|
|
271
271
|
if (!applyMessagesResult.ok)
|
|
272
272
|
return applyMessagesResult;
|
|
273
273
|
}
|
|
274
|
-
// // Apply local mutations atomically with approved messages
|
|
275
|
-
// for (const change of localMutations) {
|
|
276
|
-
// const result = applyLocalOnlyChange(deps)(change);
|
|
277
|
-
// if (!result.ok) return result;
|
|
278
|
-
// }
|
|
279
274
|
return deps.clock.save(clockTimestamp);
|
|
280
275
|
});
|
|
281
276
|
if (!transaction.ok)
|
|
@@ -306,10 +301,10 @@ const createClientStorage = (deps) => (config) => {
|
|
|
306
301
|
return null;
|
|
307
302
|
}
|
|
308
303
|
const { rows } = result.value;
|
|
309
|
-
|
|
310
|
-
const { table, id } = rows
|
|
311
|
-
const values =
|
|
312
|
-
let isInsert
|
|
304
|
+
assertNonEmptyReadonlyArray(rows, "Every timestamp must have rows");
|
|
305
|
+
const { table, id } = firstInArray(rows);
|
|
306
|
+
const values = createRecord();
|
|
307
|
+
let isInsert;
|
|
313
308
|
let isDelete = null;
|
|
314
309
|
for (const r of rows) {
|
|
315
310
|
assert(r.table === table, "All rows must have the same table");
|
|
@@ -318,14 +313,18 @@ const createClientStorage = (deps) => (config) => {
|
|
|
318
313
|
case "createdAt":
|
|
319
314
|
isInsert = true;
|
|
320
315
|
break;
|
|
316
|
+
case "updatedAt":
|
|
317
|
+
isInsert = false;
|
|
318
|
+
break;
|
|
321
319
|
case "isDeleted":
|
|
322
|
-
assert(SqliteBoolean.is(r.value), "isDeleted column must contain a valid SqliteBoolean
|
|
320
|
+
assert(SqliteBoolean.is(r.value), "isDeleted column must contain a valid SqliteBoolean");
|
|
323
321
|
isDelete = sqliteBooleanToBoolean(r.value);
|
|
324
322
|
break;
|
|
325
323
|
default:
|
|
326
324
|
values[r.column] = r.value;
|
|
327
325
|
}
|
|
328
326
|
}
|
|
327
|
+
assert(Boolean.is(isInsert), "isInsert must be in evolu_history");
|
|
329
328
|
const message = {
|
|
330
329
|
timestamp: timestampBytesToTimestamp(timestamp),
|
|
331
330
|
change: DbChange.orThrow({
|
|
@@ -345,6 +344,21 @@ const createClientStorage = (deps) => (config) => {
|
|
|
345
344
|
const createTransportKey = (transport) => {
|
|
346
345
|
return `${transport.type}:${transport.url}`;
|
|
347
346
|
};
|
|
347
|
+
const dbChangeToColumns = (change, now) => {
|
|
348
|
+
let values = objectToEntries(change.values);
|
|
349
|
+
// SystemColumns are not encoded in change.values.
|
|
350
|
+
values = appendToArray(values, [
|
|
351
|
+
change.isInsert ? "createdAt" : "updatedAt",
|
|
352
|
+
now,
|
|
353
|
+
]);
|
|
354
|
+
if (change.isDelete != null) {
|
|
355
|
+
values = appendToArray(values, [
|
|
356
|
+
"isDeleted",
|
|
357
|
+
booleanToSqliteBoolean(change.isDelete),
|
|
358
|
+
]);
|
|
359
|
+
}
|
|
360
|
+
return values;
|
|
361
|
+
};
|
|
348
362
|
export const applyLocalOnlyChange = (deps) => (change) => {
|
|
349
363
|
if (change.isDelete) {
|
|
350
364
|
const result = deps.sqlite.exec(sql `
|
|
@@ -355,21 +369,15 @@ export const applyLocalOnlyChange = (deps) => (change) => {
|
|
|
355
369
|
return result;
|
|
356
370
|
}
|
|
357
371
|
else {
|
|
358
|
-
const now = deps.time.nowIso();
|
|
359
372
|
const ownerId = deps.appOwner.id;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
entries = [...entries, ["isDeleted", sqliteFalse]];
|
|
363
|
-
}
|
|
364
|
-
for (const [column, value] of entries) {
|
|
373
|
+
const columns = dbChangeToColumns(change, deps.time.nowIso());
|
|
374
|
+
for (const [column, value] of columns) {
|
|
365
375
|
const result = deps.sqlite.exec(sql.prepared `
|
|
366
376
|
insert into ${sql.identifier(change.table)}
|
|
367
|
-
("ownerId", "id", ${sql.identifier(column)}
|
|
368
|
-
values (${ownerId}, ${change.id}, ${value}
|
|
377
|
+
("ownerId", "id", ${sql.identifier(column)})
|
|
378
|
+
values (${ownerId}, ${change.id}, ${value})
|
|
369
379
|
on conflict ("ownerId", "id") do update
|
|
370
|
-
set
|
|
371
|
-
${sql.identifier(column)} = ${value},
|
|
372
|
-
updatedAt = ${now};
|
|
380
|
+
set ${sql.identifier(column)} = ${value};
|
|
373
381
|
`);
|
|
374
382
|
if (!result.ok)
|
|
375
383
|
return result;
|
|
@@ -379,21 +387,60 @@ export const applyLocalOnlyChange = (deps) => (change) => {
|
|
|
379
387
|
};
|
|
380
388
|
const applyMessages = (deps) => (ownerId, messages) => {
|
|
381
389
|
const ownerIdBytes = ownerIdToOwnerIdBytes(ownerId);
|
|
382
|
-
const
|
|
383
|
-
if (!
|
|
384
|
-
return
|
|
385
|
-
let { firstTimestamp, lastTimestamp } =
|
|
386
|
-
for (const
|
|
387
|
-
const
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
390
|
+
const usage = getOwnerUsage(deps)(ownerIdBytes, timestampToTimestampBytes(firstInArray(messages).timestamp));
|
|
391
|
+
if (!usage.ok)
|
|
392
|
+
return usage;
|
|
393
|
+
let { firstTimestamp, lastTimestamp } = usage.value;
|
|
394
|
+
for (const { timestamp, change } of messages) {
|
|
395
|
+
const timestampBytes = timestampToTimestampBytes(timestamp);
|
|
396
|
+
const idBytes = idToIdBytes(change.id);
|
|
397
|
+
const columns = dbChangeToColumns(change, timestampToDateIso(timestamp));
|
|
398
|
+
for (const [column, value] of columns) {
|
|
399
|
+
const updateAppTable = deps.sqlite.exec(sql.prepared `
|
|
400
|
+
with
|
|
401
|
+
existingTimestamp as (
|
|
402
|
+
select 1
|
|
403
|
+
from evolu_history
|
|
404
|
+
where
|
|
405
|
+
"ownerId" = ${ownerIdBytes}
|
|
406
|
+
and "table" = ${change.table}
|
|
407
|
+
and "id" = ${idBytes}
|
|
408
|
+
and "column" = ${column}
|
|
409
|
+
and "timestamp" >= ${timestampBytes}
|
|
410
|
+
limit 1
|
|
411
|
+
)
|
|
412
|
+
insert into ${sql.identifier(change.table)}
|
|
413
|
+
("ownerId", "id", ${sql.identifier(column)})
|
|
414
|
+
select ${ownerId}, ${change.id}, ${value}
|
|
415
|
+
where not exists (select 1 from existingTimestamp)
|
|
416
|
+
on conflict ("ownerId", "id") do update
|
|
417
|
+
set ${sql.identifier(column)} = ${value}
|
|
418
|
+
where not exists (select 1 from existingTimestamp);
|
|
419
|
+
`);
|
|
420
|
+
if (!updateAppTable.ok)
|
|
421
|
+
return updateAppTable;
|
|
422
|
+
const insertHistory = deps.sqlite.exec(sql.prepared `
|
|
423
|
+
insert into evolu_history
|
|
424
|
+
("ownerId", "table", "id", "column", "value", "timestamp")
|
|
425
|
+
values
|
|
426
|
+
(
|
|
427
|
+
${ownerIdBytes},
|
|
428
|
+
${change.table},
|
|
429
|
+
${idBytes},
|
|
430
|
+
${column},
|
|
431
|
+
${value},
|
|
432
|
+
${timestampBytes}
|
|
433
|
+
)
|
|
434
|
+
on conflict do nothing;
|
|
435
|
+
`);
|
|
436
|
+
if (!insertHistory.ok)
|
|
437
|
+
return insertHistory;
|
|
438
|
+
}
|
|
392
439
|
let strategy;
|
|
393
|
-
[strategy, firstTimestamp, lastTimestamp] = getTimestampInsertStrategy(
|
|
394
|
-
const
|
|
395
|
-
if (!
|
|
396
|
-
return
|
|
440
|
+
[strategy, firstTimestamp, lastTimestamp] = getTimestampInsertStrategy(timestampBytes, firstTimestamp, lastTimestamp);
|
|
441
|
+
const insertTimestamp = deps.storage.insertTimestamp(ownerIdBytes, timestampBytes, strategy);
|
|
442
|
+
if (!insertTimestamp.ok)
|
|
443
|
+
return insertTimestamp;
|
|
397
444
|
}
|
|
398
445
|
/**
|
|
399
446
|
* TODO: Implement proper storedBytes tracking for client using encrypted
|
|
@@ -406,73 +453,4 @@ const applyMessages = (deps) => (ownerId, messages) => {
|
|
|
406
453
|
return updateUsage;
|
|
407
454
|
return ok();
|
|
408
455
|
};
|
|
409
|
-
const applyMessageToAppTable = (deps) => (ownerIdBytes, message, date) => {
|
|
410
|
-
const ownerId = ownerIdBytesToOwnerId(ownerIdBytes);
|
|
411
|
-
const columns = dbChangeToColumns(message.change, date);
|
|
412
|
-
for (const [column, value] of columns) {
|
|
413
|
-
const result = deps.sqlite.exec(sql.prepared `
|
|
414
|
-
with
|
|
415
|
-
existingTimestamp as (
|
|
416
|
-
select 1
|
|
417
|
-
from evolu_history
|
|
418
|
-
where
|
|
419
|
-
"ownerId" = ${ownerIdBytes}
|
|
420
|
-
and "table" = ${message.change.table}
|
|
421
|
-
and "id" = ${idToIdBytes(message.change.id)}
|
|
422
|
-
and "column" = ${column}
|
|
423
|
-
and "timestamp" >= ${timestampToTimestampBytes(message.timestamp)}
|
|
424
|
-
limit 1
|
|
425
|
-
)
|
|
426
|
-
insert into ${sql.identifier(message.change.table)}
|
|
427
|
-
("ownerId", "id", ${sql.identifier(column)}, updatedAt)
|
|
428
|
-
select ${ownerId}, ${message.change.id}, ${value}, ${date}
|
|
429
|
-
where not exists (select 1 from existingTimestamp)
|
|
430
|
-
on conflict ("ownerId", "id") do update
|
|
431
|
-
set
|
|
432
|
-
${sql.identifier(column)} = ${value},
|
|
433
|
-
updatedAt = ${date}
|
|
434
|
-
where not exists (select 1 from existingTimestamp);
|
|
435
|
-
`);
|
|
436
|
-
if (!result.ok)
|
|
437
|
-
return result;
|
|
438
|
-
}
|
|
439
|
-
return ok();
|
|
440
|
-
};
|
|
441
|
-
export const applyMessageToTimestampAndHistoryTables = (deps) => (ownerId, message, strategy, date) => {
|
|
442
|
-
const timestamp = timestampToTimestampBytes(message.timestamp);
|
|
443
|
-
const id = idToIdBytes(message.change.id);
|
|
444
|
-
const result = deps.storage.insertTimestamp(ownerId, timestamp, strategy);
|
|
445
|
-
if (!result.ok)
|
|
446
|
-
return result;
|
|
447
|
-
const columns = dbChangeToColumns(message.change, date);
|
|
448
|
-
for (const [column, value] of columns) {
|
|
449
|
-
const result = deps.sqlite.exec(sql.prepared `
|
|
450
|
-
insert into evolu_history
|
|
451
|
-
("ownerId", "table", "id", "column", "value", "timestamp")
|
|
452
|
-
values
|
|
453
|
-
(
|
|
454
|
-
${ownerId},
|
|
455
|
-
${message.change.table},
|
|
456
|
-
${id},
|
|
457
|
-
${column},
|
|
458
|
-
${value},
|
|
459
|
-
${timestamp}
|
|
460
|
-
)
|
|
461
|
-
on conflict do nothing;
|
|
462
|
-
`);
|
|
463
|
-
if (!result.ok)
|
|
464
|
-
return result;
|
|
465
|
-
}
|
|
466
|
-
return ok();
|
|
467
|
-
};
|
|
468
|
-
const dbChangeToColumns = (change, date) => {
|
|
469
|
-
const entries = [...objectToEntries(change.values)];
|
|
470
|
-
if (change.isInsert) {
|
|
471
|
-
entries.push(["createdAt", date]);
|
|
472
|
-
}
|
|
473
|
-
if (change.isDelete !== null) {
|
|
474
|
-
entries.push(["isDeleted", booleanToSqliteBoolean(change.isDelete)]);
|
|
475
|
-
}
|
|
476
|
-
return entries;
|
|
477
|
-
};
|
|
478
456
|
export const initialSyncState = { type: "SyncStateInitial" };
|
|
@@ -154,6 +154,19 @@ export type TimestampBytes = typeof TimestampBytes.Type;
|
|
|
154
154
|
export declare const timestampBytesLength: number & import("../Brand.js").Brand<"Int"> & import("../Brand.js").Brand<"NonNegative">;
|
|
155
155
|
export declare const timestampToTimestampBytes: (timestamp: Timestamp) => TimestampBytes;
|
|
156
156
|
export declare const timestampBytesToTimestamp: (timestamp: TimestampBytes) => Timestamp;
|
|
157
|
+
/**
|
|
158
|
+
* An {@link Order} for {@link TimestampBytes}.
|
|
159
|
+
*
|
|
160
|
+
* This `Order` uses lexicographic byte order to compare serialized
|
|
161
|
+
* {@link TimestampBytes} produced by {@link timestampToTimestampBytes}. See
|
|
162
|
+
* {@link orderUint8Array} for the underlying implementation.
|
|
163
|
+
*/
|
|
157
164
|
export declare const orderTimestampBytes: Order<TimestampBytes>;
|
|
165
|
+
/**
|
|
166
|
+
* Convert a {@link Timestamp} to an ISO 8601 {@link DateIso} string.
|
|
167
|
+
*
|
|
168
|
+
* The conversion uses the timestamp's `millis` (a {@link Millis} value) and
|
|
169
|
+
* `Date.prototype.toISOString()` to produce a `DateIso`.
|
|
170
|
+
*/
|
|
158
171
|
export declare const timestampToDateIso: (timestamp: Timestamp) => DateIso;
|
|
159
172
|
//# sourceMappingURL=Timestamp.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../src/local-first/Timestamp.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../src/local-first/Timestamp.ts"],"names":[],"mappings":"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"}
|
|
@@ -218,7 +218,20 @@ export const timestampBytesToTimestamp = (timestamp) => {
|
|
|
218
218
|
}
|
|
219
219
|
return { millis: Number(millis), counter, nodeId };
|
|
220
220
|
};
|
|
221
|
+
/**
|
|
222
|
+
* An {@link Order} for {@link TimestampBytes}.
|
|
223
|
+
*
|
|
224
|
+
* This `Order` uses lexicographic byte order to compare serialized
|
|
225
|
+
* {@link TimestampBytes} produced by {@link timestampToTimestampBytes}. See
|
|
226
|
+
* {@link orderUint8Array} for the underlying implementation.
|
|
227
|
+
*/
|
|
221
228
|
export const orderTimestampBytes = orderUint8Array;
|
|
229
|
+
/**
|
|
230
|
+
* Convert a {@link Timestamp} to an ISO 8601 {@link DateIso} string.
|
|
231
|
+
*
|
|
232
|
+
* The conversion uses the timestamp's `millis` (a {@link Millis} value) and
|
|
233
|
+
* `Date.prototype.toISOString()` to produce a `DateIso`.
|
|
234
|
+
*/
|
|
222
235
|
export const timestampToDateIso = (timestamp) =>
|
|
223
|
-
// `as DateIso` is safe because
|
|
236
|
+
// `as DateIso` is safe because Timestamp guarantees a valid `millis`
|
|
224
237
|
new Date(timestamp.millis).toISOString();
|
package/package.json
CHANGED
package/src/Object.ts
CHANGED
|
@@ -31,7 +31,7 @@ type StringKeyOf<T> = Extract<keyof T, string>;
|
|
|
31
31
|
*
|
|
32
32
|
* ```ts
|
|
33
33
|
* type UserId = string & { readonly __brand: "UserId" };
|
|
34
|
-
* const users
|
|
34
|
+
* const users = createRecord<UserId, string>();
|
|
35
35
|
* const entries = objectToEntries(users); // [UserId, string][]
|
|
36
36
|
* ```
|
|
37
37
|
*/
|
|
@@ -70,3 +70,22 @@ export const excludeProp = <T extends object, K extends keyof T>(
|
|
|
70
70
|
const { [prop]: _, ...rest } = obj;
|
|
71
71
|
return rest;
|
|
72
72
|
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates a prototype-less object typed as `Record<K, V>`.
|
|
76
|
+
*
|
|
77
|
+
* Use this function when you need a plain record without a prototype chain
|
|
78
|
+
* (e.g. when keys are controlled by external sources) to avoid prototype
|
|
79
|
+
* pollution and accidental collisions with properties like `__proto__`.
|
|
80
|
+
*
|
|
81
|
+
* Example:
|
|
82
|
+
*
|
|
83
|
+
* ```ts
|
|
84
|
+
* const values = createRecord<string, SqliteValue>();
|
|
85
|
+
* values["__proto__"] = someValue; // safe, no prototype pollution
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export const createRecord = <K extends string = string, V = unknown>(): Record<
|
|
89
|
+
K,
|
|
90
|
+
V
|
|
91
|
+
> => Object.create(null) as Record<K, V>;
|
package/src/Order.ts
CHANGED
|
@@ -94,7 +94,8 @@ export const orderNumber = createOrder<number>((a, b) => a < b);
|
|
|
94
94
|
*/
|
|
95
95
|
export const orderBigInt = createOrder<bigint>((a, b) => a < b);
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
/** An {@link Order} for Uint8Array. */
|
|
98
|
+
export const orderUint8Array: Order<Uint8Array> = (a, b) => {
|
|
98
99
|
if (a.byteLength > b.byteLength) return 1;
|
|
99
100
|
if (a.byteLength < b.byteLength) return -1;
|
|
100
101
|
|
package/src/local-first/Db.ts
CHANGED
|
@@ -336,9 +336,12 @@ export const createDbWorkerForPlatform = (
|
|
|
336
336
|
DbWorkerInput,
|
|
337
337
|
DbWorkerOutput,
|
|
338
338
|
DbWorkerDeps
|
|
339
|
-
>({
|
|
339
|
+
>({
|
|
340
|
+
init: createInit(platformDeps),
|
|
341
|
+
handlers,
|
|
342
|
+
});
|
|
340
343
|
|
|
341
|
-
const
|
|
344
|
+
const createInit =
|
|
342
345
|
(platformDeps: DbWorkerPlatformDeps) =>
|
|
343
346
|
async (
|
|
344
347
|
initMessage: Extract<DbWorkerInput, { type: "init" }>,
|
|
@@ -376,16 +379,6 @@ const createDbWorkerDeps =
|
|
|
376
379
|
}>(sql`select protocolVersion from evolu_version limit 1;`);
|
|
377
380
|
if (!currentVersion.ok) return currentVersion;
|
|
378
381
|
|
|
379
|
-
// TODO: Handle version migrations here if needed
|
|
380
|
-
// const [{ protocolVersion }] = protocolVersionResult.value.rows;
|
|
381
|
-
// if (protocolVersion < currentProtocolVersion) {
|
|
382
|
-
// const migrateResult = migrateDatabase({ sqlite })(
|
|
383
|
-
// protocolVersion,
|
|
384
|
-
// currentProtocolVersion
|
|
385
|
-
// );
|
|
386
|
-
// if (!migrateResult.ok) return migrateResult;
|
|
387
|
-
// }
|
|
388
|
-
|
|
389
382
|
const configResult = sqlite.exec<{
|
|
390
383
|
clock: TimestampBytes;
|
|
391
384
|
appOwnerId: OwnerId;
|
package/src/local-first/Diff.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRandomBytes } from "../Crypto.js";
|
|
2
|
-
import { isPlainObject, ReadonlyRecord } from "../Object.js";
|
|
2
|
+
import { createRecord, isPlainObject, ReadonlyRecord } from "../Object.js";
|
|
3
3
|
import { orderUint8Array } from "../Order.js";
|
|
4
4
|
import { SqliteValue } from "../Sqlite.js";
|
|
5
5
|
import { createId, String } from "../Type.js";
|
|
@@ -136,7 +136,7 @@ const parse = (obj: unknown): unknown => {
|
|
|
136
136
|
const parseObject = (
|
|
137
137
|
obj: ReadonlyRecord<string, unknown>,
|
|
138
138
|
): ReadonlyRecord<string, unknown> => {
|
|
139
|
-
const result =
|
|
139
|
+
const result = createRecord();
|
|
140
140
|
for (const key in obj) {
|
|
141
141
|
result[key] = parse(obj[key]);
|
|
142
142
|
}
|
package/src/local-first/Evolu.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
isNonEmptyArray,
|
|
5
5
|
isNonEmptyReadonlyArray,
|
|
6
6
|
} from "../Array.js";
|
|
7
|
-
import { assertNonEmptyReadonlyArray } from "../Assert.js";
|
|
7
|
+
import { assert, assertNonEmptyReadonlyArray } from "../Assert.js";
|
|
8
8
|
import { createCallbacks } from "../Callbacks.js";
|
|
9
9
|
import { ConsoleDep } from "../Console.js";
|
|
10
10
|
import { RandomBytesDep, SymmetricCryptoDecryptError } from "../Crypto.js";
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
isSqlMutation,
|
|
18
18
|
SafeSql,
|
|
19
19
|
SqliteBoolean,
|
|
20
|
+
sqliteBooleanToBoolean,
|
|
20
21
|
SqliteError,
|
|
21
22
|
SqliteQuery,
|
|
22
23
|
} from "../Sqlite.js";
|
|
@@ -730,13 +731,20 @@ const createEvoluInstance =
|
|
|
730
731
|
} else {
|
|
731
732
|
const { id: _, isDeleted, ...values } = result.value;
|
|
732
733
|
|
|
733
|
-
const dbChange =
|
|
734
|
+
const dbChange = {
|
|
734
735
|
table,
|
|
735
736
|
id,
|
|
736
737
|
values,
|
|
737
738
|
isInsert: kind === "insert" || kind === "upsert",
|
|
738
|
-
isDelete: SqliteBoolean.is(isDeleted)
|
|
739
|
-
|
|
739
|
+
isDelete: SqliteBoolean.is(isDeleted)
|
|
740
|
+
? sqliteBooleanToBoolean(isDeleted)
|
|
741
|
+
: null,
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
assert(
|
|
745
|
+
DbChange.is(dbChange),
|
|
746
|
+
`Invalid DbChange for table '${table}': Please check schema type errors.`,
|
|
747
|
+
);
|
|
740
748
|
|
|
741
749
|
mutateMicrotaskQueue.push([
|
|
742
750
|
{ ...dbChange, ownerId: options?.ownerId },
|
|
@@ -198,7 +198,7 @@ import {
|
|
|
198
198
|
} from "../Crypto.js";
|
|
199
199
|
import { eqArrayNumber } from "../Eq.js";
|
|
200
200
|
import { computeBalancedBuckets } from "../Number.js";
|
|
201
|
-
import { objectToEntries } from "../Object.js";
|
|
201
|
+
import { createRecord, objectToEntries } from "../Object.js";
|
|
202
202
|
import { err, ok, Result } from "../Result.js";
|
|
203
203
|
import { SqliteValue } from "../Sqlite.js";
|
|
204
204
|
import {
|
|
@@ -221,8 +221,8 @@ import {
|
|
|
221
221
|
} from "../Type.js";
|
|
222
222
|
import { Predicate } from "../Types.js";
|
|
223
223
|
import {
|
|
224
|
-
OwnerError,
|
|
225
224
|
Owner,
|
|
225
|
+
OwnerError,
|
|
226
226
|
OwnerId,
|
|
227
227
|
OwnerIdBytes,
|
|
228
228
|
ownerIdToOwnerIdBytes,
|
|
@@ -1816,7 +1816,7 @@ export const decryptAndDecodeDbChange =
|
|
|
1816
1816
|
const id = decodeId(buffer);
|
|
1817
1817
|
|
|
1818
1818
|
const length = decodeLength(buffer);
|
|
1819
|
-
const values =
|
|
1819
|
+
const values = createRecord<string, SqliteValue>();
|
|
1820
1820
|
|
|
1821
1821
|
for (let i = 0; i < length; i++) {
|
|
1822
1822
|
const column = decodeString(buffer);
|
package/src/local-first/Sync.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
+
appendToArray,
|
|
2
3
|
firstInArray,
|
|
3
4
|
isNonEmptyReadonlyArray,
|
|
4
5
|
NonEmptyArray,
|
|
5
6
|
NonEmptyReadonlyArray,
|
|
6
7
|
} from "../Array.js";
|
|
7
|
-
import { assert } from "../Assert.js";
|
|
8
|
+
import { assert, assertNonEmptyReadonlyArray } from "../Assert.js";
|
|
8
9
|
import { Brand } from "../Brand.js";
|
|
9
10
|
import { ConsoleDep } from "../Console.js";
|
|
10
11
|
import {
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
import { eqArrayNumber } from "../Eq.js";
|
|
16
17
|
import { createTransferableError, TransferableError } from "../Error.js";
|
|
17
18
|
import { constFalse, constTrue } from "../Function.js";
|
|
18
|
-
import { objectToEntries } from "../Object.js";
|
|
19
|
+
import { createRecord, objectToEntries } from "../Object.js";
|
|
19
20
|
import { RandomDep } from "../Random.js";
|
|
20
21
|
import { createResources } from "../Resources.js";
|
|
21
22
|
import { err, ok, Result } from "../Result.js";
|
|
@@ -26,12 +27,12 @@ import {
|
|
|
26
27
|
sqliteBooleanToBoolean,
|
|
27
28
|
SqliteDep,
|
|
28
29
|
SqliteError,
|
|
29
|
-
sqliteFalse,
|
|
30
30
|
SqliteValue,
|
|
31
31
|
} from "../Sqlite.js";
|
|
32
32
|
import { AbortError, createMutex } from "../Task.js";
|
|
33
33
|
import { TimeDep } from "../Time.js";
|
|
34
34
|
import {
|
|
35
|
+
Boolean,
|
|
35
36
|
DateIso,
|
|
36
37
|
IdBytes,
|
|
37
38
|
idBytesToId,
|
|
@@ -44,7 +45,6 @@ import {
|
|
|
44
45
|
AppOwner,
|
|
45
46
|
Owner,
|
|
46
47
|
OwnerId,
|
|
47
|
-
OwnerIdBytes,
|
|
48
48
|
ownerIdBytesToOwnerId,
|
|
49
49
|
ownerIdToOwnerIdBytes,
|
|
50
50
|
OwnerTransport,
|
|
@@ -71,7 +71,6 @@ import {
|
|
|
71
71
|
getOwnerUsage,
|
|
72
72
|
getTimestampInsertStrategy,
|
|
73
73
|
Storage,
|
|
74
|
-
StorageInsertTimestampStrategy,
|
|
75
74
|
StorageWriteError,
|
|
76
75
|
updateOwnerUsage,
|
|
77
76
|
} from "./Storage.js";
|
|
@@ -451,8 +450,7 @@ const createClientStorage =
|
|
|
451
450
|
SqliteDep &
|
|
452
451
|
SymmetricCryptoDep &
|
|
453
452
|
TimeDep &
|
|
454
|
-
TimestampConfigDep
|
|
455
|
-
PostMessageDep,
|
|
453
|
+
TimestampConfigDep,
|
|
456
454
|
) =>
|
|
457
455
|
(config: {
|
|
458
456
|
onError: (
|
|
@@ -545,12 +543,6 @@ const createClientStorage =
|
|
|
545
543
|
if (!applyMessagesResult.ok) return applyMessagesResult;
|
|
546
544
|
}
|
|
547
545
|
|
|
548
|
-
// // Apply local mutations atomically with approved messages
|
|
549
|
-
// for (const change of localMutations) {
|
|
550
|
-
// const result = applyLocalOnlyChange(deps)(change);
|
|
551
|
-
// if (!result.ok) return result;
|
|
552
|
-
// }
|
|
553
|
-
|
|
554
546
|
return deps.clock.save(clockTimestamp);
|
|
555
547
|
});
|
|
556
548
|
|
|
@@ -592,11 +584,11 @@ const createClientStorage =
|
|
|
592
584
|
}
|
|
593
585
|
|
|
594
586
|
const { rows } = result.value;
|
|
595
|
-
|
|
587
|
+
assertNonEmptyReadonlyArray(rows, "Every timestamp must have rows");
|
|
596
588
|
|
|
597
|
-
const { table, id } = rows
|
|
598
|
-
const values
|
|
599
|
-
let isInsert
|
|
589
|
+
const { table, id } = firstInArray(rows);
|
|
590
|
+
const values = createRecord<string, SqliteValue>();
|
|
591
|
+
let isInsert;
|
|
600
592
|
let isDelete: boolean | null = null;
|
|
601
593
|
|
|
602
594
|
for (const r of rows) {
|
|
@@ -606,10 +598,13 @@ const createClientStorage =
|
|
|
606
598
|
case "createdAt":
|
|
607
599
|
isInsert = true;
|
|
608
600
|
break;
|
|
601
|
+
case "updatedAt":
|
|
602
|
+
isInsert = false;
|
|
603
|
+
break;
|
|
609
604
|
case "isDeleted":
|
|
610
605
|
assert(
|
|
611
606
|
SqliteBoolean.is(r.value),
|
|
612
|
-
"isDeleted column must contain a valid SqliteBoolean
|
|
607
|
+
"isDeleted column must contain a valid SqliteBoolean",
|
|
613
608
|
);
|
|
614
609
|
isDelete = sqliteBooleanToBoolean(r.value);
|
|
615
610
|
break;
|
|
@@ -618,6 +613,8 @@ const createClientStorage =
|
|
|
618
613
|
}
|
|
619
614
|
}
|
|
620
615
|
|
|
616
|
+
assert(Boolean.is(isInsert), "isInsert must be in evolu_history");
|
|
617
|
+
|
|
621
618
|
const message: CrdtMessage = {
|
|
622
619
|
timestamp: timestampBytesToTimestamp(timestamp),
|
|
623
620
|
change: DbChange.orThrow({
|
|
@@ -643,6 +640,24 @@ const createTransportKey = (transport: OwnerTransport): TransportKey => {
|
|
|
643
640
|
return `${transport.type}:${transport.url}` as TransportKey;
|
|
644
641
|
};
|
|
645
642
|
|
|
643
|
+
const dbChangeToColumns = (change: DbChange, now: DateIso) => {
|
|
644
|
+
let values = objectToEntries(change.values);
|
|
645
|
+
|
|
646
|
+
// SystemColumns are not encoded in change.values.
|
|
647
|
+
values = appendToArray(values, [
|
|
648
|
+
change.isInsert ? "createdAt" : "updatedAt",
|
|
649
|
+
now,
|
|
650
|
+
]);
|
|
651
|
+
if (change.isDelete != null) {
|
|
652
|
+
values = appendToArray(values, [
|
|
653
|
+
"isDeleted",
|
|
654
|
+
booleanToSqliteBoolean(change.isDelete),
|
|
655
|
+
]);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return values;
|
|
659
|
+
};
|
|
660
|
+
|
|
646
661
|
export const applyLocalOnlyChange =
|
|
647
662
|
(deps: SqliteDep & TimeDep & AppOwnerDep) =>
|
|
648
663
|
(change: MutationChange): Result<void, SqliteError> => {
|
|
@@ -653,23 +668,16 @@ export const applyLocalOnlyChange =
|
|
|
653
668
|
`);
|
|
654
669
|
if (!result.ok) return result;
|
|
655
670
|
} else {
|
|
656
|
-
const now = deps.time.nowIso();
|
|
657
671
|
const ownerId = deps.appOwner.id;
|
|
672
|
+
const columns = dbChangeToColumns(change, deps.time.nowIso());
|
|
658
673
|
|
|
659
|
-
|
|
660
|
-
if (change.isDelete !== null) {
|
|
661
|
-
entries = [...entries, ["isDeleted", sqliteFalse]];
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
for (const [column, value] of entries) {
|
|
674
|
+
for (const [column, value] of columns) {
|
|
665
675
|
const result = deps.sqlite.exec(sql.prepared`
|
|
666
676
|
insert into ${sql.identifier(change.table)}
|
|
667
|
-
("ownerId", "id", ${sql.identifier(column)}
|
|
668
|
-
values (${ownerId}, ${change.id}, ${value}
|
|
677
|
+
("ownerId", "id", ${sql.identifier(column)})
|
|
678
|
+
values (${ownerId}, ${change.id}, ${value})
|
|
669
679
|
on conflict ("ownerId", "id") do update
|
|
670
|
-
set
|
|
671
|
-
${sql.identifier(column)} = ${value},
|
|
672
|
-
updatedAt = ${now};
|
|
680
|
+
set ${sql.identifier(column)} = ${value};
|
|
673
681
|
`);
|
|
674
682
|
if (!result.ok) return result;
|
|
675
683
|
}
|
|
@@ -686,35 +694,75 @@ const applyMessages =
|
|
|
686
694
|
): Result<void, SqliteError> => {
|
|
687
695
|
const ownerIdBytes = ownerIdToOwnerIdBytes(ownerId);
|
|
688
696
|
|
|
689
|
-
const
|
|
697
|
+
const usage = getOwnerUsage(deps)(
|
|
690
698
|
ownerIdBytes,
|
|
691
699
|
timestampToTimestampBytes(firstInArray(messages).timestamp),
|
|
692
700
|
);
|
|
693
|
-
if (!
|
|
694
|
-
|
|
695
|
-
let { firstTimestamp, lastTimestamp } =
|
|
701
|
+
if (!usage.ok) return usage;
|
|
702
|
+
|
|
703
|
+
let { firstTimestamp, lastTimestamp } = usage.value;
|
|
704
|
+
|
|
705
|
+
for (const { timestamp, change } of messages) {
|
|
706
|
+
const timestampBytes = timestampToTimestampBytes(timestamp);
|
|
707
|
+
const idBytes = idToIdBytes(change.id);
|
|
708
|
+
const columns = dbChangeToColumns(change, timestampToDateIso(timestamp));
|
|
709
|
+
|
|
710
|
+
for (const [column, value] of columns) {
|
|
711
|
+
const updateAppTable = deps.sqlite.exec(sql.prepared`
|
|
712
|
+
with
|
|
713
|
+
existingTimestamp as (
|
|
714
|
+
select 1
|
|
715
|
+
from evolu_history
|
|
716
|
+
where
|
|
717
|
+
"ownerId" = ${ownerIdBytes}
|
|
718
|
+
and "table" = ${change.table}
|
|
719
|
+
and "id" = ${idBytes}
|
|
720
|
+
and "column" = ${column}
|
|
721
|
+
and "timestamp" >= ${timestampBytes}
|
|
722
|
+
limit 1
|
|
723
|
+
)
|
|
724
|
+
insert into ${sql.identifier(change.table)}
|
|
725
|
+
("ownerId", "id", ${sql.identifier(column)})
|
|
726
|
+
select ${ownerId}, ${change.id}, ${value}
|
|
727
|
+
where not exists (select 1 from existingTimestamp)
|
|
728
|
+
on conflict ("ownerId", "id") do update
|
|
729
|
+
set ${sql.identifier(column)} = ${value}
|
|
730
|
+
where not exists (select 1 from existingTimestamp);
|
|
731
|
+
`);
|
|
696
732
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
733
|
+
if (!updateAppTable.ok) return updateAppTable;
|
|
734
|
+
|
|
735
|
+
const insertHistory = deps.sqlite.exec(sql.prepared`
|
|
736
|
+
insert into evolu_history
|
|
737
|
+
("ownerId", "table", "id", "column", "value", "timestamp")
|
|
738
|
+
values
|
|
739
|
+
(
|
|
740
|
+
${ownerIdBytes},
|
|
741
|
+
${change.table},
|
|
742
|
+
${idBytes},
|
|
743
|
+
${column},
|
|
744
|
+
${value},
|
|
745
|
+
${timestampBytes}
|
|
746
|
+
)
|
|
747
|
+
on conflict do nothing;
|
|
748
|
+
`);
|
|
701
749
|
|
|
702
|
-
|
|
750
|
+
if (!insertHistory.ok) return insertHistory;
|
|
751
|
+
}
|
|
703
752
|
|
|
704
753
|
let strategy;
|
|
705
754
|
[strategy, firstTimestamp, lastTimestamp] = getTimestampInsertStrategy(
|
|
706
|
-
|
|
755
|
+
timestampBytes,
|
|
707
756
|
firstTimestamp,
|
|
708
757
|
lastTimestamp,
|
|
709
758
|
);
|
|
710
759
|
|
|
711
|
-
const
|
|
760
|
+
const insertTimestamp = deps.storage.insertTimestamp(
|
|
712
761
|
ownerIdBytes,
|
|
713
|
-
|
|
762
|
+
timestampBytes,
|
|
714
763
|
strategy,
|
|
715
|
-
date,
|
|
716
764
|
);
|
|
717
|
-
if (!
|
|
765
|
+
if (!insertTimestamp.ok) return insertTimestamp;
|
|
718
766
|
}
|
|
719
767
|
|
|
720
768
|
/**
|
|
@@ -733,98 +781,6 @@ const applyMessages =
|
|
|
733
781
|
return ok();
|
|
734
782
|
};
|
|
735
783
|
|
|
736
|
-
const applyMessageToAppTable =
|
|
737
|
-
(deps: SqliteDep) =>
|
|
738
|
-
(
|
|
739
|
-
ownerIdBytes: OwnerIdBytes,
|
|
740
|
-
message: CrdtMessage,
|
|
741
|
-
date: DateIso,
|
|
742
|
-
): Result<void, SqliteError> => {
|
|
743
|
-
const ownerId = ownerIdBytesToOwnerId(ownerIdBytes);
|
|
744
|
-
const columns = dbChangeToColumns(message.change, date);
|
|
745
|
-
|
|
746
|
-
for (const [column, value] of columns) {
|
|
747
|
-
const result = deps.sqlite.exec(sql.prepared`
|
|
748
|
-
with
|
|
749
|
-
existingTimestamp as (
|
|
750
|
-
select 1
|
|
751
|
-
from evolu_history
|
|
752
|
-
where
|
|
753
|
-
"ownerId" = ${ownerIdBytes}
|
|
754
|
-
and "table" = ${message.change.table}
|
|
755
|
-
and "id" = ${idToIdBytes(message.change.id)}
|
|
756
|
-
and "column" = ${column}
|
|
757
|
-
and "timestamp" >= ${timestampToTimestampBytes(message.timestamp)}
|
|
758
|
-
limit 1
|
|
759
|
-
)
|
|
760
|
-
insert into ${sql.identifier(message.change.table)}
|
|
761
|
-
("ownerId", "id", ${sql.identifier(column)}, updatedAt)
|
|
762
|
-
select ${ownerId}, ${message.change.id}, ${value}, ${date}
|
|
763
|
-
where not exists (select 1 from existingTimestamp)
|
|
764
|
-
on conflict ("ownerId", "id") do update
|
|
765
|
-
set
|
|
766
|
-
${sql.identifier(column)} = ${value},
|
|
767
|
-
updatedAt = ${date}
|
|
768
|
-
where not exists (select 1 from existingTimestamp);
|
|
769
|
-
`);
|
|
770
|
-
|
|
771
|
-
if (!result.ok) return result;
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
return ok();
|
|
775
|
-
};
|
|
776
|
-
|
|
777
|
-
export const applyMessageToTimestampAndHistoryTables =
|
|
778
|
-
(deps: ClientStorageDep & SqliteDep) =>
|
|
779
|
-
(
|
|
780
|
-
ownerId: OwnerIdBytes,
|
|
781
|
-
message: CrdtMessage,
|
|
782
|
-
strategy: StorageInsertTimestampStrategy,
|
|
783
|
-
date: DateIso,
|
|
784
|
-
): Result<void, SqliteError> => {
|
|
785
|
-
const timestamp = timestampToTimestampBytes(message.timestamp);
|
|
786
|
-
const id = idToIdBytes(message.change.id);
|
|
787
|
-
|
|
788
|
-
const result = deps.storage.insertTimestamp(ownerId, timestamp, strategy);
|
|
789
|
-
if (!result.ok) return result;
|
|
790
|
-
|
|
791
|
-
const columns = dbChangeToColumns(message.change, date);
|
|
792
|
-
|
|
793
|
-
for (const [column, value] of columns) {
|
|
794
|
-
const result = deps.sqlite.exec(sql.prepared`
|
|
795
|
-
insert into evolu_history
|
|
796
|
-
("ownerId", "table", "id", "column", "value", "timestamp")
|
|
797
|
-
values
|
|
798
|
-
(
|
|
799
|
-
${ownerId},
|
|
800
|
-
${message.change.table},
|
|
801
|
-
${id},
|
|
802
|
-
${column},
|
|
803
|
-
${value},
|
|
804
|
-
${timestamp}
|
|
805
|
-
)
|
|
806
|
-
on conflict do nothing;
|
|
807
|
-
`);
|
|
808
|
-
if (!result.ok) return result;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
return ok();
|
|
812
|
-
};
|
|
813
|
-
|
|
814
|
-
const dbChangeToColumns = (
|
|
815
|
-
change: DbChange,
|
|
816
|
-
date: DateIso,
|
|
817
|
-
): Array<[string, SqliteValue | DateIso]> => {
|
|
818
|
-
const entries = [...objectToEntries(change.values)];
|
|
819
|
-
if (change.isInsert) {
|
|
820
|
-
entries.push(["createdAt", date]);
|
|
821
|
-
}
|
|
822
|
-
if (change.isDelete !== null) {
|
|
823
|
-
entries.push(["isDeleted", booleanToSqliteBoolean(change.isDelete)]);
|
|
824
|
-
}
|
|
825
|
-
return entries;
|
|
826
|
-
};
|
|
827
|
-
|
|
828
784
|
/**
|
|
829
785
|
* TODO: Rework for the new owners API.
|
|
830
786
|
*
|
|
@@ -336,8 +336,21 @@ export const timestampBytesToTimestamp = (
|
|
|
336
336
|
return { millis: Number(millis), counter, nodeId } as Timestamp;
|
|
337
337
|
};
|
|
338
338
|
|
|
339
|
+
/**
|
|
340
|
+
* An {@link Order} for {@link TimestampBytes}.
|
|
341
|
+
*
|
|
342
|
+
* This `Order` uses lexicographic byte order to compare serialized
|
|
343
|
+
* {@link TimestampBytes} produced by {@link timestampToTimestampBytes}. See
|
|
344
|
+
* {@link orderUint8Array} for the underlying implementation.
|
|
345
|
+
*/
|
|
339
346
|
export const orderTimestampBytes: Order<TimestampBytes> = orderUint8Array;
|
|
340
347
|
|
|
348
|
+
/**
|
|
349
|
+
* Convert a {@link Timestamp} to an ISO 8601 {@link DateIso} string.
|
|
350
|
+
*
|
|
351
|
+
* The conversion uses the timestamp's `millis` (a {@link Millis} value) and
|
|
352
|
+
* `Date.prototype.toISOString()` to produce a `DateIso`.
|
|
353
|
+
*/
|
|
341
354
|
export const timestampToDateIso = (timestamp: Timestamp): DateIso =>
|
|
342
|
-
// `as DateIso` is safe because
|
|
355
|
+
// `as DateIso` is safe because Timestamp guarantees a valid `millis`
|
|
343
356
|
new Date(timestamp.millis).toISOString() as DateIso;
|