cojson 0.10.0 → 0.10.1

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 (210) hide show
  1. package/.turbo/turbo-build.log +2 -10
  2. package/CHANGELOG.md +7 -0
  3. package/dist/CoValuesStore.js.map +1 -0
  4. package/dist/PeerKnownStates.js.map +1 -0
  5. package/dist/PeerState.js.map +1 -0
  6. package/dist/PriorityBasedMessageQueue.js.map +1 -0
  7. package/dist/SyncStateManager.js.map +1 -0
  8. package/dist/base64url.js.map +1 -0
  9. package/dist/base64url.test.js.map +1 -0
  10. package/dist/coValue.js.map +1 -0
  11. package/dist/coValueCore.js.map +1 -0
  12. package/dist/coValueState.js.map +1 -0
  13. package/dist/coValues/account.js.map +1 -0
  14. package/dist/coValues/coList.js.map +1 -0
  15. package/dist/coValues/coMap.js.map +1 -0
  16. package/dist/coValues/coPlainText.js.map +1 -0
  17. package/dist/coValues/coStream.js.map +1 -0
  18. package/dist/coValues/group.js.map +1 -0
  19. package/dist/coreToCoValue.js.map +1 -0
  20. package/dist/crypto/PureJSCrypto.js.map +1 -0
  21. package/dist/crypto/WasmCrypto.js.map +1 -0
  22. package/dist/crypto/crypto.js.map +1 -0
  23. package/dist/exports.js.map +1 -0
  24. package/dist/ids.js.map +1 -0
  25. package/dist/index.js +2 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/jsonStringify.js.map +1 -0
  28. package/dist/{native/jsonValue.js.map → jsonValue.js.map} +1 -1
  29. package/dist/localNode.js.map +1 -0
  30. package/dist/logger.js.map +1 -0
  31. package/dist/media.js.map +1 -0
  32. package/dist/permissions.js.map +1 -0
  33. package/dist/priority.js.map +1 -0
  34. package/dist/storage/FileSystem.js.map +1 -0
  35. package/dist/storage/chunksAndKnownStates.js.map +1 -0
  36. package/dist/storage/index.js.map +1 -0
  37. package/dist/streamUtils.js.map +1 -0
  38. package/dist/sync.js.map +1 -0
  39. package/dist/typeUtils/accountOrAgentIDfromSessionID.js.map +1 -0
  40. package/dist/typeUtils/expectGroup.js.map +1 -0
  41. package/dist/typeUtils/isAccountID.js.map +1 -0
  42. package/dist/typeUtils/isCoValue.js.map +1 -0
  43. package/package.json +19 -21
  44. package/src/exports.ts +1 -0
  45. package/src/index.ts +1 -0
  46. package/tsconfig.json +3 -1
  47. package/dist/native/CoValuesStore.js.map +0 -1
  48. package/dist/native/PeerKnownStates.js.map +0 -1
  49. package/dist/native/PeerState.js.map +0 -1
  50. package/dist/native/PriorityBasedMessageQueue.js.map +0 -1
  51. package/dist/native/SyncStateManager.js.map +0 -1
  52. package/dist/native/base64url.js.map +0 -1
  53. package/dist/native/base64url.test.js.map +0 -1
  54. package/dist/native/coValue.js.map +0 -1
  55. package/dist/native/coValueCore.js.map +0 -1
  56. package/dist/native/coValueState.js.map +0 -1
  57. package/dist/native/coValues/account.js.map +0 -1
  58. package/dist/native/coValues/coList.js.map +0 -1
  59. package/dist/native/coValues/coMap.js.map +0 -1
  60. package/dist/native/coValues/coPlainText.js.map +0 -1
  61. package/dist/native/coValues/coStream.js.map +0 -1
  62. package/dist/native/coValues/group.js.map +0 -1
  63. package/dist/native/coreToCoValue.js.map +0 -1
  64. package/dist/native/crypto/PureJSCrypto.js.map +0 -1
  65. package/dist/native/crypto/WasmCrypto.js.map +0 -1
  66. package/dist/native/crypto/crypto.js.map +0 -1
  67. package/dist/native/crypto/export.js +0 -3
  68. package/dist/native/crypto/export.js.map +0 -1
  69. package/dist/native/exports.js.map +0 -1
  70. package/dist/native/ids.js.map +0 -1
  71. package/dist/native/index.native.js +0 -3
  72. package/dist/native/index.native.js.map +0 -1
  73. package/dist/native/jsonStringify.js.map +0 -1
  74. package/dist/native/localNode.js.map +0 -1
  75. package/dist/native/logger.js.map +0 -1
  76. package/dist/native/media.js.map +0 -1
  77. package/dist/native/permissions.js.map +0 -1
  78. package/dist/native/priority.js.map +0 -1
  79. package/dist/native/storage/FileSystem.js.map +0 -1
  80. package/dist/native/storage/chunksAndKnownStates.js.map +0 -1
  81. package/dist/native/storage/index.js.map +0 -1
  82. package/dist/native/streamUtils.js.map +0 -1
  83. package/dist/native/sync.js.map +0 -1
  84. package/dist/native/typeUtils/accountOrAgentIDfromSessionID.js.map +0 -1
  85. package/dist/native/typeUtils/expectGroup.js.map +0 -1
  86. package/dist/native/typeUtils/isAccountID.js.map +0 -1
  87. package/dist/native/typeUtils/isCoValue.js.map +0 -1
  88. package/dist/web/CoValuesStore.js +0 -31
  89. package/dist/web/CoValuesStore.js.map +0 -1
  90. package/dist/web/PeerKnownStates.js +0 -68
  91. package/dist/web/PeerKnownStates.js.map +0 -1
  92. package/dist/web/PeerState.js +0 -103
  93. package/dist/web/PeerState.js.map +0 -1
  94. package/dist/web/PriorityBasedMessageQueue.js +0 -98
  95. package/dist/web/PriorityBasedMessageQueue.js.map +0 -1
  96. package/dist/web/SyncStateManager.js +0 -94
  97. package/dist/web/SyncStateManager.js.map +0 -1
  98. package/dist/web/base64url.js +0 -53
  99. package/dist/web/base64url.js.map +0 -1
  100. package/dist/web/base64url.test.js +0 -25
  101. package/dist/web/base64url.test.js.map +0 -1
  102. package/dist/web/coValue.js +0 -52
  103. package/dist/web/coValue.js.map +0 -1
  104. package/dist/web/coValueCore.js +0 -597
  105. package/dist/web/coValueCore.js.map +0 -1
  106. package/dist/web/coValueState.js +0 -267
  107. package/dist/web/coValueState.js.map +0 -1
  108. package/dist/web/coValues/account.js +0 -100
  109. package/dist/web/coValues/account.js.map +0 -1
  110. package/dist/web/coValues/coList.js +0 -381
  111. package/dist/web/coValues/coList.js.map +0 -1
  112. package/dist/web/coValues/coMap.js +0 -273
  113. package/dist/web/coValues/coMap.js.map +0 -1
  114. package/dist/web/coValues/coPlainText.js +0 -86
  115. package/dist/web/coValues/coPlainText.js.map +0 -1
  116. package/dist/web/coValues/coStream.js +0 -224
  117. package/dist/web/coValues/coStream.js.map +0 -1
  118. package/dist/web/coValues/group.js +0 -522
  119. package/dist/web/coValues/group.js.map +0 -1
  120. package/dist/web/coreToCoValue.js +0 -46
  121. package/dist/web/coreToCoValue.js.map +0 -1
  122. package/dist/web/crypto/PureJSCrypto.js +0 -94
  123. package/dist/web/crypto/PureJSCrypto.js.map +0 -1
  124. package/dist/web/crypto/WasmCrypto.js +0 -115
  125. package/dist/web/crypto/WasmCrypto.js.map +0 -1
  126. package/dist/web/crypto/crypto.js +0 -152
  127. package/dist/web/crypto/crypto.js.map +0 -1
  128. package/dist/web/crypto/export.js +0 -3
  129. package/dist/web/crypto/export.js.map +0 -1
  130. package/dist/web/exports.js +0 -48
  131. package/dist/web/exports.js.map +0 -1
  132. package/dist/web/ids.js +0 -50
  133. package/dist/web/ids.js.map +0 -1
  134. package/dist/web/index.web.js +0 -3
  135. package/dist/web/index.web.js.map +0 -1
  136. package/dist/web/jsonStringify.js +0 -57
  137. package/dist/web/jsonStringify.js.map +0 -1
  138. package/dist/web/jsonValue.js +0 -2
  139. package/dist/web/jsonValue.js.map +0 -1
  140. package/dist/web/localNode.js +0 -412
  141. package/dist/web/localNode.js.map +0 -1
  142. package/dist/web/logger.js +0 -58
  143. package/dist/web/logger.js.map +0 -1
  144. package/dist/web/media.js +0 -2
  145. package/dist/web/media.js.map +0 -1
  146. package/dist/web/permissions.js +0 -341
  147. package/dist/web/permissions.js.map +0 -1
  148. package/dist/web/priority.js +0 -31
  149. package/dist/web/priority.js.map +0 -1
  150. package/dist/web/storage/FileSystem.js +0 -48
  151. package/dist/web/storage/FileSystem.js.map +0 -1
  152. package/dist/web/storage/chunksAndKnownStates.js +0 -98
  153. package/dist/web/storage/chunksAndKnownStates.js.map +0 -1
  154. package/dist/web/storage/index.js +0 -336
  155. package/dist/web/storage/index.js.map +0 -1
  156. package/dist/web/streamUtils.js +0 -41
  157. package/dist/web/streamUtils.js.map +0 -1
  158. package/dist/web/sync.js +0 -555
  159. package/dist/web/sync.js.map +0 -1
  160. package/dist/web/typeUtils/accountOrAgentIDfromSessionID.js +0 -5
  161. package/dist/web/typeUtils/accountOrAgentIDfromSessionID.js.map +0 -1
  162. package/dist/web/typeUtils/expectGroup.js +0 -13
  163. package/dist/web/typeUtils/expectGroup.js.map +0 -1
  164. package/dist/web/typeUtils/isAccountID.js +0 -4
  165. package/dist/web/typeUtils/isAccountID.js.map +0 -1
  166. package/dist/web/typeUtils/isCoValue.js +0 -11
  167. package/dist/web/typeUtils/isCoValue.js.map +0 -1
  168. package/src/crypto/export.ts +0 -2
  169. package/src/index.native.ts +0 -2
  170. package/src/index.web.ts +0 -2
  171. package/tsconfig.native.json +0 -10
  172. package/tsconfig.web.json +0 -5
  173. /package/dist/{native/CoValuesStore.js → CoValuesStore.js} +0 -0
  174. /package/dist/{native/PeerKnownStates.js → PeerKnownStates.js} +0 -0
  175. /package/dist/{native/PeerState.js → PeerState.js} +0 -0
  176. /package/dist/{native/PriorityBasedMessageQueue.js → PriorityBasedMessageQueue.js} +0 -0
  177. /package/dist/{native/SyncStateManager.js → SyncStateManager.js} +0 -0
  178. /package/dist/{native/base64url.js → base64url.js} +0 -0
  179. /package/dist/{native/base64url.test.js → base64url.test.js} +0 -0
  180. /package/dist/{native/coValue.js → coValue.js} +0 -0
  181. /package/dist/{native/coValueCore.js → coValueCore.js} +0 -0
  182. /package/dist/{native/coValueState.js → coValueState.js} +0 -0
  183. /package/dist/{native/coValues → coValues}/account.js +0 -0
  184. /package/dist/{native/coValues → coValues}/coList.js +0 -0
  185. /package/dist/{native/coValues → coValues}/coMap.js +0 -0
  186. /package/dist/{native/coValues → coValues}/coPlainText.js +0 -0
  187. /package/dist/{native/coValues → coValues}/coStream.js +0 -0
  188. /package/dist/{native/coValues → coValues}/group.js +0 -0
  189. /package/dist/{native/coreToCoValue.js → coreToCoValue.js} +0 -0
  190. /package/dist/{native/crypto → crypto}/PureJSCrypto.js +0 -0
  191. /package/dist/{native/crypto → crypto}/WasmCrypto.js +0 -0
  192. /package/dist/{native/crypto → crypto}/crypto.js +0 -0
  193. /package/dist/{native/exports.js → exports.js} +0 -0
  194. /package/dist/{native/ids.js → ids.js} +0 -0
  195. /package/dist/{native/jsonStringify.js → jsonStringify.js} +0 -0
  196. /package/dist/{native/jsonValue.js → jsonValue.js} +0 -0
  197. /package/dist/{native/localNode.js → localNode.js} +0 -0
  198. /package/dist/{native/logger.js → logger.js} +0 -0
  199. /package/dist/{native/media.js → media.js} +0 -0
  200. /package/dist/{native/permissions.js → permissions.js} +0 -0
  201. /package/dist/{native/priority.js → priority.js} +0 -0
  202. /package/dist/{native/storage → storage}/FileSystem.js +0 -0
  203. /package/dist/{native/storage → storage}/chunksAndKnownStates.js +0 -0
  204. /package/dist/{native/storage → storage}/index.js +0 -0
  205. /package/dist/{native/streamUtils.js → streamUtils.js} +0 -0
  206. /package/dist/{native/sync.js → sync.js} +0 -0
  207. /package/dist/{native/typeUtils → typeUtils}/accountOrAgentIDfromSessionID.js +0 -0
  208. /package/dist/{native/typeUtils → typeUtils}/expectGroup.js +0 -0
  209. /package/dist/{native/typeUtils → typeUtils}/isAccountID.js +0 -0
  210. /package/dist/{native/typeUtils → typeUtils}/isCoValue.js +0 -0
