cojson 0.0.7 → 0.0.9

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 (92) hide show
  1. package/.eslintrc.cjs +11 -8
  2. package/dist/coValue.d.ts +97 -0
  3. package/dist/coValue.js +381 -0
  4. package/dist/coValue.js.map +1 -0
  5. package/dist/coValue.test.d.ts +1 -0
  6. package/dist/coValue.test.js +78 -0
  7. package/dist/coValue.test.js.map +1 -0
  8. package/dist/contentType.d.ts +15 -0
  9. package/dist/contentType.js +7 -0
  10. package/dist/contentType.js.map +1 -0
  11. package/dist/contentType.test.d.ts +1 -0
  12. package/dist/contentType.test.js +149 -0
  13. package/dist/contentType.test.js.map +1 -0
  14. package/dist/contentTypes/coList.d.ts +11 -0
  15. package/dist/contentTypes/coList.js +16 -0
  16. package/dist/contentTypes/coList.js.map +1 -0
  17. package/dist/contentTypes/coMap.d.ts +56 -0
  18. package/dist/contentTypes/coMap.js +126 -0
  19. package/dist/contentTypes/coMap.js.map +1 -0
  20. package/dist/contentTypes/coStream.d.ts +11 -0
  21. package/dist/contentTypes/coStream.js +16 -0
  22. package/dist/contentTypes/coStream.js.map +1 -0
  23. package/dist/contentTypes/static.d.ts +11 -0
  24. package/dist/contentTypes/static.js +14 -0
  25. package/dist/contentTypes/static.js.map +1 -0
  26. package/dist/crypto.d.ts +97 -0
  27. package/dist/crypto.js +156 -0
  28. package/dist/crypto.js.map +1 -0
  29. package/dist/crypto.test.d.ts +1 -0
  30. package/dist/crypto.test.js +115 -0
  31. package/dist/crypto.test.js.map +1 -0
  32. package/dist/ids.d.ts +7 -0
  33. package/dist/ids.js +2 -0
  34. package/dist/ids.js.map +1 -0
  35. package/dist/index.d.ts +19 -0
  36. package/dist/index.js +13 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/jsonValue.d.ts +7 -0
  39. package/dist/jsonValue.js +2 -0
  40. package/dist/jsonValue.js.map +1 -0
  41. package/dist/node.d.ts +33 -0
  42. package/dist/node.js +113 -0
  43. package/dist/node.js.map +1 -0
  44. package/dist/permissions.d.ts +54 -0
  45. package/dist/permissions.js +218 -0
  46. package/dist/permissions.js.map +1 -0
  47. package/dist/permissions.test.d.ts +1 -0
  48. package/dist/permissions.test.js +794 -0
  49. package/dist/permissions.test.js.map +1 -0
  50. package/dist/sync.d.ts +80 -0
  51. package/dist/sync.js +271 -0
  52. package/dist/sync.js.map +1 -0
  53. package/dist/sync.test.d.ts +1 -0
  54. package/dist/sync.test.js +826 -0
  55. package/dist/sync.test.js.map +1 -0
  56. package/package.json +7 -6
  57. package/src/coValue.test.ts +3 -4
  58. package/src/coValue.ts +11 -11
  59. package/src/contentType.test.ts +3 -3
  60. package/src/contentType.ts +6 -6
  61. package/src/contentTypes/coList.ts +4 -4
  62. package/src/contentTypes/coMap.ts +6 -6
  63. package/src/contentTypes/coStream.ts +4 -4
  64. package/src/contentTypes/static.ts +5 -5
  65. package/src/crypto.test.ts +1 -1
  66. package/src/crypto.ts +2 -2
  67. package/src/index.ts +8 -8
  68. package/src/jsonValue.ts +1 -1
  69. package/src/node.ts +6 -7
  70. package/src/permissions.test.ts +5 -5
  71. package/src/permissions.ts +7 -7
  72. package/src/sync.test.ts +7 -7
  73. package/src/sync.ts +6 -6
  74. package/tsconfig.json +1 -7
  75. package/dist/coValue.mjs +0 -437
  76. package/dist/coValue.test.mjs +0 -122
  77. package/dist/contentType.mjs +0 -7
  78. package/dist/contentType.test.mjs +0 -179
  79. package/dist/contentTypes/coList.mjs +0 -18
  80. package/dist/contentTypes/coMap.mjs +0 -126
  81. package/dist/contentTypes/coStream.mjs +0 -18
  82. package/dist/contentTypes/static.mjs +0 -16
  83. package/dist/crypto.mjs +0 -207
  84. package/dist/crypto.test.mjs +0 -155
  85. package/dist/ids.mjs +0 -1
  86. package/dist/index.mjs +0 -21
  87. package/dist/jsonValue.mjs +0 -1
  88. package/dist/node.mjs +0 -144
  89. package/dist/permissions.mjs +0 -244
  90. package/dist/permissions.test.mjs +0 -985
  91. package/dist/sync.mjs +0 -318
  92. package/dist/sync.test.mjs +0 -861
