cojson 0.13.10 → 0.13.12

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.
Files changed (102) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +15 -0
  3. package/dist/CoValuesStore.d.ts +3 -1
  4. package/dist/CoValuesStore.d.ts.map +1 -1
  5. package/dist/CoValuesStore.js +7 -6
  6. package/dist/CoValuesStore.js.map +1 -1
  7. package/dist/PeerKnownStates.d.ts +5 -25
  8. package/dist/PeerKnownStates.d.ts.map +1 -1
  9. package/dist/PeerKnownStates.js +7 -20
  10. package/dist/PeerKnownStates.js.map +1 -1
  11. package/dist/PeerState.d.ts +14 -9
  12. package/dist/PeerState.d.ts.map +1 -1
  13. package/dist/PeerState.js +51 -8
  14. package/dist/PeerState.js.map +1 -1
  15. package/dist/SyncStateManager.js +2 -2
  16. package/dist/SyncStateManager.js.map +1 -1
  17. package/dist/coValueCore.js +2 -2
  18. package/dist/coValueCore.js.map +1 -1
  19. package/dist/coValueState.d.ts +21 -46
  20. package/dist/coValueState.d.ts.map +1 -1
  21. package/dist/coValueState.js +174 -246
  22. package/dist/coValueState.js.map +1 -1
  23. package/dist/coValues/coList.d.ts +13 -2
  24. package/dist/coValues/coList.d.ts.map +1 -1
  25. package/dist/coValues/coList.js +60 -34
  26. package/dist/coValues/coList.js.map +1 -1
  27. package/dist/coValues/coPlainText.d.ts +45 -0
  28. package/dist/coValues/coPlainText.d.ts.map +1 -1
  29. package/dist/coValues/coPlainText.js +61 -11
  30. package/dist/coValues/coPlainText.js.map +1 -1
  31. package/dist/coValues/group.js +2 -2
  32. package/dist/coValues/group.js.map +1 -1
  33. package/dist/exports.d.ts +2 -4
  34. package/dist/exports.d.ts.map +1 -1
  35. package/dist/exports.js +1 -2
  36. package/dist/exports.js.map +1 -1
  37. package/dist/localNode.d.ts.map +1 -1
  38. package/dist/localNode.js +20 -16
  39. package/dist/localNode.js.map +1 -1
  40. package/dist/sync.d.ts.map +1 -1
  41. package/dist/sync.js +40 -92
  42. package/dist/sync.js.map +1 -1
  43. package/dist/tests/PeerKnownStates.test.js +9 -14
  44. package/dist/tests/PeerKnownStates.test.js.map +1 -1
  45. package/dist/tests/PeerState.test.js +22 -34
  46. package/dist/tests/PeerState.test.js.map +1 -1
  47. package/dist/tests/coList.test.js +63 -0
  48. package/dist/tests/coList.test.js.map +1 -1
  49. package/dist/tests/coPlainText.test.js +66 -11
  50. package/dist/tests/coPlainText.test.js.map +1 -1
  51. package/dist/tests/coValueState.test.js +57 -104
  52. package/dist/tests/coValueState.test.js.map +1 -1
  53. package/dist/tests/group.test.js +1 -2
  54. package/dist/tests/group.test.js.map +1 -1
  55. package/dist/tests/messagesTestUtils.d.ts +4 -1
  56. package/dist/tests/messagesTestUtils.d.ts.map +1 -1
  57. package/dist/tests/messagesTestUtils.js +10 -0
  58. package/dist/tests/messagesTestUtils.js.map +1 -1
  59. package/dist/tests/sync.mesh.test.js +65 -3
  60. package/dist/tests/sync.mesh.test.js.map +1 -1
  61. package/dist/tests/sync.peerReconciliation.test.js +8 -8
  62. package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
  63. package/dist/tests/sync.test.js +6 -4
  64. package/dist/tests/sync.test.js.map +1 -1
  65. package/package.json +1 -1
  66. package/src/CoValuesStore.ts +9 -6
  67. package/src/PeerKnownStates.ts +19 -56
  68. package/src/PeerState.ts +69 -13
  69. package/src/SyncStateManager.ts +2 -2
  70. package/src/coValueCore.ts +2 -2
  71. package/src/coValueState.ts +197 -317
  72. package/src/coValues/coList.ts +84 -44
  73. package/src/coValues/coPlainText.ts +75 -11
  74. package/src/coValues/group.ts +2 -2
  75. package/src/exports.ts +0 -6
  76. package/src/localNode.ts +30 -21
  77. package/src/sync.ts +46 -95
  78. package/src/tests/PeerKnownStates.test.ts +9 -14
  79. package/src/tests/PeerState.test.ts +27 -40
  80. package/src/tests/coList.test.ts +83 -0
  81. package/src/tests/coPlainText.test.ts +81 -11
  82. package/src/tests/coValueState.test.ts +55 -106
  83. package/src/tests/group.test.ts +2 -2
  84. package/src/tests/messagesTestUtils.ts +12 -1
  85. package/src/tests/sync.mesh.test.ts +81 -3
  86. package/src/tests/sync.peerReconciliation.test.ts +8 -8
  87. package/src/tests/sync.test.ts +8 -23
  88. package/dist/storage/FileSystem.d.ts +0 -37
  89. package/dist/storage/FileSystem.d.ts.map +0 -1
  90. package/dist/storage/FileSystem.js +0 -48
  91. package/dist/storage/FileSystem.js.map +0 -1
  92. package/dist/storage/chunksAndKnownStates.d.ts +0 -7
  93. package/dist/storage/chunksAndKnownStates.d.ts.map +0 -1
  94. package/dist/storage/chunksAndKnownStates.js +0 -98
  95. package/dist/storage/chunksAndKnownStates.js.map +0 -1
  96. package/dist/storage/index.d.ts +0 -52
  97. package/dist/storage/index.d.ts.map +0 -1
  98. package/dist/storage/index.js +0 -335
  99. package/dist/storage/index.js.map +0 -1
  100. package/src/storage/FileSystem.ts +0 -113
  101. package/src/storage/chunksAndKnownStates.ts +0 -137
  102. package/src/storage/index.ts +0 -531