@@ -1,52 +0,0 @@
1
- export class RawUnknownCoValue {
2
- constructor(core) {
3
- this.id = core.id;
4
- this.core = core;
5
- }
6
- get type() {
7
- return this.core.header.type;
8
- }
9
- get headerMeta() {
10
- return this.core.header.meta;
11
- }
12
- /** @category 6. Meta */
13
- get group() {
14
- return this.core.getGroup();
15
- }
16
- toJSON() {
17
- return {};
18
- }
19
- atTime() {
20
- return this;
21
- }
22
- subscribe(listener) {
23
- return this.core.subscribe((content) => {
24
- listener(content);
25
- });
26
- }
27
- }
28
- export function expectMap(content) {
29
- if (content.type !== "comap") {
30
- throw new Error("Expected map");
31
- }
32
- return content;
33
- }
34
- export function expectList(content) {
35
- if (content.type !== "colist") {
36
- throw new Error("Expected list");
37
- }
38
- return content;
39
- }
40
- export function expectStream(content) {
41
- if (content.type !== "costream") {
42
- throw new Error("Expected stream");
43
- }
44
- return content;
45
- }
46
- export function expectPlainText(content) {
47
- if (content.type !== "coplaintext") {
48
- throw new Error("Expected plaintext");
49
- }
50
- return content;
51
- }
52
- //# sourceMappingURL=coValue.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"coValue.js","sourceRoot":"","sources":["../../src/coValue.ts"],"names":[],"mappings":"AAqCA,MAAM,OAAO,iBAAiB;IAI5B,YAAY,IAAiB;QAC3B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAgB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAkB,CAAC;IAC7C,CAAC;IAED,wBAAwB;IACxB,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,SAAS,CAAC,QAA+B;QACvC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE;YACrC,QAAQ,CAAC,OAAe,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAYD,MAAM,UAAU,SAAS,CAAC,OAAmB;IAC3C,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,OAAmB,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAmB;IAC5C,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,OAAoB,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAmB;IAC9C,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,OAAsB,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAmB;IACjD,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,OAAyB,CAAC;AACnC,CAAC"}
@@ -1,597 +0,0 @@
1
- import { err, ok } from "neverthrow";
2
- import { coreToCoValue } from "./coreToCoValue.js";
3
- import { StreamingHash, } from "./crypto/crypto.js";
4
- import { getGroupDependentKeyList, getParentGroupId, isParentGroupReference, } from "./ids.js";
5
- import { parseJSON, stableStringify } from "./jsonStringify.js";
6
- import { logger } from "./logger.js";
7
- import { determineValidTransactions, isKeyForKeyField, } from "./permissions.js";
8
- import { getPriorityFromHeader } from "./priority.js";
9
- import { accountOrAgentIDfromSessionID } from "./typeUtils/accountOrAgentIDfromSessionID.js";
10
- import { expectGroup } from "./typeUtils/expectGroup.js";
11
- import { isAccountID } from "./typeUtils/isAccountID.js";
12
- /**
13
- In order to not block other concurrently syncing CoValues we introduce a maximum size of transactions,
14
- since they are the smallest unit of progress that can be synced within a CoValue.
15
- This is particularly important for storing binary data in CoValues, since they are likely to be at least on the order of megabytes.
16
- This also means that we want to keep signatures roughly after each MAX_RECOMMENDED_TX size chunk,
17
- to be able to verify partially loaded CoValues or CoValues that are still being created (like a video live stream).
18
- **/
19
- export const MAX_RECOMMENDED_TX_SIZE = 100 * 1024;
20
- export function idforHeader(header, crypto) {
21
- const hash = crypto.shortHash(header);
22
- return `co_z${hash.slice("shortHash_z".length)}`;
23
- }
24
- const readKeyCache = new WeakMap();
25
- export class CoValueCore {
26
- constructor(header, node, internalInitSessions = new Map()) {
27
- this.listeners = new Set();
28
- this._decryptionCache = {};
29
- this.deferredUpdates = 0;
30
- this.crypto = node.crypto;
31
- this.id = idforHeader(header, node.crypto);
32
- this.header = header;
33
- this._sessionLogs = internalInitSessions;
34
- this.node = node;
35
- if (header.ruleset.type == "ownedByGroup") {
36
- this.node
37
- .expectCoValueLoaded(header.ruleset.group)
38
- .subscribe((_groupUpdate) => {
39
- this._cachedContent = undefined;
40
- this.notifyUpdate("immediate");
41
- });
42
- }
43
- }
44
- get sessionLogs() {
45
- return this._sessionLogs;
46
- }
47
- testWithDifferentAccount(account, currentSessionID) {
48
- const newNode = this.node.testWithDifferentAccount(account, currentSessionID);
49
- return newNode.expectCoValueLoaded(this.id);
50
- }
51
- knownState() {
52
- if (this._cachedKnownState) {
53
- return this._cachedKnownState;
54
- }
55
- else {
56
- const knownState = this.knownStateUncached();
57
- this._cachedKnownState = knownState;
58
- return knownState;
59
- }
60
- }
61
- /** @internal */
62
- knownStateUncached() {
63
- const sessions = {};
64
- for (const [sessionID, sessionLog] of this.sessionLogs.entries()) {
65
- sessions[sessionID] = sessionLog.transactions.length;
66
- }
67
- return {
68
- id: this.id,
69
- header: true,
70
- sessions,
71
- };
72
- }
73
- get meta() {
74
- return this.header?.meta ?? null;
75
- }
76
- nextTransactionID() {
77
- // This is an ugly hack to get a unique but stable session ID for editing the current account
78
- const sessionID = this.header.meta?.type === "account"
79
- ? this.node.currentSessionID.replace(this.node.account.id, this.node.account
80
- .currentAgentID()
81
- ._unsafeUnwrap({ withStackTrace: true }))
82
- : this.node.currentSessionID;
83
- return {
84
- sessionID,
85
- txIndex: this.sessionLogs.get(sessionID)?.transactions.length || 0,
86
- };
87
- }
88
- tryAddTransactions(sessionID, newTransactions, givenExpectedNewHash, newSignature, skipVerify = false) {
89
- return this.node
90
- .resolveAccountAgent(accountOrAgentIDfromSessionID(sessionID), "Expected to know signer of transaction")
91
- .andThen((agent) => {
92
- const signerID = this.crypto.getAgentSignerID(agent);
93
- const { expectedNewHash, newStreamingHash } = this.expectedNewHashAfter(sessionID, newTransactions);
94
- if (givenExpectedNewHash && givenExpectedNewHash !== expectedNewHash) {
95
- return err({
96
- type: "InvalidHash",
97
- id: this.id,
98
- expectedNewHash,
99
- givenExpectedNewHash,
100
- });
101
- }
102
- if (skipVerify !== true &&
103
- !this.crypto.verify(newSignature, expectedNewHash, signerID)) {
104
- return err({
105
- type: "InvalidSignature",
106
- id: this.id,
107
- newSignature,
108
- sessionID,
109
- signerID,
110
- });
111
- }
112
- this.doAddTransactions(sessionID, newTransactions, newSignature, expectedNewHash, newStreamingHash, "immediate");
113
- return ok(true);
114
- });
115
- }
116
- doAddTransactions(sessionID, newTransactions, newSignature, expectedNewHash, newStreamingHash, notifyMode) {
117
- if (this.node.crashed) {
118
- throw new Error("Trying to add transactions after node is crashed");
119
- }
120
- const transactions = this.sessionLogs.get(sessionID)?.transactions ?? [];
121
- for (const tx of newTransactions) {
122
- transactions.push(tx);
123
- }
124
- const signatureAfter = this.sessionLogs.get(sessionID)?.signatureAfter ?? {};
125
- const lastInbetweenSignatureIdx = Object.keys(signatureAfter).reduce((max, idx) => (parseInt(idx) > max ? parseInt(idx) : max), -1);
126
- const sizeOfTxsSinceLastInbetweenSignature = transactions
127
- .slice(lastInbetweenSignatureIdx + 1)
128
- .reduce((sum, tx) => sum +
129
- (tx.privacy === "private"
130
- ? tx.encryptedChanges.length
131
- : tx.changes.length), 0);
132
- if (sizeOfTxsSinceLastInbetweenSignature > MAX_RECOMMENDED_TX_SIZE) {
133
- signatureAfter[transactions.length - 1] = newSignature;
134
- }
135
- this._sessionLogs.set(sessionID, {
136
- transactions,
137
- lastHash: expectedNewHash,
138
- streamingHash: newStreamingHash,
139
- lastSignature: newSignature,
140
- signatureAfter: signatureAfter,
141
- });
142
- if (this._cachedContent &&
143
- "processNewTransactions" in this._cachedContent &&
144
- typeof this._cachedContent.processNewTransactions === "function") {
145
- this._cachedContent.processNewTransactions();
146
- }
147
- else {
148
- this._cachedContent = undefined;
149
- }
150
- this._cachedKnownState = undefined;
151
- this._cachedDependentOn = undefined;
152
- this._cachedNewContentSinceEmpty = undefined;
153
- this.notifyUpdate(notifyMode);
154
- }
155
- notifyUpdate(notifyMode) {
156
- if (this.listeners.size === 0) {
157
- return;
158
- }
159
- if (notifyMode === "immediate") {
160
- const content = this.getCurrentContent();
161
- for (const listener of this.listeners) {
162
- listener(content);
163
- }
164
- }
165
- else {
166
- if (!this.nextDeferredNotify) {
167
- this.nextDeferredNotify = new Promise((resolve) => {
168
- setTimeout(() => {
169
- this.nextDeferredNotify = undefined;
170
- this.deferredUpdates = 0;
171
- const content = this.getCurrentContent();
172
- for (const listener of this.listeners) {
173
- listener(content);
174
- }
175
- resolve();
176
- }, 0);
177
- });
178
- }
179
- this.deferredUpdates++;
180
- }
181
- }
182
- subscribe(listener) {
183
- this.listeners.add(listener);
184
- listener(this.getCurrentContent());
185
- return () => {
186
- this.listeners.delete(listener);
187
- };
188
- }
189
- expectedNewHashAfter(sessionID, newTransactions) {
190
- const streamingHash = this.sessionLogs.get(sessionID)?.streamingHash.clone() ??
191
- new StreamingHash(this.crypto);
192
- for (const transaction of newTransactions) {
193
- streamingHash.update(transaction);
194
- }
195
- const newStreamingHash = streamingHash.clone();
196
- return {
197
- expectedNewHash: streamingHash.digest(),
198
- newStreamingHash,
199
- };
200
- }
201
- async expectedNewHashAfterAsync(sessionID, newTransactions) {
202
- const streamingHash = this.sessionLogs.get(sessionID)?.streamingHash.clone() ??
203
- new StreamingHash(this.crypto);
204
- let before = performance.now();
205
- for (const transaction of newTransactions) {
206
- streamingHash.update(transaction);
207
- const after = performance.now();
208
- if (after - before > 1) {
209
- await new Promise((resolve) => setTimeout(resolve, 0));
210
- before = performance.now();
211
- }
212
- }
213
- const newStreamingHash = streamingHash.clone();
214
- return {
215
- expectedNewHash: streamingHash.digest(),
216
- newStreamingHash,
217
- };
218
- }
219
- makeTransaction(changes, privacy) {
220
- const madeAt = Date.now();
221
- let transaction;
222
- if (privacy === "private") {
223
- const { secret: keySecret, id: keyID } = this.getCurrentReadKey();
224
- if (!keySecret) {
225
- throw new Error("Can't make transaction without read key secret");
226
- }
227
- const encrypted = this.crypto.encryptForTransaction(changes, keySecret, {
228
- in: this.id,
229
- tx: this.nextTransactionID(),
230
- });
231
- this._decryptionCache[encrypted] = changes;
232
- transaction = {
233
- privacy: "private",
234
- madeAt,
235
- keyUsed: keyID,
236
- encryptedChanges: encrypted,
237
- };
238
- }
239
- else {
240
- transaction = {
241
- privacy: "trusting",
242
- madeAt,
243
- changes: stableStringify(changes),
244
- };
245
- }
246
- // This is an ugly hack to get a unique but stable session ID for editing the current account
247
- const sessionID = this.header.meta?.type === "account"
248
- ? this.node.currentSessionID.replace(this.node.account.id, this.node.account
249
- .currentAgentID()
250
- ._unsafeUnwrap({ withStackTrace: true }))
251
- : this.node.currentSessionID;
252
- const { expectedNewHash } = this.expectedNewHashAfter(sessionID, [
253
- transaction,
254
- ]);
255
- const signature = this.crypto.sign(this.node.account.currentSignerSecret(), expectedNewHash);
256
- const success = this.tryAddTransactions(sessionID, [transaction], expectedNewHash, signature, true)._unsafeUnwrap({ withStackTrace: true });
257
- if (success) {
258
- void this.node.syncManager.syncCoValue(this);
259
- }
260
- return success;
261
- }
262
- getCurrentContent(options) {
263
- if (!options?.ignorePrivateTransactions && this._cachedContent) {
264
- return this._cachedContent;
265
- }
266
- const newContent = coreToCoValue(this, options);
267
- if (!options?.ignorePrivateTransactions) {
268
- this._cachedContent = newContent;
269
- }
270
- return newContent;
271
- }
272
- getValidTransactions(options) {
273
- const validTransactions = determineValidTransactions(this);
274
- const allTransactions = [];
275
- for (const { txID, tx } of validTransactions) {
276
- if (options?.knownTransactions?.[txID.sessionID] >= txID.txIndex) {
277
- continue;
278
- }
279
- if (tx.privacy === "trusting") {
280
- allTransactions.push({
281
- txID,
282
- madeAt: tx.madeAt,
283
- changes: parseJSON(tx.changes),
284
- });
285
- continue;
286
- }
287
- if (options?.ignorePrivateTransactions) {
288
- continue;
289
- }
290
- const readKey = this.getReadKey(tx.keyUsed);
291
- if (!readKey) {
292
- continue;
293
- }
294
- let decryptedChanges = this._decryptionCache[tx.encryptedChanges];
295
- if (!decryptedChanges) {
296
- const decryptedString = this.crypto.decryptRawForTransaction(tx.encryptedChanges, readKey, {
297
- in: this.id,
298
- tx: txID,
299
- });
300
- decryptedChanges = decryptedString && parseJSON(decryptedString);
301
- this._decryptionCache[tx.encryptedChanges] = decryptedChanges;
302
- }
303
- if (!decryptedChanges) {
304
- logger.error("Failed to decrypt transaction despite having key");
305
- continue;
306
- }
307
- allTransactions.push({
308
- txID,
309
- madeAt: tx.madeAt,
310
- changes: decryptedChanges,
311
- });
312
- }
313
- return allTransactions;
314
- }
315
- getValidSortedTransactions(options) {
316
- const allTransactions = this.getValidTransactions(options);
317
- allTransactions.sort(this.compareTransactions);
318
- return allTransactions;
319
- }
320
- compareTransactions(a, b) {
321
- return (a.madeAt - b.madeAt ||
322
- (a.txID.sessionID < b.txID.sessionID ? -1 : 1) ||
323
- a.txID.txIndex - b.txID.txIndex);
324
- }
325
- getCurrentReadKey() {
326
- if (this.header.ruleset.type === "group") {
327
- const content = expectGroup(this.getCurrentContent());
328
- const currentKeyId = content.getCurrentReadKeyId();
329
- if (!currentKeyId) {
330
- throw new Error("No readKey set");
331
- }
332
- const secret = this.getReadKey(currentKeyId);
333
- return {
334
- secret: secret,
335
- id: currentKeyId,
336
- };
337
- }
338
- else if (this.header.ruleset.type === "ownedByGroup") {
339
- return this.node
340
- .expectCoValueLoaded(this.header.ruleset.group)
341
- .getCurrentReadKey();
342
- }
343
- else {
344
- throw new Error("Only groups or values owned by groups have read secrets");
345
- }
346
- }
347
- getReadKey(keyID) {
348
- let key = readKeyCache.get(this)?.[keyID];
349
- if (!key) {
350
- key = this.getUncachedReadKey(keyID);
351
- if (key) {
352
- let cache = readKeyCache.get(this);
353
- if (!cache) {
354
- cache = {};
355
- readKeyCache.set(this, cache);
356
- }
357
- cache[keyID] = key;
358
- }
359
- }
360
- return key;
361
- }
362
- getUncachedReadKey(keyID) {
363
- if (this.header.ruleset.type === "group") {
364
- const content = expectGroup(this.getCurrentContent({ ignorePrivateTransactions: true }));
365
- const keyForEveryone = content.get(`${keyID}_for_everyone`);
366
- if (keyForEveryone)
367
- return keyForEveryone;
368
- // Try to find key revelation for us
369
- const lookupAccountOrAgentID = this.header.meta?.type === "account"
370
- ? this.node.account
371
- .currentAgentID()
372
- ._unsafeUnwrap({ withStackTrace: true })
373
- : this.node.account.id;
374
- const lastReadyKeyEdit = content.lastEditAt(`${keyID}_for_${lookupAccountOrAgentID}`);
375
- if (lastReadyKeyEdit?.value) {
376
- const revealer = lastReadyKeyEdit.by;
377
- const revealerAgent = this.node
378
- .resolveAccountAgent(revealer, "Expected to know revealer")
379
- ._unsafeUnwrap({ withStackTrace: true });
380
- const secret = this.crypto.unseal(lastReadyKeyEdit.value, this.node.account.currentSealerSecret(), this.crypto.getAgentSealerID(revealerAgent), {
381
- in: this.id,
382
- tx: lastReadyKeyEdit.tx,
383
- });
384
- if (secret) {
385
- return secret;
386
- }
387
- }
388
- // Try to find indirect revelation through previousKeys
389
- for (const co of content.keys()) {
390
- if (isKeyForKeyField(co) && co.startsWith(keyID)) {
391
- const encryptingKeyID = co.split("_for_")[1];
392
- const encryptingKeySecret = this.getReadKey(encryptingKeyID);
393
- if (!encryptingKeySecret) {
394
- continue;
395
- }
396
- const encryptedPreviousKey = content.get(co);
397
- const secret = this.crypto.decryptKeySecret({
398
- encryptedID: keyID,
399
- encryptingID: encryptingKeyID,
400
- encrypted: encryptedPreviousKey,
401
- }, encryptingKeySecret);
402
- if (secret) {
403
- return secret;
404
- }
405
- else {
406
- logger.warn(`Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`);
407
- }
408
- }
409
- }
410
- // try to find revelation to parent group read keys
411
- for (const co of content.keys()) {
412
- if (isParentGroupReference(co)) {
413
- const parentGroupID = getParentGroupId(co);
414
- const parentGroup = this.node.expectCoValueLoaded(parentGroupID, "Expected parent group to be loaded");
415
- const parentKeys = this.findValidParentKeys(keyID, content, parentGroup);
416
- for (const parentKey of parentKeys) {
417
- const revelationForParentKey = content.get(`${keyID}_for_${parentKey.id}`);
418
- if (revelationForParentKey) {
419
- const secret = parentGroup.crypto.decryptKeySecret({
420
- encryptedID: keyID,
421
- encryptingID: parentKey.id,
422
- encrypted: revelationForParentKey,
423
- }, parentKey.secret);
424
- if (secret) {
425
- return secret;
426
- }
427
- else {
428
- logger.warn(`Encrypting parent ${parentKey.id} key didn't decrypt ${keyID}`);
429
- }
430
- }
431
- }
432
- }
433
- }
434
- return undefined;
435
- }
436
- else if (this.header.ruleset.type === "ownedByGroup") {
437
- return this.node
438
- .expectCoValueLoaded(this.header.ruleset.group)
439
- .getReadKey(keyID);
440
- }
441
- else {
442
- throw new Error("Only groups or values owned by groups have read secrets");
443
- }
444
- }
445
- findValidParentKeys(keyID, group, parentGroup) {
446
- const validParentKeys = [];
447
- for (const co of group.keys()) {
448
- if (isKeyForKeyField(co) && co.startsWith(keyID)) {
449
- const encryptingKeyID = co.split("_for_")[1];
450
- const encryptingKeySecret = parentGroup.getReadKey(encryptingKeyID);
451
- if (!encryptingKeySecret) {
452
- continue;
453
- }
454
- validParentKeys.push({
455
- id: encryptingKeyID,
456
- secret: encryptingKeySecret,
457
- });
458
- }
459
- }
460
- return validParentKeys;
461
- }
462
- getGroup() {
463
- if (this.header.ruleset.type !== "ownedByGroup") {
464
- throw new Error("Only values owned by groups have groups");
465
- }
466
- return expectGroup(this.node
467
- .expectCoValueLoaded(this.header.ruleset.group)
468
- .getCurrentContent());
469
- }
470
- getTx(txID) {
471
- return this.sessionLogs.get(txID.sessionID)?.transactions[txID.txIndex];
472
- }
473
- newContentSince(knownState) {
474
- const isKnownStateEmpty = !knownState?.header && !knownState?.sessions;
475
- if (isKnownStateEmpty && this._cachedNewContentSinceEmpty) {
476
- return this._cachedNewContentSinceEmpty;
477
- }
478
- let currentPiece = {
479
- action: "content",
480
- id: this.id,
481
- header: knownState?.header ? undefined : this.header,
482
- priority: getPriorityFromHeader(this.header),
483
- new: {},
484
- };
485
- const pieces = [currentPiece];
486
- const sentState = {};
487
- let pieceSize = 0;
488
- let sessionsTodoAgain = "first";
489
- while (sessionsTodoAgain === "first" || sessionsTodoAgain?.size || 0 > 0) {
490
- if (sessionsTodoAgain === "first") {
491
- sessionsTodoAgain = undefined;
492
- }
493
- const sessionsTodo = sessionsTodoAgain ?? this.sessionLogs.keys();
494
- for (const sessionIDKey of sessionsTodo) {
495
- const sessionID = sessionIDKey;
496
- const log = this.sessionLogs.get(sessionID);
497
- const knownStateForSessionID = knownState?.sessions[sessionID];
498
- const sentStateForSessionID = sentState[sessionID];
499
- const nextKnownSignatureIdx = getNextKnownSignatureIdx(log, knownStateForSessionID, sentStateForSessionID);
500
- const firstNewTxIdx = sentStateForSessionID ?? knownStateForSessionID ?? 0;
501
- const afterLastNewTxIdx = nextKnownSignatureIdx === undefined
502
- ? log.transactions.length
503
- : nextKnownSignatureIdx + 1;
504
- const nNewTx = Math.max(0, afterLastNewTxIdx - firstNewTxIdx);
505
- if (nNewTx === 0) {
506
- sessionsTodoAgain?.delete(sessionID);
507
- continue;
508
- }
509
- if (afterLastNewTxIdx < log.transactions.length) {
510
- if (!sessionsTodoAgain) {
511
- sessionsTodoAgain = new Set();
512
- }
513
- sessionsTodoAgain.add(sessionID);
514
- }
515
- const oldPieceSize = pieceSize;
516
- for (let txIdx = firstNewTxIdx; txIdx < afterLastNewTxIdx; txIdx++) {
517
- const tx = log.transactions[txIdx];
518
- pieceSize +=
519
- tx.privacy === "private"
520
- ? tx.encryptedChanges.length
521
- : tx.changes.length;
522
- }
523
- if (pieceSize >= MAX_RECOMMENDED_TX_SIZE) {
524
- currentPiece = {
525
- action: "content",
526
- id: this.id,
527
- header: undefined,
528
- new: {},
529
- priority: getPriorityFromHeader(this.header),
530
- };
531
- pieces.push(currentPiece);
532
- pieceSize = pieceSize - oldPieceSize;
533
- }
534
- let sessionEntry = currentPiece.new[sessionID];
535
- if (!sessionEntry) {
536
- sessionEntry = {
537
- after: sentStateForSessionID ?? knownStateForSessionID ?? 0,
538
- newTransactions: [],
539
- lastSignature: "WILL_BE_REPLACED",
540
- };
541
- currentPiece.new[sessionID] = sessionEntry;
542
- }
543
- for (let txIdx = firstNewTxIdx; txIdx < afterLastNewTxIdx; txIdx++) {
544
- const tx = log.transactions[txIdx];
545
- sessionEntry.newTransactions.push(tx);
546
- }
547
- sessionEntry.lastSignature =
548
- nextKnownSignatureIdx === undefined
549
- ? log.lastSignature
550
- : log.signatureAfter[nextKnownSignatureIdx];
551
- sentState[sessionID] =
552
- (sentStateForSessionID ?? knownStateForSessionID ?? 0) + nNewTx;
553
- }
554
- }
555
- const piecesWithContent = pieces.filter((piece) => Object.keys(piece.new).length > 0 || piece.header);
556
- if (piecesWithContent.length === 0) {
557
- return undefined;
558
- }
559
- if (isKnownStateEmpty) {
560
- this._cachedNewContentSinceEmpty = piecesWithContent;
561
- }
562
- return piecesWithContent;
563
- }
564
- getDependedOnCoValues() {
565
- if (this._cachedDependentOn) {
566
- return this._cachedDependentOn;
567
- }
568
- else {
569
- const dependentOn = this.getDependedOnCoValuesUncached();
570
- this._cachedDependentOn = dependentOn;
571
- return dependentOn;
572
- }
573
- }
574
- /** @internal */
575
- getDependedOnCoValuesUncached() {
576
- return this.header.ruleset.type === "group"
577
- ? getGroupDependentKeyList(expectGroup(this.getCurrentContent()).keys())
578
- : this.header.ruleset.type === "ownedByGroup"
579
- ? [
580
- this.header.ruleset.group,
581
- ...new Set([...this.sessionLogs.keys()]
582
- .map((sessionID) => accountOrAgentIDfromSessionID(sessionID))
583
- .filter((session) => isAccountID(session) && session !== this.id)),
584
- ]
585
- : [];
586
- }
587
- waitForSync(options) {
588
- return this.node.syncManager.waitForSync(this.id, options?.timeout);
589
- }
590
- }
591
- function getNextKnownSignatureIdx(log, knownStateForSessionID, sentStateForSessionID) {
592
- return Object.keys(log.signatureAfter)
593
- .map(Number)
594
- .sort((a, b) => a - b)
595
- .find((idx) => idx >= (sentStateForSessionID ?? knownStateForSessionID ?? -1));
596
- }
597
- //# sourceMappingURL=coValueCore.js.map