package/dist/coValue.mjs DELETED
@@ -1,437 +0,0 @@
1
- "use strict";
2
- import { randomBytes } from "@noble/hashes/utils";
3
- import { Static } from "./contentTypes/static";
4
- import { CoStream } from "./contentTypes/coStream";
5
- import { CoMap } from "./contentTypes/coMap";
6
- import {
7
- StreamingHash,
8
- getRecipientID,
9
- getSignatoryID,
10
- newRandomRecipient,
11
- newRandomSignatory,
12
- openAs,
13
- shortHash,
14
- sign,
15
- verify,
16
- encryptForTransaction,
17
- decryptForTransaction,
18
- unsealKeySecret,
19
- signatorySecretToBytes,
20
- recipientSecretToBytes,
21
- signatorySecretFromBytes,
22
- recipientSecretFromBytes
23
- } from "./crypto";
24
- import { base58 } from "@scure/base";
25
- import {
26
- Team,
27
- determineValidTransactions,
28
- expectTeamContent
29
- } from "./permissions";
30
- import { CoList } from "./contentTypes/coList";
31
- function coValueIDforHeader(header) {
32
- const hash = shortHash(header);
33
- if (header.publicNickname) {
34
- return `co_${header.publicNickname}_z${hash.slice(
35
- "shortHash_z".length
36
- )}`;
37
- } else {
38
- return `co_z${hash.slice("shortHash_z".length)}`;
39
- }
40
- }
41
- export function agentIDfromSessionID(sessionID) {
42
- return sessionID.split("_session")[0];
43
- }
44
- export function newRandomSessionID(agentID) {
45
- return `${agentID}_session_z${base58.encode(randomBytes(8))}`;
46
- }
47
- export class CoValue {
48
- id;
49
- node;
50
- header;
51
- sessions;
52
- content;
53
- listeners = /* @__PURE__ */ new Set();
54
- constructor(header, node) {
55
- this.id = coValueIDforHeader(header);
56
- this.header = header;
57
- this.sessions = {};
58
- this.node = node;
59
- }
60
- testWithDifferentCredentials(agentCredential, ownSessionID) {
61
- const newNode = this.node.testWithDifferentCredentials(
62
- agentCredential,
63
- ownSessionID
64
- );
65
- return newNode.expectCoValueLoaded(this.id);
66
- }
67
- knownState() {
68
- return {
69
- coValueID: this.id,
70
- header: true,
71
- sessions: Object.fromEntries(
72
- Object.entries(this.sessions).map(([k, v]) => [
73
- k,
74
- v.transactions.length
75
- ])
76
- )
77
- };
78
- }
79
- get meta() {
80
- var _a;
81
- return ((_a = this.header) == null ? void 0 : _a.meta) ?? null;
82
- }
83
- nextTransactionID() {
84
- var _a;
85
- const sessionID = this.node.ownSessionID;
86
- return {
87
- sessionID,
88
- txIndex: ((_a = this.sessions[sessionID]) == null ? void 0 : _a.transactions.length) || 0
89
- };
90
- }
91
- tryAddTransactions(sessionID, newTransactions, newHash, newSignature) {
92
- var _a;
93
- const signatoryID = this.node.expectAgentLoaded(
94
- agentIDfromSessionID(sessionID),
95
- "Expected to know signatory of transaction"
96
- ).signatoryID;
97
- if (!signatoryID) {
98
- console.warn("Unknown agent", agentIDfromSessionID(sessionID));
99
- return false;
100
- }
101
- const { expectedNewHash, newStreamingHash } = this.expectedNewHashAfter(
102
- sessionID,
103
- newTransactions
104
- );
105
- if (newHash !== expectedNewHash) {
106
- console.warn("Invalid hash", { newHash, expectedNewHash });
107
- return false;
108
- }
109
- if (!verify(newSignature, newHash, signatoryID)) {
110
- console.warn(
111
- "Invalid signature",
112
- newSignature,
113
- newHash,
114
- signatoryID
115
- );
116
- return false;
117
- }
118
- const transactions = ((_a = this.sessions[sessionID]) == null ? void 0 : _a.transactions) ?? [];
119
- transactions.push(...newTransactions);
120
- this.sessions[sessionID] = {
121
- transactions,
122
- lastHash: newHash,
123
- streamingHash: newStreamingHash,
124
- lastSignature: newSignature
125
- };
126
- this.content = void 0;
127
- const content = this.getCurrentContent();
128
- for (const listener of this.listeners) {
129
- listener(content);
130
- }
131
- return true;
132
- }
133
- subscribe(listener) {
134
- this.listeners.add(listener);
135
- listener(this.getCurrentContent());
136
- return () => {
137
- this.listeners.delete(listener);
138
- };
139
- }
140
- expectedNewHashAfter(sessionID, newTransactions) {
141
- var _a;
142
- const streamingHash = ((_a = this.sessions[sessionID]) == null ? void 0 : _a.streamingHash.clone()) ?? new StreamingHash();
143
- for (const transaction of newTransactions) {
144
- streamingHash.update(transaction);
145
- }
146
- const newStreamingHash = streamingHash.clone();
147
- return {
148
- expectedNewHash: streamingHash.digest(),
149
- newStreamingHash
150
- };
151
- }
152
- makeTransaction(changes, privacy) {
153
- const madeAt = Date.now();
154
- let transaction;
155
- if (privacy === "private") {
156
- const { secret: keySecret, id: keyID } = this.getCurrentReadKey();
157
- if (!keySecret) {
158
- throw new Error(
159
- "Can't make transaction without read key secret"
160
- );
161
- }
162
- transaction = {
163
- privacy: "private",
164
- madeAt,
165
- keyUsed: keyID,
166
- encryptedChanges: encryptForTransaction(changes, keySecret, {
167
- in: this.id,
168
- tx: this.nextTransactionID()
169
- })
170
- };
171
- } else {
172
- transaction = {
173
- privacy: "trusting",
174
- madeAt,
175
- changes
176
- };
177
- }
178
- const sessionID = this.node.ownSessionID;
179
- const { expectedNewHash } = this.expectedNewHashAfter(sessionID, [
180
- transaction
181
- ]);
182
- const signature = sign(
183
- this.node.agentCredential.signatorySecret,
184
- expectedNewHash
185
- );
186
- const success = this.tryAddTransactions(
187
- sessionID,
188
- [transaction],
189
- expectedNewHash,
190
- signature
191
- );
192
- if (success) {
193
- void this.node.sync.syncCoValue(this);
194
- }
195
- return success;
196
- }
197
- getCurrentContent() {
198
- if (this.content) {
199
- return this.content;
200
- }
201
- if (this.header.type === "comap") {
202
- this.content = new CoMap(this);
203
- } else if (this.header.type === "colist") {
204
- this.content = new CoList(this);
205
- } else if (this.header.type === "costream") {
206
- this.content = new CoStream(this);
207
- } else if (this.header.type === "static") {
208
- this.content = new Static(this);
209
- } else {
210
- throw new Error(`Unknown coValue type ${this.header.type}`);
211
- }
212
- return this.content;
213
- }
214
- getValidSortedTransactions() {
215
- const validTransactions = determineValidTransactions(this);
216
- const allTransactions = validTransactions.map(({ txID, tx }) => {
217
- if (tx.privacy === "trusting") {
218
- return {
219
- txID,
220
- madeAt: tx.madeAt,
221
- changes: tx.changes
222
- };
223
- } else {
224
- const readKey = this.getReadKey(tx.keyUsed);
225
- if (!readKey) {
226
- return void 0;
227
- } else {
228
- const decrytedChanges = decryptForTransaction(
229
- tx.encryptedChanges,
230
- readKey,
231
- {
232
- in: this.id,
233
- tx: txID
234
- }
235
- );
236
- if (!decrytedChanges) {
237
- console.error(
238
- "Failed to decrypt transaction despite having key"
239
- );
240
- return void 0;
241
- }
242
- return {
243
- txID,
244
- madeAt: tx.madeAt,
245
- changes: decrytedChanges
246
- };
247
- }
248
- }
249
- }).filter((x) => !!x);
250
- allTransactions.sort(
251
- (a, b) => a.madeAt - b.madeAt || (a.txID.sessionID < b.txID.sessionID ? -1 : 1) || a.txID.txIndex - b.txID.txIndex
252
- );
253
- return allTransactions;
254
- }
255
- getCurrentReadKey() {
256
- var _a;
257
- if (this.header.ruleset.type === "team") {
258
- const content = expectTeamContent(this.getCurrentContent());
259
- const currentKeyId = (_a = content.get("readKey")) == null ? void 0 : _a.keyID;
260
- if (!currentKeyId) {
261
- throw new Error("No readKey set");
262
- }
263
- const secret = this.getReadKey(currentKeyId);
264
- return {
265
- secret,
266
- id: currentKeyId
267
- };
268
- } else if (this.header.ruleset.type === "ownedByTeam") {
269
- return this.node.expectCoValueLoaded(this.header.ruleset.team).getCurrentReadKey();
270
- } else {
271
- throw new Error(
272
- "Only teams or values owned by teams have read secrets"
273
- );
274
- }
275
- }
276
- getReadKey(keyID) {
277
- var _a, _b, _c;
278
- if (this.header.ruleset.type === "team") {
279
- const content = expectTeamContent(this.getCurrentContent());
280
- const readKeyHistory = content.getHistory("readKey");
281
- for (const entry of readKeyHistory) {
282
- if (((_a = entry.value) == null ? void 0 : _a.keyID) === keyID) {
283
- const revealer = agentIDfromSessionID(entry.txID.sessionID);
284
- const revealerAgent = this.node.expectAgentLoaded(
285
- revealer,
286
- "Expected to know revealer"
287
- );
288
- const secret = openAs(
289
- entry.value.revelation,
290
- this.node.agentCredential.recipientSecret,
291
- revealerAgent.recipientID,
292
- {
293
- in: this.id,
294
- tx: entry.txID
295
- }
296
- );
297
- if (secret)
298
- return secret;
299
- }
300
- }
301
- for (const entry of readKeyHistory) {
302
- const encryptedPreviousKey = (_c = (_b = entry.value) == null ? void 0 : _b.previousKeys) == null ? void 0 : _c[keyID];
303
- if (entry.value && encryptedPreviousKey) {
304
- const sealingKeyID = entry.value.keyID;
305
- const sealingKeySecret = this.getReadKey(sealingKeyID);
306
- if (!sealingKeySecret) {
307
- continue;
308
- }
309
- const secret = unsealKeySecret(
310
- {
311
- sealed: keyID,
312
- sealing: sealingKeyID,
313
- encrypted: encryptedPreviousKey
314
- },
315
- sealingKeySecret
316
- );
317
- if (secret) {
318
- return secret;
319
- } else {
320
- console.error(
321
- `Sealing ${sealingKeyID} key didn't unseal ${keyID}`
322
- );
323
- }
324
- }
325
- }
326
- return void 0;
327
- } else if (this.header.ruleset.type === "ownedByTeam") {
328
- return this.node.expectCoValueLoaded(this.header.ruleset.team).getReadKey(keyID);
329
- } else {
330
- throw new Error(
331
- "Only teams or values owned by teams have read secrets"
332
- );
333
- }
334
- }
335
- getTeam() {
336
- if (this.header.ruleset.type !== "ownedByTeam") {
337
- throw new Error("Only values owned by teams have teams");
338
- }
339
- return new Team(
340
- expectTeamContent(
341
- this.node.expectCoValueLoaded(this.header.ruleset.team).getCurrentContent()
342
- ),
343
- this.node
344
- );
345
- }
346
- getTx(txID) {
347
- var _a;
348
- return (_a = this.sessions[txID.sessionID]) == null ? void 0 : _a.transactions[txID.txIndex];
349
- }
350
- newContentSince(knownState) {
351
- const newContent = {
352
- action: "newContent",
353
- coValueID: this.id,
354
- header: (knownState == null ? void 0 : knownState.header) ? void 0 : this.header,
355
- newContent: Object.fromEntries(
356
- Object.entries(this.sessions).map(([sessionID, log]) => {
357
- const newTransactions = log.transactions.slice(
358
- (knownState == null ? void 0 : knownState.sessions[sessionID]) || 0
359
- );
360
- if (newTransactions.length === 0 || !log.lastHash || !log.lastSignature) {
361
- return void 0;
362
- }
363
- return [
364
- sessionID,
365
- {
366
- after: (knownState == null ? void 0 : knownState.sessions[sessionID]) || 0,
367
- newTransactions,
368
- lastHash: log.lastHash,
369
- lastSignature: log.lastSignature
370
- }
371
- ];
372
- }).filter((x) => !!x)
373
- )
374
- };
375
- if (!newContent.header && Object.keys(newContent.newContent).length === 0) {
376
- return void 0;
377
- }
378
- return newContent;
379
- }
380
- getDependedOnCoValues() {
381
- return this.header.ruleset.type === "team" ? expectTeamContent(this.getCurrentContent()).keys().filter((k) => k.startsWith("co_agent")) : this.header.ruleset.type === "ownedByTeam" ? [this.header.ruleset.team] : [];
382
- }
383
- }
384
- export function getAgent(agentCredential) {
385
- return {
386
- signatoryID: getSignatoryID(agentCredential.signatorySecret),
387
- recipientID: getRecipientID(agentCredential.recipientSecret),
388
- publicNickname: agentCredential.publicNickname
389
- };
390
- }
391
- export function getAgentCoValueHeader(agent) {
392
- return {
393
- type: "comap",
394
- ruleset: {
395
- type: "agent",
396
- initialSignatoryID: agent.signatoryID,
397
- initialRecipientID: agent.recipientID
398
- },
399
- meta: null,
400
- createdAt: null,
401
- uniqueness: null,
402
- publicNickname: "agent" + (agent.publicNickname ? `-${agent.publicNickname}` : "")
403
- };
404
- }
405
- export function getAgentID(agent) {
406
- return coValueIDforHeader(getAgentCoValueHeader(agent));
407
- }
408
- export function newRandomAgentCredential(publicNickname) {
409
- const signatorySecret = newRandomSignatory();
410
- const recipientSecret = newRandomRecipient();
411
- return { signatorySecret, recipientSecret, publicNickname };
412
- }
413
- export function agentCredentialToBytes(cred) {
414
- if (cred.publicNickname) {
415
- throw new Error("Can't convert agent credential with publicNickname");
416
- }
417
- const bytes = new Uint8Array(64);
418
- const signatorySecretBytes = signatorySecretToBytes(cred.signatorySecret);
419
- if (signatorySecretBytes.length !== 32) {
420
- throw new Error("Invalid signatorySecret length");
421
- }
422
- bytes.set(signatorySecretBytes);
423
- const recipientSecretBytes = recipientSecretToBytes(cred.recipientSecret);
424
- if (recipientSecretBytes.length !== 32) {
425
- throw new Error("Invalid recipientSecret length");
426
- }
427
- bytes.set(recipientSecretBytes, 32);
428
- return bytes;
429
- }
430
- export function agentCredentialFromBytes(bytes) {
431
- if (bytes.length !== 64) {
432
- return void 0;
433
- }
434
- const signatorySecret = signatorySecretFromBytes(bytes.slice(0, 32));
435
- const recipientSecret = recipientSecretFromBytes(bytes.slice(32));
436
- return { signatorySecret, recipientSecret };
437
- }
@@ -1,122 +0,0 @@
1
- "use strict";
2
- import {
3
- getAgent,
4
- getAgentID,
5
- newRandomAgentCredential,
6
- newRandomSessionID
7
- } from "./coValue";
8
- import { LocalNode } from "./node";
9
- import { createdNowUnique, sign } from "./crypto";
10
- test("Can create coValue with new agent credentials and add transaction to it", () => {
11
- const agentCredential = newRandomAgentCredential("agent1");
12
- const node = new LocalNode(
13
- agentCredential,
14
- newRandomSessionID(getAgentID(getAgent(agentCredential)))
15
- );
16
- const coValue = node.createCoValue({
17
- type: "costream",
18
- ruleset: { type: "unsafeAllowAll" },
19
- meta: null,
20
- ...createdNowUnique()
21
- });
22
- const transaction = {
23
- privacy: "trusting",
24
- madeAt: Date.now(),
25
- changes: [
26
- {
27
- hello: "world"
28
- }
29
- ]
30
- };
31
- const { expectedNewHash } = coValue.expectedNewHashAfter(
32
- node.ownSessionID,
33
- [transaction]
34
- );
35
- expect(
36
- coValue.tryAddTransactions(
37
- node.ownSessionID,
38
- [transaction],
39
- expectedNewHash,
40
- sign(agentCredential.signatorySecret, expectedNewHash)
41
- )
42
- ).toBe(true);
43
- });
44
- test("transactions with wrong signature are rejected", () => {
45
- const wrongAgent = newRandomAgentCredential("wrongAgent");
46
- const agentCredential = newRandomAgentCredential("agent1");
47
- const node = new LocalNode(
48
- agentCredential,
49
- newRandomSessionID(getAgentID(getAgent(agentCredential)))
50
- );
51
- const coValue = node.createCoValue({
52
- type: "costream",
53
- ruleset: { type: "unsafeAllowAll" },
54
- meta: null,
55
- ...createdNowUnique()
56
- });
57
- const transaction = {
58
- privacy: "trusting",
59
- madeAt: Date.now(),
60
- changes: [
61
- {
62
- hello: "world"
63
- }
64
- ]
65
- };
66
- const { expectedNewHash } = coValue.expectedNewHashAfter(
67
- node.ownSessionID,
68
- [transaction]
69
- );
70
- expect(
71
- coValue.tryAddTransactions(
72
- node.ownSessionID,
73
- [transaction],
74
- expectedNewHash,
75
- sign(wrongAgent.signatorySecret, expectedNewHash)
76
- )
77
- ).toBe(false);
78
- });
79
- test("transactions with correctly signed, but wrong hash are rejected", () => {
80
- const agentCredential = newRandomAgentCredential("agent1");
81
- const node = new LocalNode(
82
- agentCredential,
83
- newRandomSessionID(getAgentID(getAgent(agentCredential)))
84
- );
85
- const coValue = node.createCoValue({
86
- type: "costream",
87
- ruleset: { type: "unsafeAllowAll" },
88
- meta: null,
89
- ...createdNowUnique()
90
- });
91
- const transaction = {
92
- privacy: "trusting",
93
- madeAt: Date.now(),
94
- changes: [
95
- {
96
- hello: "world"
97
- }
98
- ]
99
- };
100
- const { expectedNewHash } = coValue.expectedNewHashAfter(
101
- node.ownSessionID,
102
- [
103
- {
104
- privacy: "trusting",
105
- madeAt: Date.now(),
106
- changes: [
107
- {
108
- hello: "wrong"
109
- }
110
- ]
111
- }
112
- ]
113
- );
114
- expect(
115
- coValue.tryAddTransactions(
116
- node.ownSessionID,
117
- [transaction],
118
- expectedNewHash,
119
- sign(agentCredential.signatorySecret, expectedNewHash)
120
- )
121
- ).toBe(false);
122
- });
@@ -1,7 +0,0 @@
1
- "use strict";
2
- export function expectMap(content) {
3
- if (content.type !== "comap") {
4
- throw new Error("Expected map");
5
- }
6
- return content;
7
- }