@evolu/common 5.4.7 → 6.0.0
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/README.md +30 -34
- package/dist/src/Array.d.ts +17 -0
- package/dist/src/Array.d.ts.map +1 -0
- package/dist/src/Array.js +12 -0
- package/dist/src/Assert.d.ts +68 -0
- package/dist/src/Assert.d.ts.map +1 -0
- package/dist/src/Assert.js +77 -0
- package/dist/src/BigInt.d.ts +20 -0
- package/dist/src/BigInt.d.ts.map +1 -0
- package/dist/src/BigInt.js +18 -0
- package/dist/src/Buffer.d.ts +92 -0
- package/dist/src/Buffer.d.ts.map +1 -0
- package/dist/src/Buffer.js +62 -0
- package/dist/src/Callbacks.d.ts +20 -0
- package/dist/src/Callbacks.d.ts.map +1 -0
- package/dist/src/Callbacks.js +18 -0
- package/dist/src/Console.d.ts +78 -0
- package/dist/src/Console.d.ts.map +1 -0
- package/dist/src/Console.js +103 -0
- package/dist/src/Crypto.d.ts +72 -39
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +89 -54
- package/dist/src/Eq.d.ts +97 -0
- package/dist/src/Eq.d.ts.map +1 -0
- package/dist/src/Eq.js +167 -0
- package/dist/src/Error.d.ts +14 -10
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +43 -11
- package/dist/src/Evolu/Config.d.ts +69 -0
- package/dist/src/Evolu/Config.d.ts.map +1 -0
- package/dist/src/Evolu/Config.js +9 -0
- package/dist/src/Evolu/Db.d.ts +126 -0
- package/dist/src/Evolu/Db.d.ts.map +1 -0
- package/dist/src/Evolu/Db.js +774 -0
- package/dist/src/Evolu/Diff.d.ts +43 -0
- package/dist/src/Evolu/Diff.d.ts.map +1 -0
- package/dist/src/Evolu/Diff.js +95 -0
- package/dist/src/Evolu/Evolu.d.ts +334 -0
- package/dist/src/Evolu/Evolu.d.ts.map +1 -0
- package/dist/src/Evolu/Evolu.js +434 -0
- package/dist/src/Evolu/Internal.d.ts +26 -0
- package/dist/src/Evolu/Internal.d.ts.map +1 -0
- package/dist/src/Evolu/Internal.js +25 -0
- package/dist/src/Evolu/Kysely.d.ts +6 -0
- package/dist/src/Evolu/Kysely.d.ts.map +1 -0
- package/dist/src/Evolu/Kysely.js +21 -0
- package/dist/src/Evolu/Owner.d.ts +155 -0
- package/dist/src/Evolu/Owner.d.ts.map +1 -0
- package/dist/src/Evolu/Owner.js +126 -0
- package/dist/src/Evolu/Platform.d.ts +23 -0
- package/dist/src/Evolu/Platform.d.ts.map +1 -0
- package/dist/src/Evolu/Platform.js +1 -0
- package/dist/src/Evolu/Protocol.d.ts +401 -0
- package/dist/src/Evolu/Protocol.d.ts.map +1 -0
- package/dist/src/Evolu/Protocol.js +1151 -0
- package/dist/src/Evolu/Public.d.ts +18 -0
- package/dist/src/Evolu/Public.d.ts.map +1 -0
- package/dist/src/Evolu/Public.js +11 -0
- package/dist/src/Evolu/PublicKysely.d.ts +148 -0
- package/dist/src/Evolu/PublicKysely.d.ts.map +1 -0
- package/dist/src/Evolu/PublicKysely.js +185 -0
- package/dist/src/Evolu/Query.d.ts +63 -0
- package/dist/src/Evolu/Query.d.ts.map +1 -0
- package/dist/src/Evolu/Query.js +61 -0
- package/dist/src/Evolu/Relay.d.ts +13 -0
- package/dist/src/Evolu/Relay.d.ts.map +1 -0
- package/dist/src/Evolu/Relay.js +109 -0
- package/dist/src/Evolu/Schema.d.ts +201 -0
- package/dist/src/Evolu/Schema.d.ts.map +1 -0
- package/dist/src/Evolu/Schema.js +150 -0
- package/dist/src/Evolu/Storage.d.ts +49 -0
- package/dist/src/Evolu/Storage.d.ts.map +1 -0
- package/dist/src/Evolu/Storage.js +1111 -0
- package/dist/src/Evolu/Sync.d.ts +59 -0
- package/dist/src/Evolu/Sync.d.ts.map +1 -0
- package/dist/src/Evolu/Sync.js +29 -0
- package/dist/src/Evolu/Timestamp.d.ts +106 -0
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -0
- package/dist/src/Evolu/Timestamp.js +179 -0
- package/dist/src/Function.d.ts +54 -0
- package/dist/src/Function.d.ts.map +1 -0
- package/dist/src/Function.js +38 -0
- package/dist/src/ManyToManyMap.d.ts +26 -0
- package/dist/src/ManyToManyMap.d.ts.map +1 -0
- package/dist/src/ManyToManyMap.js +92 -0
- package/dist/src/NanoId.d.ts +27 -0
- package/dist/src/NanoId.d.ts.map +1 -0
- package/dist/src/NanoId.js +6 -0
- package/dist/src/Number.d.ts +42 -0
- package/dist/src/Number.d.ts.map +1 -0
- package/dist/src/Number.js +55 -0
- package/dist/src/Object.d.ts +35 -0
- package/dist/src/Object.d.ts.map +1 -0
- package/dist/src/Object.js +36 -0
- package/dist/src/Order.d.ts +90 -0
- package/dist/src/Order.d.ts.map +1 -0
- package/dist/src/Order.js +85 -0
- package/dist/src/Promise.d.ts +180 -0
- package/dist/src/Promise.d.ts.map +1 -0
- package/dist/src/Promise.js +176 -0
- package/dist/src/Random.d.ts +52 -0
- package/dist/src/Random.d.ts.map +1 -0
- package/dist/src/Random.js +29 -0
- package/dist/src/Ref.d.ts +40 -0
- package/dist/src/Ref.d.ts.map +1 -0
- package/dist/src/Ref.js +13 -0
- package/dist/src/Result.d.ts +421 -0
- package/dist/src/Result.d.ts.map +1 -0
- package/dist/src/Result.js +357 -0
- package/dist/src/Skiplist.d.ts +23 -0
- package/dist/src/Skiplist.d.ts.map +1 -0
- package/dist/src/Skiplist.js +58 -0
- package/dist/src/Sqlite.d.ts +116 -52
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +183 -67
- package/dist/src/Store.d.ts +45 -8
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +33 -17
- package/dist/src/String.d.ts +2 -0
- package/dist/src/String.d.ts.map +1 -0
- package/dist/src/String.js +14 -0
- package/dist/src/Time.d.ts +20 -0
- package/dist/src/Time.d.ts.map +1 -0
- package/dist/src/Time.js +25 -0
- package/dist/src/Type.d.ts +1937 -0
- package/dist/src/Type.d.ts.map +1 -0
- package/dist/src/Type.js +2002 -0
- package/dist/src/Types.d.ts +188 -0
- package/dist/src/Types.d.ts.map +1 -0
- package/dist/src/Types.js +6 -0
- package/dist/src/WebSocket.d.ts +112 -0
- package/dist/src/WebSocket.d.ts.map +1 -0
- package/dist/src/WebSocket.js +139 -0
- package/dist/src/Worker.d.ts +44 -0
- package/dist/src/Worker.d.ts.map +1 -0
- package/dist/src/Worker.js +66 -0
- package/dist/src/index.d.ts +24 -11
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +24 -11
- package/package.json +29 -38
- package/src/Array.ts +39 -0
- package/src/Assert.ts +116 -0
- package/src/BigInt.ts +29 -0
- package/src/Buffer.ts +175 -0
- package/src/Callbacks.ts +43 -0
- package/src/Console.ts +159 -0
- package/src/Crypto.ts +169 -115
- package/src/Eq.ts +204 -0
- package/src/Error.ts +57 -20
- package/src/Evolu/Config.ts +83 -0
- package/src/Evolu/Db.ts +1275 -0
- package/src/Evolu/Diff.ts +142 -0
- package/src/Evolu/Evolu.ts +947 -0
- package/src/Evolu/Internal.ts +26 -0
- package/src/Evolu/Kysely.ts +38 -0
- package/src/Evolu/Owner.ts +296 -0
- package/src/Evolu/Platform.ts +27 -0
- package/src/Evolu/Protocol.ts +1857 -0
- package/src/Evolu/Public.ts +43 -0
- package/src/Evolu/PublicKysely.ts +240 -0
- package/src/Evolu/Query.ts +167 -0
- package/src/Evolu/Relay.ts +142 -0
- package/src/Evolu/Schema.ts +417 -0
- package/src/Evolu/Storage.ts +1281 -0
- package/src/Evolu/Sync.ts +105 -0
- package/src/Evolu/Timestamp.ts +311 -0
- package/src/Function.ts +58 -0
- package/src/ManyToManyMap.ts +140 -0
- package/src/NanoId.ts +39 -0
- package/src/Number.ts +90 -0
- package/src/Object.ts +64 -0
- package/src/Order.ts +113 -0
- package/src/Promise.ts +295 -0
- package/src/Random.ts +68 -0
- package/src/Ref.ts +63 -0
- package/src/Result.ts +453 -0
- package/src/Skiplist.ts +102 -0
- package/src/Sqlite.ts +366 -153
- package/src/Store.ts +79 -36
- package/src/String.ts +10 -0
- package/src/Time.ts +36 -0
- package/src/Type.ts +3978 -0
- package/src/Types.ts +209 -0
- package/src/WebSocket.ts +273 -0
- package/src/Worker.ts +129 -0
- package/src/index.ts +24 -11
- package/dist/src/Config.d.ts +0 -56
- package/dist/src/Config.d.ts.map +0 -1
- package/dist/src/Config.js +0 -39
- package/dist/src/Crdt.d.ts +0 -89
- package/dist/src/Crdt.d.ts.map +0 -1
- package/dist/src/Crdt.js +0 -181
- package/dist/src/Db.d.ts +0 -107
- package/dist/src/Db.d.ts.map +0 -1
- package/dist/src/Db.js +0 -443
- package/dist/src/Diff.d.ts +0 -27
- package/dist/src/Diff.d.ts.map +0 -1
- package/dist/src/Diff.js +0 -84
- package/dist/src/Evolu.d.ts +0 -426
- package/dist/src/Evolu.d.ts.map +0 -1
- package/dist/src/Evolu.js +0 -333
- package/dist/src/Model.d.ts +0 -141
- package/dist/src/Model.d.ts.map +0 -1
- package/dist/src/Model.js +0 -125
- package/dist/src/Murmurhash.d.ts +0 -2
- package/dist/src/Murmurhash.d.ts.map +0 -1
- package/dist/src/Murmurhash.js +0 -60
- package/dist/src/Owner.d.ts +0 -33
- package/dist/src/Owner.d.ts.map +0 -1
- package/dist/src/Owner.js +0 -26
- package/dist/src/Platform.d.ts +0 -37
- package/dist/src/Platform.d.ts.map +0 -1
- package/dist/src/Platform.js +0 -11
- package/dist/src/Protobuf.d.ts +0 -81
- package/dist/src/Protobuf.d.ts.map +0 -1
- package/dist/src/Protobuf.js +0 -92
- package/dist/src/Public.d.ts +0 -13
- package/dist/src/Public.d.ts.map +0 -1
- package/dist/src/Public.js +0 -6
- package/dist/src/Socket.d.ts +0 -8
- package/dist/src/Socket.d.ts.map +0 -1
- package/dist/src/Socket.js +0 -51
- package/dist/src/Sql.d.ts +0 -12
- package/dist/src/Sql.d.ts.map +0 -1
- package/dist/src/Sql.js +0 -30
- package/dist/src/Sync.d.ts +0 -70
- package/dist/src/Sync.d.ts.map +0 -1
- package/dist/src/Sync.js +0 -127
- package/src/Config.ts +0 -119
- package/src/Crdt.ts +0 -361
- package/src/Db.ts +0 -955
- package/src/Diff.ts +0 -114
- package/src/Evolu.ts +0 -1016
- package/src/Model.ts +0 -233
- package/src/Murmurhash.ts +0 -70
- package/src/Owner.ts +0 -69
- package/src/Platform.ts +0 -47
- package/src/Protobuf.ts +0 -155
- package/src/Public.ts +0 -12
- package/src/Socket.ts +0 -83
- package/src/Sql.ts +0 -41
- package/src/Sync.ts +0 -315
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ConsoleConfig, ConsoleDep } from "../Console.js";
|
|
2
|
+
import { ProtocolMessage } from "./Protocol.js";
|
|
3
|
+
import { Millis } from "./Timestamp.js";
|
|
4
|
+
export interface Sync {
|
|
5
|
+
readonly send: (message: ProtocolMessage) => void;
|
|
6
|
+
}
|
|
7
|
+
export interface SyncDep {
|
|
8
|
+
readonly sync: Sync;
|
|
9
|
+
}
|
|
10
|
+
export type CreateSync = (deps: ConsoleDep) => (config: SyncConfig) => Sync;
|
|
11
|
+
export interface CreateSyncDep {
|
|
12
|
+
readonly createSync: CreateSync;
|
|
13
|
+
}
|
|
14
|
+
export interface SyncConfig extends ConsoleConfig {
|
|
15
|
+
readonly syncUrl: string;
|
|
16
|
+
readonly onOpen: (send: Sync["send"]) => void;
|
|
17
|
+
readonly onMessage: (message: Uint8Array, send: Sync["send"]) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const createWebSocketSync: CreateSync;
|
|
20
|
+
/**
|
|
21
|
+
* The possible states of a synchronization process. The `SyncState` can be one
|
|
22
|
+
* of the following:
|
|
23
|
+
*
|
|
24
|
+
* - {@link SyncStateInitial}
|
|
25
|
+
* - {@link SyncStateIsSyncing}
|
|
26
|
+
* - {@link SyncStateIsSynced}
|
|
27
|
+
* - {@link SyncStateIsNotSynced}
|
|
28
|
+
*/
|
|
29
|
+
export type SyncState = SyncStateInitial | SyncStateIsSyncing | SyncStateIsSynced | SyncStateIsNotSynced;
|
|
30
|
+
/**
|
|
31
|
+
* The initial synchronization state when the app starts. In this state, the app
|
|
32
|
+
* needs to determine whether the data is synced.
|
|
33
|
+
*/
|
|
34
|
+
export interface SyncStateInitial {
|
|
35
|
+
readonly type: "SyncStateInitial";
|
|
36
|
+
}
|
|
37
|
+
export interface SyncStateIsSyncing {
|
|
38
|
+
readonly type: "SyncStateIsSyncing";
|
|
39
|
+
}
|
|
40
|
+
export interface SyncStateIsSynced {
|
|
41
|
+
readonly type: "SyncStateIsSynced";
|
|
42
|
+
readonly time: Millis;
|
|
43
|
+
}
|
|
44
|
+
export interface SyncStateIsNotSynced {
|
|
45
|
+
readonly type: "SyncStateIsNotSynced";
|
|
46
|
+
readonly error: NetworkError | ServerError | PaymentRequiredError;
|
|
47
|
+
}
|
|
48
|
+
export interface NetworkError {
|
|
49
|
+
readonly type: "NetworkError";
|
|
50
|
+
}
|
|
51
|
+
export interface ServerError {
|
|
52
|
+
readonly type: "ServerError";
|
|
53
|
+
readonly status: number;
|
|
54
|
+
}
|
|
55
|
+
export interface PaymentRequiredError {
|
|
56
|
+
readonly type: "PaymentRequiredError";
|
|
57
|
+
}
|
|
58
|
+
export declare const initialSyncState: SyncStateInitial;
|
|
59
|
+
//# sourceMappingURL=Sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sync.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;AAE5E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;CACvE;AAED,eAAO,MAAM,mBAAmB,EAAE,UA2BjC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GACjB,gBAAgB,GAChB,kBAAkB,GAClB,iBAAiB,GACjB,oBAAoB,CAAC;AAEzB;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,GAAG,oBAAoB,CAAC;CACnE;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;CACvC;AAED,eAAO,MAAM,gBAAgB,EAAE,gBAA+C,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createWebSocket } from "../WebSocket.js";
|
|
2
|
+
export const createWebSocketSync = (_deps) => (config) => {
|
|
3
|
+
const sync = {
|
|
4
|
+
send: (message) => {
|
|
5
|
+
/**
|
|
6
|
+
* We don't need an in-memory queue; apps can be offline for a long time,
|
|
7
|
+
* and mutations are stored in SQLite. Dropped CRDT messages are synced
|
|
8
|
+
* when the web socket connection is open.
|
|
9
|
+
*/
|
|
10
|
+
if (socket.getReadyState() !== "open")
|
|
11
|
+
return;
|
|
12
|
+
socket.send(message);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
const socket = createWebSocket(config.syncUrl, {
|
|
16
|
+
binaryType: "arraybuffer",
|
|
17
|
+
onOpen: () => {
|
|
18
|
+
config.onOpen(sync.send);
|
|
19
|
+
},
|
|
20
|
+
onMessage: (data) => {
|
|
21
|
+
if (data instanceof ArrayBuffer) {
|
|
22
|
+
const messages = new Uint8Array(data);
|
|
23
|
+
config.onMessage(messages, sync.send);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
return sync;
|
|
28
|
+
};
|
|
29
|
+
export const initialSyncState = { type: "SyncStateInitial" };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { NanoIdLibDep } from "../NanoId.js";
|
|
2
|
+
import { Order } from "../Order.js";
|
|
3
|
+
import { Result } from "../Result.js";
|
|
4
|
+
import { TimeDep } from "../Time.js";
|
|
5
|
+
import { Brand } from "../Types.js";
|
|
6
|
+
export interface TimestampConfig {
|
|
7
|
+
/**
|
|
8
|
+
* Maximum physical clock drift allowed in ms.
|
|
9
|
+
*
|
|
10
|
+
* The default value is 5 * 60 * 1000 (5 minutes).
|
|
11
|
+
*/
|
|
12
|
+
readonly maxDrift: number;
|
|
13
|
+
}
|
|
14
|
+
export interface TimestampConfigDep {
|
|
15
|
+
readonly timestampConfig: TimestampConfig;
|
|
16
|
+
}
|
|
17
|
+
export type TimestampError = TimestampDriftError | TimestampCounterOverflowError | TimestampDuplicateNodeError | TimestampTimeOutOfRangeError;
|
|
18
|
+
export interface TimestampDriftError {
|
|
19
|
+
readonly type: "TimestampDriftError";
|
|
20
|
+
readonly next: Millis;
|
|
21
|
+
readonly now: Millis;
|
|
22
|
+
}
|
|
23
|
+
export interface TimestampCounterOverflowError {
|
|
24
|
+
readonly type: "TimestampCounterOverflowError";
|
|
25
|
+
}
|
|
26
|
+
export interface TimestampDuplicateNodeError {
|
|
27
|
+
readonly type: "TimestampDuplicateNodeError";
|
|
28
|
+
readonly nodeId: NodeId;
|
|
29
|
+
}
|
|
30
|
+
export interface TimestampTimeOutOfRangeError {
|
|
31
|
+
readonly type: "TimestampTimeOutOfRangeError";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Millis is a timestamp in milliseconds, like `Date.now()`, but limited to the
|
|
35
|
+
* maximum value representable in 6 bytes (281474976710655) minus 1 (reserved
|
|
36
|
+
* for infinity). This enables more efficient binary serialization, saving 2
|
|
37
|
+
* bytes compared to the typical 8-byte (64-bit) timestamp representation.
|
|
38
|
+
*
|
|
39
|
+
* This limit is enforced to prevent data corruption. If a device's clock
|
|
40
|
+
* exceeds this range, Evolu will stop saving data until the clock is
|
|
41
|
+
* corrected.
|
|
42
|
+
*
|
|
43
|
+
* `new Date(281474976710654).toString()` = Tue Aug 02 10889 07:31:49
|
|
44
|
+
*/
|
|
45
|
+
export declare const Millis: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & Brand<"Int"> & Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & Brand<"Int">, import("../Type.js").NumberError | import("../Type.js").IntError>, `LessThanOrEqualTo${number}`, import("../Type.js").LessThanOrEqualToError<number>, import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError>, "Millis", import("../Type.js").BrandWithoutRefineError<"Millis", import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").LessThanOrEqualToError<number>>, never>;
|
|
46
|
+
export type Millis = typeof Millis.Type;
|
|
47
|
+
export declare const minMillis: Millis;
|
|
48
|
+
export declare const maxMillis: Millis;
|
|
49
|
+
export declare const Counter: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & Brand<"Int"> & Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & Brand<"Int">, import("../Type.js").NumberError | import("../Type.js").IntError>, "LessThanOrEqualTo65535", import("../Type.js").LessThanOrEqualToError<65535>, import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError>, "Counter", import("../Type.js").BrandWithoutRefineError<"Counter", import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").LessThanOrEqualToError<65535>>, never>;
|
|
50
|
+
export type Counter = typeof Counter.Type;
|
|
51
|
+
export declare const minCounter: Counter;
|
|
52
|
+
export declare const maxCounter: Counter;
|
|
53
|
+
/**
|
|
54
|
+
* A NodeId uniquely identifies an owner's device. Generated once per device
|
|
55
|
+
* using cryptographic randomness.
|
|
56
|
+
*
|
|
57
|
+
* Collision probability (birthday paradox):
|
|
58
|
+
*
|
|
59
|
+
* - 1,000 devices: ~0.00000000000271% (negligible).
|
|
60
|
+
* - 1M devices: ~0.00000271% (1 in 37M chance).
|
|
61
|
+
* - 135M devices: ~1% chance.
|
|
62
|
+
* - 4.29B devices: ~50% chance.
|
|
63
|
+
*
|
|
64
|
+
* https://lemire.me/blog/2019/12/12/are-64-bit-random-identifiers-free-from-collision
|
|
65
|
+
*
|
|
66
|
+
* What will happen if a different device generates the same NodeId?
|
|
67
|
+
*
|
|
68
|
+
* If the device belongs to a different owner, nothing will happen because
|
|
69
|
+
* different owner have different owner IDs. Timestamps are partitioned by
|
|
70
|
+
* OwnerId.
|
|
71
|
+
*
|
|
72
|
+
* If the device belongs to the same owner, the other device will return
|
|
73
|
+
* {@link TimestampDuplicateNodeError}.
|
|
74
|
+
*/
|
|
75
|
+
export declare const NodeId: import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "NodeId", import("../Type.js").RegexError<"NodeId">, import("../Type.js").StringError>;
|
|
76
|
+
export type NodeId = typeof NodeId.Type;
|
|
77
|
+
export declare const minNodeId: NodeId;
|
|
78
|
+
export declare const maxNodeId: NodeId;
|
|
79
|
+
/**
|
|
80
|
+
* Hybrid Logical Clock timestamp.
|
|
81
|
+
*
|
|
82
|
+
* - https://muratbuffalo.blogspot.com/2014/07/hybrid-logical-clocks.html
|
|
83
|
+
* - https://sergeiturukin.com/2017/06/26/hybrid-logical-clocks.html
|
|
84
|
+
* - https://jaredforsyth.com/posts/hybrid-logical-clocks/
|
|
85
|
+
*/
|
|
86
|
+
export declare const Timestamp: import("../Type.js").ObjectType<{
|
|
87
|
+
millis: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & Brand<"Int"> & Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & Brand<"Int">, import("../Type.js").NumberError | import("../Type.js").IntError>, `LessThanOrEqualTo${number}`, import("../Type.js").LessThanOrEqualToError<number>, import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError>, "Millis", import("../Type.js").BrandWithoutRefineError<"Millis", import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").LessThanOrEqualToError<number>>, never>;
|
|
88
|
+
counter: import("../Type.js").BrandType<import("../Type.js").BrandType<import("../Type.js").Type<"Brand", number & Brand<"Int"> & Brand<"NonNegative">, number, import("../Type.js").NonNegativeError, number & Brand<"Int">, import("../Type.js").NumberError | import("../Type.js").IntError>, "LessThanOrEqualTo65535", import("../Type.js").LessThanOrEqualToError<65535>, import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError>, "Counter", import("../Type.js").BrandWithoutRefineError<"Counter", import("../Type.js").NumberError | import("../Type.js").NonNegativeError | import("../Type.js").IntError | import("../Type.js").LessThanOrEqualToError<65535>>, never>;
|
|
89
|
+
nodeId: import("../Type.js").BrandType<import("../Type.js").Type<"String", string, string, import("../Type.js").StringError, string, import("../Type.js").StringError>, "NodeId", import("../Type.js").RegexError<"NodeId">, import("../Type.js").StringError>;
|
|
90
|
+
}>;
|
|
91
|
+
export type Timestamp = typeof Timestamp.Type;
|
|
92
|
+
export declare const createTimestamp: ({ millis, counter, nodeId, }?: Partial<Timestamp>) => Timestamp;
|
|
93
|
+
export declare const createInitialTimestamp: (deps: NanoIdLibDep) => Timestamp;
|
|
94
|
+
/** TimestampString is a sortable string version of {@link Timestamp}. */
|
|
95
|
+
export type TimestampString = string & Brand<"TimestampString">;
|
|
96
|
+
export declare const timestampToTimestampString: (t: Timestamp) => TimestampString;
|
|
97
|
+
export declare const timestampStringToTimestamp: (timestampString: TimestampString) => Timestamp;
|
|
98
|
+
export declare const sendTimestamp: (deps: TimeDep & TimestampConfigDep) => (timestamp: Timestamp) => Result<Timestamp, TimestampDriftError | TimestampCounterOverflowError | TimestampTimeOutOfRangeError>;
|
|
99
|
+
export declare const receiveTimestamp: (deps: TimeDep & TimestampConfigDep) => (local: Timestamp, remote: Timestamp) => Result<Timestamp, TimestampDriftError | TimestampCounterOverflowError | TimestampDuplicateNodeError | TimestampTimeOutOfRangeError>;
|
|
100
|
+
/** BinaryTimestamp is a binary and sortable version of {@link Timestamp} for DB. */
|
|
101
|
+
export type BinaryTimestamp = Uint8Array & Brand<"BinaryTimestamp">;
|
|
102
|
+
export declare const binaryTimestampLength: number & Brand<"Int"> & Brand<"NonNegative">;
|
|
103
|
+
export declare const timestampToBinaryTimestamp: (timestamp: Timestamp) => BinaryTimestamp;
|
|
104
|
+
export declare const binaryTimestampToTimestamp: (timestamp: BinaryTimestamp) => Timestamp;
|
|
105
|
+
export declare const orderBinaryTimestamp: Order<BinaryTimestamp>;
|
|
106
|
+
//# sourceMappingURL=Timestamp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Timestamp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { assert } from "../Assert.js";
|
|
2
|
+
import { increment } from "../Number.js";
|
|
3
|
+
import { orderUint8Array } from "../Order.js";
|
|
4
|
+
import { err, getOrThrow, ok } from "../Result.js";
|
|
5
|
+
import { brand, lessThanOrEqualTo, NonNegativeInt, object, regex, String, } from "../Type.js";
|
|
6
|
+
/**
|
|
7
|
+
* Millis is a timestamp in milliseconds, like `Date.now()`, but limited to the
|
|
8
|
+
* maximum value representable in 6 bytes (281474976710655) minus 1 (reserved
|
|
9
|
+
* for infinity). This enables more efficient binary serialization, saving 2
|
|
10
|
+
* bytes compared to the typical 8-byte (64-bit) timestamp representation.
|
|
11
|
+
*
|
|
12
|
+
* This limit is enforced to prevent data corruption. If a device's clock
|
|
13
|
+
* exceeds this range, Evolu will stop saving data until the clock is
|
|
14
|
+
* corrected.
|
|
15
|
+
*
|
|
16
|
+
* `new Date(281474976710654).toString()` = Tue Aug 02 10889 07:31:49
|
|
17
|
+
*/
|
|
18
|
+
export const Millis = brand("Millis", lessThanOrEqualTo(281474976710655 - 1)(NonNegativeInt));
|
|
19
|
+
export const minMillis = 0;
|
|
20
|
+
export const maxMillis = (281474976710655 - 1);
|
|
21
|
+
export const Counter = brand("Counter", lessThanOrEqualTo(65535)(NonNegativeInt));
|
|
22
|
+
export const minCounter = 0;
|
|
23
|
+
export const maxCounter = 65535;
|
|
24
|
+
/**
|
|
25
|
+
* A NodeId uniquely identifies an owner's device. Generated once per device
|
|
26
|
+
* using cryptographic randomness.
|
|
27
|
+
*
|
|
28
|
+
* Collision probability (birthday paradox):
|
|
29
|
+
*
|
|
30
|
+
* - 1,000 devices: ~0.00000000000271% (negligible).
|
|
31
|
+
* - 1M devices: ~0.00000271% (1 in 37M chance).
|
|
32
|
+
* - 135M devices: ~1% chance.
|
|
33
|
+
* - 4.29B devices: ~50% chance.
|
|
34
|
+
*
|
|
35
|
+
* https://lemire.me/blog/2019/12/12/are-64-bit-random-identifiers-free-from-collision
|
|
36
|
+
*
|
|
37
|
+
* What will happen if a different device generates the same NodeId?
|
|
38
|
+
*
|
|
39
|
+
* If the device belongs to a different owner, nothing will happen because
|
|
40
|
+
* different owner have different owner IDs. Timestamps are partitioned by
|
|
41
|
+
* OwnerId.
|
|
42
|
+
*
|
|
43
|
+
* If the device belongs to the same owner, the other device will return
|
|
44
|
+
* {@link TimestampDuplicateNodeError}.
|
|
45
|
+
*/
|
|
46
|
+
export const NodeId = regex("NodeId", /^[a-f0-9]{16}$/)(String);
|
|
47
|
+
export const minNodeId = "0000000000000000";
|
|
48
|
+
export const maxNodeId = "ffffffffffffffff";
|
|
49
|
+
/**
|
|
50
|
+
* Hybrid Logical Clock timestamp.
|
|
51
|
+
*
|
|
52
|
+
* - https://muratbuffalo.blogspot.com/2014/07/hybrid-logical-clocks.html
|
|
53
|
+
* - https://sergeiturukin.com/2017/06/26/hybrid-logical-clocks.html
|
|
54
|
+
* - https://jaredforsyth.com/posts/hybrid-logical-clocks/
|
|
55
|
+
*/
|
|
56
|
+
export const Timestamp = object({
|
|
57
|
+
millis: Millis,
|
|
58
|
+
counter: Counter,
|
|
59
|
+
nodeId: NodeId,
|
|
60
|
+
});
|
|
61
|
+
export const createTimestamp = ({ millis = minMillis, counter = minCounter, nodeId = minNodeId, } = {}) => ({ millis, counter, nodeId });
|
|
62
|
+
const hexAlphabet = "0123456789abcdef";
|
|
63
|
+
export const createInitialTimestamp = (deps) => {
|
|
64
|
+
const nodeId = deps.nanoIdLib.customAlphabet(hexAlphabet, 16)();
|
|
65
|
+
return createTimestamp({ nodeId });
|
|
66
|
+
};
|
|
67
|
+
export const timestampToTimestampString = (t) => [
|
|
68
|
+
new Date(t.millis).toISOString(),
|
|
69
|
+
t.counter.toString(16).toUpperCase().padStart(4, "0"),
|
|
70
|
+
t.nodeId,
|
|
71
|
+
].join("-");
|
|
72
|
+
export const timestampStringToTimestamp = (timestampString) => {
|
|
73
|
+
const array = timestampString.split("-");
|
|
74
|
+
const timestamp = {
|
|
75
|
+
millis: Date.parse(array.slice(0, 3).join("-")).valueOf(),
|
|
76
|
+
counter: parseInt(array[3], 16),
|
|
77
|
+
nodeId: array[4],
|
|
78
|
+
};
|
|
79
|
+
assert(Timestamp.is(timestamp), "timestampString is malformed");
|
|
80
|
+
return timestamp;
|
|
81
|
+
};
|
|
82
|
+
const getNextMillis = (deps) => (millis) => {
|
|
83
|
+
const now = Millis.from(deps.time.now());
|
|
84
|
+
if (!now.ok) {
|
|
85
|
+
return err({ type: "TimestampTimeOutOfRangeError" });
|
|
86
|
+
}
|
|
87
|
+
const next = Math.max(now.value, ...millis);
|
|
88
|
+
return next - now.value > deps.timestampConfig.maxDrift
|
|
89
|
+
? err({
|
|
90
|
+
type: "TimestampDriftError",
|
|
91
|
+
now: now.value,
|
|
92
|
+
next,
|
|
93
|
+
})
|
|
94
|
+
: ok(next);
|
|
95
|
+
};
|
|
96
|
+
const incrementCounter = (counter) => {
|
|
97
|
+
const next = Counter.from(increment(counter));
|
|
98
|
+
if (!next.ok)
|
|
99
|
+
return err({ type: "TimestampCounterOverflowError" });
|
|
100
|
+
return ok(next.value);
|
|
101
|
+
};
|
|
102
|
+
export const sendTimestamp = (deps) => (timestamp) => {
|
|
103
|
+
const millis = getNextMillis(deps)([timestamp.millis]);
|
|
104
|
+
if (!millis.ok)
|
|
105
|
+
return millis;
|
|
106
|
+
const counter = millis.value === timestamp.millis
|
|
107
|
+
? incrementCounter(timestamp.counter)
|
|
108
|
+
: ok(minCounter);
|
|
109
|
+
if (!counter.ok)
|
|
110
|
+
return counter;
|
|
111
|
+
return ok({
|
|
112
|
+
millis: millis.value,
|
|
113
|
+
counter: counter.value,
|
|
114
|
+
nodeId: timestamp.nodeId,
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
export const receiveTimestamp = (deps) => (local, remote) => {
|
|
118
|
+
if (local.nodeId === remote.nodeId) {
|
|
119
|
+
return err({ type: "TimestampDuplicateNodeError", nodeId: local.nodeId });
|
|
120
|
+
}
|
|
121
|
+
const millis = getNextMillis(deps)([local.millis, remote.millis]);
|
|
122
|
+
if (!millis.ok)
|
|
123
|
+
return millis;
|
|
124
|
+
const counter = millis.value === local.millis && millis.value === remote.millis
|
|
125
|
+
? incrementCounter(Math.max(local.counter, remote.counter))
|
|
126
|
+
: millis.value === local.millis
|
|
127
|
+
? incrementCounter(local.counter)
|
|
128
|
+
: millis.value === remote.millis
|
|
129
|
+
? incrementCounter(remote.counter)
|
|
130
|
+
: ok(minCounter);
|
|
131
|
+
if (!counter.ok)
|
|
132
|
+
return counter;
|
|
133
|
+
return ok({
|
|
134
|
+
millis: millis.value,
|
|
135
|
+
counter: counter.value,
|
|
136
|
+
nodeId: local.nodeId,
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
export const binaryTimestampLength = getOrThrow(NonNegativeInt.from(16));
|
|
140
|
+
export const timestampToBinaryTimestamp = (timestamp) => {
|
|
141
|
+
const { millis, counter, nodeId } = timestamp;
|
|
142
|
+
// 6 bytes for millis, 2 bytes for counter, 8 bytes for nodeId.
|
|
143
|
+
const value = new Uint8Array(16);
|
|
144
|
+
// Encode `millis` into the first 6 bytes.
|
|
145
|
+
const millisBigInt = BigInt(millis);
|
|
146
|
+
value[0] = Number((millisBigInt >> 40n) & 0xffn);
|
|
147
|
+
value[1] = Number((millisBigInt >> 32n) & 0xffn);
|
|
148
|
+
value[2] = Number((millisBigInt >> 24n) & 0xffn);
|
|
149
|
+
value[3] = Number((millisBigInt >> 16n) & 0xffn);
|
|
150
|
+
value[4] = Number((millisBigInt >> 8n) & 0xffn);
|
|
151
|
+
value[5] = Number(millisBigInt & 0xffn);
|
|
152
|
+
// Encode `counter` into the next 2 bytes.
|
|
153
|
+
value[6] = (counter >> 8) & 0xff;
|
|
154
|
+
value[7] = counter & 0xff;
|
|
155
|
+
// Encode `nodeId` (16-character hex string) into the next 8 bytes.
|
|
156
|
+
for (let i = 0; i < 8; i++) {
|
|
157
|
+
const byte = parseInt(nodeId.slice(i * 2, i * 2 + 2), 16);
|
|
158
|
+
value[8 + i] = byte;
|
|
159
|
+
}
|
|
160
|
+
return value;
|
|
161
|
+
};
|
|
162
|
+
export const binaryTimestampToTimestamp = (timestamp) => {
|
|
163
|
+
// Decode `millis` from the first 6 bytes.
|
|
164
|
+
const millis = (BigInt(timestamp[0]) << 40n) |
|
|
165
|
+
(BigInt(timestamp[1]) << 32n) |
|
|
166
|
+
(BigInt(timestamp[2]) << 24n) |
|
|
167
|
+
(BigInt(timestamp[3]) << 16n) |
|
|
168
|
+
(BigInt(timestamp[4]) << 8n) |
|
|
169
|
+
BigInt(timestamp[5]);
|
|
170
|
+
// Decode `counter` from the next 2 bytes.
|
|
171
|
+
const counter = (timestamp[6] << 8) | timestamp[7];
|
|
172
|
+
// Decode `nodeId` from the last 8 bytes.
|
|
173
|
+
let nodeId = "";
|
|
174
|
+
for (let i = 8; i < 16; i++) {
|
|
175
|
+
nodeId += timestamp[i].toString(16).padStart(2, "0");
|
|
176
|
+
}
|
|
177
|
+
return { millis: Number(millis), counter, nodeId };
|
|
178
|
+
};
|
|
179
|
+
export const orderBinaryTimestamp = orderUint8Array;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to ensure exhaustive matching in a switch statement. Throws
|
|
3
|
+
* an error if an unhandled case is encountered.
|
|
4
|
+
*
|
|
5
|
+
* Remember, it's useful only when we don't return anything from the switch
|
|
6
|
+
* statement. Otherwise, a return type of a function is enough.
|
|
7
|
+
*
|
|
8
|
+
* ### Example
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* type Color = "red" | "green" | "blue";
|
|
12
|
+
*
|
|
13
|
+
* function handleColor(color: Color): void {
|
|
14
|
+
* switch (color) {
|
|
15
|
+
* case "red":
|
|
16
|
+
* console.log("Handling red");
|
|
17
|
+
* break;
|
|
18
|
+
* case "green":
|
|
19
|
+
* console.log("Handling green");
|
|
20
|
+
* break;
|
|
21
|
+
* case "blue":
|
|
22
|
+
* console.log("Handling blue");
|
|
23
|
+
* break;
|
|
24
|
+
* default:
|
|
25
|
+
* exhaustiveCheck(color); // Ensures all cases are handled
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare const exhaustiveCheck: (value: never) => never;
|
|
31
|
+
export declare const identity: <A>(a: A) => A;
|
|
32
|
+
/**
|
|
33
|
+
* A function that delays computation and returns a value of type T.
|
|
34
|
+
*
|
|
35
|
+
* Useful for:
|
|
36
|
+
*
|
|
37
|
+
* - Lazy evaluation
|
|
38
|
+
* - Returning constant values
|
|
39
|
+
* - Providing default or placeholder behaviors
|
|
40
|
+
*
|
|
41
|
+
* ### Example
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* const getRandomNumber: LazyValue<number> = () => Math.random();
|
|
45
|
+
* const randomValue = getRandomNumber();
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export type LazyValue<T> = () => T;
|
|
49
|
+
export declare const constVoid: LazyValue<void>;
|
|
50
|
+
export declare const constUndefined: LazyValue<undefined>;
|
|
51
|
+
export declare const constNull: LazyValue<null>;
|
|
52
|
+
export declare const constTrue: LazyValue<true>;
|
|
53
|
+
export declare const constFalse: LazyValue<false>;
|
|
54
|
+
//# sourceMappingURL=Function.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Function.d.ts","sourceRoot":"","sources":["../../src/Function.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,KAAK,KAAG,KAE9C,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,GAAG,CAAC,KAAG,CAAM,CAAC;AAE1C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AAEnC,eAAO,MAAM,SAAS,EAAE,SAAS,CAAC,IAAI,CAAmB,CAAC;AAC1D,eAAO,MAAM,cAAc,EAAE,SAAS,CAAC,SAAS,CAAmB,CAAC;AACpE,eAAO,MAAM,SAAS,EAAE,SAAS,CAAC,IAAI,CAAc,CAAC;AACrD,eAAO,MAAM,SAAS,EAAE,SAAS,CAAC,IAAI,CAAc,CAAC;AACrD,eAAO,MAAM,UAAU,EAAE,SAAS,CAAC,KAAK,CAAe,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to ensure exhaustive matching in a switch statement. Throws
|
|
3
|
+
* an error if an unhandled case is encountered.
|
|
4
|
+
*
|
|
5
|
+
* Remember, it's useful only when we don't return anything from the switch
|
|
6
|
+
* statement. Otherwise, a return type of a function is enough.
|
|
7
|
+
*
|
|
8
|
+
* ### Example
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* type Color = "red" | "green" | "blue";
|
|
12
|
+
*
|
|
13
|
+
* function handleColor(color: Color): void {
|
|
14
|
+
* switch (color) {
|
|
15
|
+
* case "red":
|
|
16
|
+
* console.log("Handling red");
|
|
17
|
+
* break;
|
|
18
|
+
* case "green":
|
|
19
|
+
* console.log("Handling green");
|
|
20
|
+
* break;
|
|
21
|
+
* case "blue":
|
|
22
|
+
* console.log("Handling blue");
|
|
23
|
+
* break;
|
|
24
|
+
* default:
|
|
25
|
+
* exhaustiveCheck(color); // Ensures all cases are handled
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export const exhaustiveCheck = (value) => {
|
|
31
|
+
throw new Error(`exhaustiveCheck unhandled case: ${JSON.stringify(value)}`);
|
|
32
|
+
};
|
|
33
|
+
export const identity = (a) => a;
|
|
34
|
+
export const constVoid = () => undefined;
|
|
35
|
+
export const constUndefined = () => undefined;
|
|
36
|
+
export const constNull = () => null;
|
|
37
|
+
export const constTrue = () => true;
|
|
38
|
+
export const constFalse = () => false;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Represents a many-to-many mapping between keys and values. */
|
|
2
|
+
export interface ManyToManyMap<K, V> {
|
|
3
|
+
/** Adds a key-value association to the map. */
|
|
4
|
+
add: (key: K, value: V) => ManyToManyMap<K, V>;
|
|
5
|
+
/** Removes a specific key-value association. */
|
|
6
|
+
remove: (key: K, value: V) => boolean;
|
|
7
|
+
/** Gets all values associated with a key. */
|
|
8
|
+
getValues: (key: K) => Set<V> | undefined;
|
|
9
|
+
/** Gets all keys associated with a value. */
|
|
10
|
+
getKeys: (value: V) => Set<K> | undefined;
|
|
11
|
+
/** Checks if a specific key-value pair exists. */
|
|
12
|
+
hasPair: (key: K, value: V) => boolean;
|
|
13
|
+
/** Checks if a key exists in the map. */
|
|
14
|
+
hasKey(key: K): boolean;
|
|
15
|
+
/** Checks if a value exists in the map. */
|
|
16
|
+
hasValue: (value: V) => boolean;
|
|
17
|
+
/** Deletes all associations for a key. */
|
|
18
|
+
deleteKey: (key: K) => boolean;
|
|
19
|
+
/** Deletes all associations for a value. */
|
|
20
|
+
deleteValue: (value: V) => boolean;
|
|
21
|
+
/** Clears all associations in the map. */
|
|
22
|
+
clear(): void;
|
|
23
|
+
}
|
|
24
|
+
/** Creates a {@link ManyToManyMap}. */
|
|
25
|
+
export declare const createManyToManyMap: <K, V>() => ManyToManyMap<K, V>;
|
|
26
|
+
//# sourceMappingURL=ManyToManyMap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManyToManyMap.d.ts","sourceRoot":"","sources":["../../src/ManyToManyMap.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,CAAC;IACjC,+CAA+C;IAC/C,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE/C,gDAAgD;IAChD,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEtC,6CAA6C;IAC7C,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE1C,6CAA6C;IAC7C,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE1C,kDAAkD;IAClD,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEvC,yCAAyC;IACzC,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC;IAExB,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEhC,0CAA0C;IAC1C,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAE/B,4CAA4C;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEnC,0CAA0C;IAC1C,KAAK,IAAI,IAAI,CAAC;CACf;AAED,uCAAuC;AACvC,eAAO,MAAM,mBAAmB,GAAI,CAAC,EAAE,CAAC,OAAK,aAAa,CAAC,CAAC,EAAE,CAAC,CAyG9D,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Creates a {@link ManyToManyMap}. */
|
|
2
|
+
export const createManyToManyMap = () => {
|
|
3
|
+
const forwardMap = new Map();
|
|
4
|
+
const reverseMap = new Map();
|
|
5
|
+
const map = {
|
|
6
|
+
add(key, value) {
|
|
7
|
+
let values = forwardMap.get(key);
|
|
8
|
+
if (!values) {
|
|
9
|
+
values = new Set();
|
|
10
|
+
forwardMap.set(key, values);
|
|
11
|
+
}
|
|
12
|
+
values.add(value);
|
|
13
|
+
let keys = reverseMap.get(value);
|
|
14
|
+
if (!keys) {
|
|
15
|
+
keys = new Set();
|
|
16
|
+
reverseMap.set(value, keys);
|
|
17
|
+
}
|
|
18
|
+
keys.add(key);
|
|
19
|
+
return map;
|
|
20
|
+
},
|
|
21
|
+
remove(key, value) {
|
|
22
|
+
const values = forwardMap.get(key);
|
|
23
|
+
if (!values?.has(value))
|
|
24
|
+
return false;
|
|
25
|
+
values.delete(value);
|
|
26
|
+
if (values.size === 0) {
|
|
27
|
+
forwardMap.delete(key);
|
|
28
|
+
}
|
|
29
|
+
const keys = reverseMap.get(value);
|
|
30
|
+
if (keys?.size) {
|
|
31
|
+
keys.delete(key);
|
|
32
|
+
if (keys.size === 0) {
|
|
33
|
+
reverseMap.delete(value);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
},
|
|
38
|
+
getValues(key) {
|
|
39
|
+
return forwardMap.get(key);
|
|
40
|
+
},
|
|
41
|
+
getKeys(value) {
|
|
42
|
+
return reverseMap.get(value);
|
|
43
|
+
},
|
|
44
|
+
hasPair(key, value) {
|
|
45
|
+
const values = forwardMap.get(key);
|
|
46
|
+
return values?.has(value) ?? false;
|
|
47
|
+
},
|
|
48
|
+
hasKey(key) {
|
|
49
|
+
return forwardMap.has(key);
|
|
50
|
+
},
|
|
51
|
+
hasValue(value) {
|
|
52
|
+
return reverseMap.has(value);
|
|
53
|
+
},
|
|
54
|
+
deleteKey(key) {
|
|
55
|
+
const values = forwardMap.get(key);
|
|
56
|
+
if (!values)
|
|
57
|
+
return false;
|
|
58
|
+
for (const value of values) {
|
|
59
|
+
const keys = reverseMap.get(value);
|
|
60
|
+
if (keys) {
|
|
61
|
+
keys.delete(key);
|
|
62
|
+
if (keys.size === 0) {
|
|
63
|
+
reverseMap.delete(value);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
forwardMap.delete(key);
|
|
68
|
+
return true;
|
|
69
|
+
},
|
|
70
|
+
deleteValue(value) {
|
|
71
|
+
const keys = reverseMap.get(value);
|
|
72
|
+
if (!keys)
|
|
73
|
+
return false;
|
|
74
|
+
for (const key of keys) {
|
|
75
|
+
const values = forwardMap.get(key);
|
|
76
|
+
if (values) {
|
|
77
|
+
values.delete(value);
|
|
78
|
+
if (values.size === 0) {
|
|
79
|
+
forwardMap.delete(key);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
reverseMap.delete(value);
|
|
84
|
+
return true;
|
|
85
|
+
},
|
|
86
|
+
clear() {
|
|
87
|
+
forwardMap.clear();
|
|
88
|
+
reverseMap.clear();
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
return map;
|
|
92
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface representing a NanoId library.
|
|
3
|
+
*
|
|
4
|
+
* It's useful for testing by allowing ID generation to be mocked, ensuring
|
|
5
|
+
* consistent results.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/ai/nanoid
|
|
8
|
+
*
|
|
9
|
+
* ### Example
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const foo = createFoo({
|
|
13
|
+
* ...createNanoIdLib(),
|
|
14
|
+
* ...createTime(),
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export interface NanoIdLib {
|
|
19
|
+
readonly urlAlphabet: string;
|
|
20
|
+
readonly customAlphabet: (alphabet: string, defaultSize?: number) => (size?: number) => string;
|
|
21
|
+
readonly nanoid: (size?: number) => string;
|
|
22
|
+
}
|
|
23
|
+
export interface NanoIdLibDep {
|
|
24
|
+
readonly nanoIdLib: NanoIdLib;
|
|
25
|
+
}
|
|
26
|
+
export declare const createNanoIdLib: () => NanoIdLib;
|
|
27
|
+
//# sourceMappingURL=NanoId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NanoId.d.ts","sourceRoot":"","sources":["../../src/NanoId.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,QAAQ,CAAC,cAAc,EAAE,CACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,KACjB,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAE/B,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CAC5C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B;AAED,eAAO,MAAM,eAAe,QAAO,SAIjC,CAAC"}
|