@@ -1,113 +0,0 @@
1
- import { CryptoProvider, StreamingHash } from "../crypto/crypto.js";
2
- import { RawCoID } from "../ids.js";
3
- import { CoValueChunk } from "./index.js";
4
-
5
- export type BlockFilename = `L${number}-${string}-${string}-H${number}.jsonl`;
6
-
7
- export type BlockHeader = { id: RawCoID; start: number; length: number }[];
8
-
9
- export type WalEntry = { id: RawCoID } & CoValueChunk;
10
-
11
- export type WalFilename = `wal-${number}.jsonl`;
12
-
13
- export interface FileSystem<WriteHandle, ReadHandle> {
14
- crypto: CryptoProvider;
15
- createFile(filename: string): Promise<WriteHandle>;
16
- append(handle: WriteHandle, data: Uint8Array): Promise<void>;
17
- close(handle: ReadHandle | WriteHandle): Promise<void>;
18
- closeAndRename(handle: WriteHandle, filename: BlockFilename): Promise<void>;
19
- openToRead(filename: string): Promise<{ handle: ReadHandle; size: number }>;
20
- read(handle: ReadHandle, offset: number, length: number): Promise<Uint8Array>;
21
- listFiles(): Promise<string[]>;
22
- removeFile(filename: BlockFilename | WalFilename): Promise<void>;
23
- }
24
-
25
- export const textEncoder = new TextEncoder();
26
- export const textDecoder = new TextDecoder();
27
-
28
- export async function readChunk<RH, FS extends FileSystem<unknown, RH>>(
29
- handle: RH,
30
- header: { start: number; length: number },
31
- fs: FS,
32
- ): Promise<CoValueChunk> {
33
- const chunkBytes = await fs.read(handle, header.start, header.length);
34
-
35
- const chunk = JSON.parse(textDecoder.decode(chunkBytes));
36
- return chunk;
37
- }
38
-
39
- export async function readHeader<RH, FS extends FileSystem<unknown, RH>>(
40
- filename: string,
41
- handle: RH,
42
- size: number,
43
- fs: FS,
44
- ): Promise<BlockHeader> {
45
- const headerLength = Number(filename.match(/-H(\d+)\.jsonl$/)![1]!);
46
-
47
- const headerBytes = await fs.read(handle, size - headerLength, headerLength);
48
-
49
- const header = JSON.parse(textDecoder.decode(headerBytes));
50
- return header;
51
- }
52
-
53
- export async function writeBlock<WH, RH, FS extends FileSystem<WH, RH>>(
54
- chunks: Map<RawCoID, CoValueChunk>,
55
- level: number,
56
- blockNumber: number,
57
- fs: FS,
58
- ): Promise<BlockFilename> {
59
- if (chunks.size === 0) {
60
- throw new Error("No chunks to write");
61
- }
62
-
63
- const blockHeader: BlockHeader = [];
64
-
65
- let offset = 0;
66
-
67
- const file = await fs.createFile(
68
- "wipBlock" + Math.random().toString(36).substring(7) + ".tmp.jsonl",
69
- );
70
- const hash = new StreamingHash(fs.crypto);
71
-
72
- const chunksSortedById = Array.from(chunks).sort(([id1], [id2]) =>
73
- id1.localeCompare(id2),
74
- );
75
-
76
- for (const [id, chunk] of chunksSortedById) {
77
- const encodedBytes = hash.update(chunk);
78
- const encodedBytesWithNewline = new Uint8Array(encodedBytes.length + 1);
79
- encodedBytesWithNewline.set(encodedBytes);
80
- encodedBytesWithNewline[encodedBytes.length] = 10;
81
- await fs.append(file, encodedBytesWithNewline);
82
- const length = encodedBytesWithNewline.length;
83
- blockHeader.push({ id, start: offset, length });
84
- offset += length;
85
- }
86
-
87
- const headerBytes = textEncoder.encode(JSON.stringify(blockHeader));
88
- await fs.append(file, headerBytes);
89
-
90
- const filename: BlockFilename = `L${level}-${(blockNumber + "").padStart(
91
- 3,
92
- "0",
93
- )}-${hash.digest().replace("hash_", "").slice(0, 15)}-H${
94
- headerBytes.length
95
- }.jsonl`;
96
- await fs.closeAndRename(file, filename);
97
-
98
- return filename;
99
- }
100
-
101
- export async function writeToWal<WH, RH, FS extends FileSystem<WH, RH>>(
102
- handle: WH,
103
- fs: FS,
104
- id: RawCoID,
105
- chunk: CoValueChunk,
106
- ) {
107
- const walEntry: WalEntry = {
108
- id,
109
- ...chunk,
110
- };
111
- const bytes = textEncoder.encode(JSON.stringify(walEntry) + "\n");
112
- return fs.append(handle, bytes);
113
- }
@@ -1,137 +0,0 @@
1
- import { MAX_RECOMMENDED_TX_SIZE } from "../coValueCore.js";
2
- import { RawCoID, SessionID } from "../ids.js";
3
- import { getPriorityFromHeader } from "../priority.js";
4
- import { CoValueKnownState, NewContentMessage } from "../sync.js";
5
- import { CoValueChunk } from "./index.js";
6
-
7
- export function contentSinceChunk(
8
- id: RawCoID,
9
- chunk: CoValueChunk,
10
- known?: CoValueKnownState,
11
- ): NewContentMessage[] {
12
- const newContentPieces: NewContentMessage[] = [];
13
-
14
- newContentPieces.push({
15
- id: id,
16
- action: "content",
17
- header: known?.header ? undefined : chunk.header,
18
- new: {},
19
- priority: getPriorityFromHeader(chunk.header),
20
- });
21
-
22
- for (const [sessionID, sessionsEntry] of Object.entries(
23
- chunk.sessionEntries,
24
- )) {
25
- for (const entry of sessionsEntry) {
26
- const knownStart = known?.sessions[sessionID as SessionID] || 0;
27
-
28
- if (entry.after + entry.transactions.length <= knownStart) {
29
- continue;
30
- }
31
-
32
- const actuallyNewTransactions = entry.transactions.slice(
33
- Math.max(0, knownStart - entry.after),
34
- );
35
-
36
- const newAfter =
37
- entry.after +
38
- (actuallyNewTransactions.length - entry.transactions.length);
39
-
40
- let newContentEntry = newContentPieces[0]?.new[sessionID as SessionID];
41
-
42
- if (!newContentEntry) {
43
- newContentEntry = {
44
- after: newAfter,
45
- lastSignature: entry.lastSignature,
46
- newTransactions: actuallyNewTransactions,
47
- };
48
- newContentPieces[0]!.new[sessionID as SessionID] = newContentEntry;
49
- } else {
50
- newContentEntry.newTransactions.push(...actuallyNewTransactions);
51
- newContentEntry.lastSignature = entry.lastSignature;
52
- }
53
- }
54
- }
55
-
56
- return newContentPieces;
57
- }
58
-
59
- export function chunkToKnownState(id: RawCoID, chunk: CoValueChunk) {
60
- const ourKnown: CoValueKnownState = {
61
- id,
62
- header: !!chunk.header,
63
- sessions: {},
64
- };
65
-
66
- for (const [sessionID, sessionEntries] of Object.entries(
67
- chunk.sessionEntries,
68
- )) {
69
- for (const entry of sessionEntries) {
70
- ourKnown.sessions[sessionID as SessionID] =
71
- entry.after + entry.transactions.length;
72
- }
73
- }
74
- return ourKnown;
75
- }
76
-
77
- export function mergeChunks(
78
- chunkA: CoValueChunk,
79
- chunkB: CoValueChunk,
80
- ): "nonContigous" | CoValueChunk {
81
- const header = chunkA.header || chunkB.header;
82
-
83
- const newSessions = { ...chunkA.sessionEntries };
84
- for (const sessionID in chunkB.sessionEntries) {
85
- // figure out if we can merge the chunks
86
- const sessionEntriesA = chunkA.sessionEntries[sessionID];
87
- const sessionEntriesB = chunkB.sessionEntries[sessionID]!;
88
-
89
- if (!sessionEntriesA) {
90
- newSessions[sessionID] = sessionEntriesB;
91
- continue;
92
- }
93
-
94
- const lastEntryOfA = sessionEntriesA[sessionEntriesA.length - 1]!;
95
- const firstEntryOfB = sessionEntriesB[0]!;
96
-
97
- if (
98
- lastEntryOfA.after + lastEntryOfA.transactions.length ===
99
- firstEntryOfB.after
100
- ) {
101
- const newEntries = [];
102
- let bytesSinceLastSignature = 0;
103
- for (const entry of sessionEntriesA.concat(sessionEntriesB)) {
104
- const entryByteLength = entry.transactions.reduce(
105
- (sum, tx) =>
106
- sum +
107
- (tx.privacy === "private"
108
- ? tx.encryptedChanges.length
109
- : tx.changes.length),
110
- 0,
111
- );
112
- if (
113
- newEntries.length === 0 ||
114
- bytesSinceLastSignature + entryByteLength > MAX_RECOMMENDED_TX_SIZE
115
- ) {
116
- newEntries.push({
117
- after: entry.after,
118
- lastSignature: entry.lastSignature,
119
- transactions: entry.transactions,
120
- });
121
- bytesSinceLastSignature = 0;
122
- } else {
123
- const lastNewEntry = newEntries[newEntries.length - 1]!;
124
- lastNewEntry.transactions.push(...entry.transactions);
125
- lastNewEntry.lastSignature = entry.lastSignature;
126
-
127
- bytesSinceLastSignature += entry.transactions.length;
128
- }
129
- }
130
- newSessions[sessionID] = newEntries;
131
- } else {
132
- return "nonContigous" as const;
133
- }
134
- }
135
-
136
- return { header, sessionEntries: newSessions };
137
- }