Compare commits

...

33 Commits

Author SHA1 Message Date
Anselm
406ab9b0da Hotfix release 2024-08-21 15:24:27 +01:00
Anselm
140f6616cb Remove WS buffer filling log message 2024-08-21 15:23:41 +01:00
Anselm
b09589b15e Hotfix release 2024-08-21 11:39:18 +01:00
Anselm
00638897f4 only one async transaction per covalue again 2024-08-21 11:36:47 +01:00
Anselm
5094e6d536 Hotfix release 2024-08-20 18:03:01 +01:00
Anselm
39242e7f68 Start introducing neverthrow, make tryAddNewTransactionsAsync and handleNewContent less throwy 2024-08-20 18:02:26 +01:00
Anselm Eickhoff
be7e208b1c Merge pull request #333 from gardencmp/anselm-jazz-265
Make sure errors in storage peer completely crash jazz context instead of failing silently
2024-08-20 14:09:19 +01:00
Anselm
c3bffbf4de Release 2024-08-20 14:02:53 +01:00
Anselm
d46467f318 Hotfix release 2024-08-20 12:58:09 +01:00
Anselm
6d21400803 Get rid of simulated errors 2024-08-20 12:57:50 +01:00
Anselm
db53161296 Hotfix release 2024-08-20 12:46:15 +01:00
Anselm
cb4a116cec Make simulated errors even more likely 2024-08-20 12:45:34 +01:00
Anselm
013199b9b2 Increase chance of simulated storage bug 2024-08-20 11:43:28 +01:00
Anselm
a8b74ff703 Hotfix release 2024-08-20 11:43:20 +01:00
Anselm
b1985a9161 Throw properly on peer that should crash on close 2024-08-20 11:42:53 +01:00
Anselm
3bf512719f Hotfix release 2024-08-20 11:22:44 +01:00
Anselm
d83ed69d41 Allow crashing whole local node on peer errors 2024-08-20 11:20:20 +01:00
Anselm
fdde8db664 Hotfix release 2024-08-19 17:19:40 +01:00
Anselm
dd5581ba2d Handle ws closing while buffering 2024-08-19 17:19:01 +01:00
Anselm
07fe2b9dcf Release 2024-08-19 16:45:35 +01:00
Anselm
b297c93b80 Release fixes 2024-08-19 15:08:08 +01:00
Anselm
d2e62e5b44 Reduce log level on loading message 2024-08-19 14:50:26 +01:00
Anselm
fe73ce7514 Make failed transaction log message leaner 2024-08-19 14:48:57 +01:00
Anselm Eickhoff
0fed16cea4 Merge pull request #323 from gardencmp/callumflack-jazz-240
fix: chat example URL
2024-08-19 11:15:39 +01:00
Callum Flack
08804ad435 fix: chat example URL 2024-08-19 11:03:33 +10:00
Anselm
79fa7724ad Release 2024-08-15 19:35:11 +01:00
Anselm
4604c2184a Adapt type of applyDiff to make CoMaps fully subclassable again 2024-08-15 19:34:47 +01:00
Anselm
11bac697fb Release 2024-08-15 19:23:19 +01:00
Anselm
96cec27f89 Close both ends of the peer on gracefulShutdown 2024-08-15 19:22:59 +01:00
Anselm
bcd412b8f9 Properly close connecting websockets 2024-08-15 19:22:19 +01:00
Anselm
6b456e2841 Properly close and delete peer on incoming disconnect/timeout 2024-08-15 19:10:22 +01:00
Anselm
1df72b3dc8 Reintroduce nomad example deploy, but only on main 2024-08-15 19:08:42 +01:00
Anselm
402d692739 Don't deploy examples to Nomad anymore 2024-08-15 17:02:40 +01:00
51 changed files with 1842 additions and 307 deletions

View File

@@ -0,0 +1,5 @@
---
"cojson": patch
---
Start introducing neverthrow, make tryAddNewTransactionsAsync and handleNewContent less throwy

View File

@@ -0,0 +1,5 @@
---
"cojson": patch
---
Only one async transaction per CoValue at a time again

26
.changeset/pre.json Normal file
View File

@@ -0,0 +1,26 @@
{
"mode": "pre",
"tag": "neverthrow",
"initialVersions": {
"jazz-example-chat": "0.0.80",
"jazz-inspector": "0.0.58",
"jazz-example-pets": "0.0.98",
"jazz-example-todo": "0.0.97",
"cojson": "0.7.33",
"cojson-storage-indexeddb": "0.7.33",
"cojson-storage-sqlite": "0.7.33",
"cojson-transport-ws": "0.7.33",
"hash-slash": "0.2.0",
"jazz-browser": "0.7.33",
"jazz-browser-media-images": "0.7.33",
"jazz-nodejs": "0.7.33",
"jazz-react": "0.7.33",
"jazz-run": "0.7.33",
"jazz-tools": "0.7.33"
},
"changesets": [
"early-files-lick",
"mighty-cameras-tickle",
"rich-tigers-cross"
]
}

View File

@@ -0,0 +1,5 @@
---
"cojson-transport-ws": patch
---
Remove WS buffer filling log message

View File

@@ -3,8 +3,6 @@ name: Build and Deploy
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-examples:

View File

@@ -1,5 +1,106 @@
# jazz-example-chat
## 0.0.81-neverthrow.2
### Patch Changes
- jazz-react@0.7.34-neverthrow.2
## 0.0.81-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
- jazz-react@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
## 0.0.81-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
- jazz-react@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
## 0.0.80
### Patch Changes
- Updated dependencies [b297c93]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson@0.7.33
- jazz-react@0.7.33
- jazz-tools@0.7.33
## 0.0.80-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
- jazz-react@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
## 0.0.80-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
- jazz-react@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
## 0.0.80-hotfixes.3
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.3
- jazz-react@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
## 0.0.80-hotfixes.2
### Patch Changes
- jazz-react@0.7.33-hotfixes.2
## 0.0.80-hotfixes.1
### Patch Changes
- jazz-react@0.7.33-hotfixes.1
## 0.0.80-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
- jazz-react@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
## 0.0.79
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.32
- jazz-react@0.7.32
## 0.0.78
### Patch Changes
- Updated dependencies
- cojson@0.7.31
- jazz-react@0.7.31
- jazz-tools@0.7.31
## 0.0.77
### Patch Changes

View File

@@ -1,12 +1,13 @@
# Jazz Chat Example
Live version: https://example-chat.jazz.tools
Live version: [https://chat.jazz.tools](https://chat.jazz.tools)
## Installing & running the example locally
(this requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation))
Start by checking out `jazz`
```bash
git clone https://github.com/gardencmp/jazz.git
cd jazz/examples/chat
@@ -34,7 +35,6 @@ pnpm dev
If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
## Configuration: sync server
By default, the example app uses [Jazz Global Mesh](https://jazz.tools/mesh) (`wss://sync.jazz.tools`) - so cross-device use, invites and collaboration should just work.

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.77",
"version": "0.0.81-neverthrow.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,96 @@
# jazz-example-chat
## 0.0.59-neverthrow.2
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.34-neverthrow.2
## 0.0.59-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
- cojson-transport-ws@0.7.34-neverthrow.1
## 0.0.59-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
- cojson-transport-ws@0.7.34-neverthrow.0
## 0.0.58
### Patch Changes
- Updated dependencies [fdde8db]
- Updated dependencies [b297c93]
- Updated dependencies [07fe2b9]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson-transport-ws@0.7.33
- cojson@0.7.33
## 0.0.58-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
- cojson-transport-ws@0.7.33-hotfixes.5
## 0.0.58-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
- cojson-transport-ws@0.7.33-hotfixes.4
## 0.0.58-hotfixes.3
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.3
- cojson@0.7.33-hotfixes.3
## 0.0.58-hotfixes.2
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.2
## 0.0.58-hotfixes.1
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.1
## 0.0.58-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
- cojson-transport-ws@0.7.33-hotfixes.0
## 0.0.57
### Patch Changes
- Updated dependencies
- Updated dependencies
- cojson-transport-ws@0.7.31
- cojson@0.7.31
## 0.0.56
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector",
"private": true,
"version": "0.0.56",
"version": "0.0.59-neverthrow.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,99 @@
# jazz-example-pets
## 0.0.99-neverthrow.2
### Patch Changes
- jazz-browser-media-images@0.7.34-neverthrow.2
- jazz-react@0.7.34-neverthrow.2
## 0.0.99-neverthrow.1
### Patch Changes
- jazz-react@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
- jazz-browser-media-images@0.7.34-neverthrow.1
## 0.0.99-neverthrow.0
### Patch Changes
- jazz-react@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
- jazz-browser-media-images@0.7.34-neverthrow.0
## 0.0.98
### Patch Changes
- jazz-react@0.7.33
- jazz-tools@0.7.33
- jazz-browser-media-images@0.7.33
## 0.0.98-hotfixes.5
### Patch Changes
- jazz-react@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
- jazz-browser-media-images@0.7.33-hotfixes.5
## 0.0.98-hotfixes.4
### Patch Changes
- jazz-react@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
- jazz-browser-media-images@0.7.33-hotfixes.4
## 0.0.98-hotfixes.3
### Patch Changes
- jazz-react@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
- jazz-browser-media-images@0.7.33-hotfixes.3
## 0.0.98-hotfixes.2
### Patch Changes
- jazz-browser-media-images@0.7.33-hotfixes.2
- jazz-react@0.7.33-hotfixes.2
## 0.0.98-hotfixes.1
### Patch Changes
- jazz-browser-media-images@0.7.33-hotfixes.1
- jazz-react@0.7.33-hotfixes.1
## 0.0.98-hotfixes.0
### Patch Changes
- jazz-react@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
- jazz-browser-media-images@0.7.33-hotfixes.0
## 0.0.97
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.32
- jazz-browser-media-images@0.7.32
- jazz-react@0.7.32
## 0.0.96
### Patch Changes
- jazz-react@0.7.31
- jazz-tools@0.7.31
- jazz-browser-media-images@0.7.31
## 0.0.95
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.95",
"version": "0.0.99-neverthrow.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,87 @@
# jazz-example-todo
## 0.0.98-neverthrow.2
### Patch Changes
- jazz-react@0.7.34-neverthrow.2
## 0.0.98-neverthrow.1
### Patch Changes
- jazz-react@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
## 0.0.98-neverthrow.0
### Patch Changes
- jazz-react@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
## 0.0.97
### Patch Changes
- jazz-react@0.7.33
- jazz-tools@0.7.33
## 0.0.97-hotfixes.5
### Patch Changes
- jazz-react@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
## 0.0.97-hotfixes.4
### Patch Changes
- jazz-react@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
## 0.0.97-hotfixes.3
### Patch Changes
- jazz-react@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
## 0.0.97-hotfixes.2
### Patch Changes
- jazz-react@0.7.33-hotfixes.2
## 0.0.97-hotfixes.1
### Patch Changes
- jazz-react@0.7.33-hotfixes.1
## 0.0.97-hotfixes.0
### Patch Changes
- jazz-react@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
## 0.0.96
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.32
- jazz-react@0.7.32
## 0.0.95
### Patch Changes
- jazz-react@0.7.31
- jazz-tools@0.7.31
## 0.0.94
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.94",
"version": "0.0.98-neverthrow.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,66 @@
# cojson-storage-indexeddb
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- 3bf5127: Allow crashing whole node on peer errors
- Updated dependencies [b297c93]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson@0.7.33
## 0.7.33-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Allow crashing whole node on peer errors
- Updated dependencies
- cojson@0.7.33-hotfixes.3
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
## 0.7.31
### Patch Changes
- Updated dependencies
- cojson@0.7.31
## 0.7.29
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "cojson-storage-indexeddb",
"version": "0.7.29",
"version": "0.7.34-neverthrow.1",
"main": "dist/index.js",
"type": "module",
"types": "src/index.ts",

View File

@@ -92,7 +92,7 @@ export class IDBStorage {
const [localNodeAsPeer, storageAsPeer] = cojsonInternals.connectedPeers(
localNodeName,
"storage",
{ peer1role: "client", peer2role: "server", trace },
{ peer1role: "client", peer2role: "server", trace, crashOnClose: true },
);
await IDBStorage.open(

View File

@@ -1,5 +1,73 @@
# cojson-storage-sqlite
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- 3bf5127: Allow crashing whole node on peer errors
- Updated dependencies [b297c93]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson@0.7.33
## 0.7.33-hotfixes.6
### Patch Changes
- Get rid of simulated errors
## 0.7.33-hotfixes.5
### Patch Changes
- Make simulated errors even more likely
- Updated dependencies
- cojson@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Allow crashing whole node on peer errors
- Updated dependencies
- cojson@0.7.33-hotfixes.3
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
## 0.7.31
### Patch Changes
- Updated dependencies
- cojson@0.7.31
## 0.7.29
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.7.29",
"version": "0.7.34-neverthrow.1",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",

View File

@@ -94,7 +94,7 @@ export class SQLiteStorage {
const [localNodeAsPeer, storageAsPeer] = cojsonInternals.connectedPeers(
localNodeName,
"storage",
{ peer1role: "client", peer2role: "server", trace },
{ peer1role: "client", peer2role: "server", trace, crashOnClose: true },
);
await SQLiteStorage.open(

View File

@@ -1,5 +1,87 @@
# cojson-transport-nodejs-ws
## 0.7.34-neverthrow.2
### Patch Changes
- Remove WS buffer filling log message
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- fdde8db: Handle ws closing while buffering
- 07fe2b9: Wait if WS buffer is full
- 3bf5127: Allow crashing whole node on peer errors
- Updated dependencies [b297c93]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson@0.7.33
## 0.7.33-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Allow crashing whole node on peer errors
- Updated dependencies
- cojson@0.7.33-hotfixes.3
## 0.7.33-hotfixes.2
### Patch Changes
- Handle ws closing while buffering
## 0.7.33-hotfixes.1
### Patch Changes
- Wait if WS buffer is full
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
## 0.7.31
### Patch Changes
- Properly close connecting websockets
- Updated dependencies
- cojson@0.7.31
## 0.7.30
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-transport-ws",
"type": "module",
"version": "0.7.30",
"version": "0.7.34-neverthrow.2",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",

View File

@@ -29,6 +29,7 @@ interface AnyWebSocket {
close(): void;
send(data: string): void;
readyState: number;
bufferedAmount: number;
}
const g: typeof globalThis & {
@@ -108,15 +109,30 @@ export function createWebSocketPeer({
async push(msg) {
await websocketOpen;
if (websocket.readyState === 1) {
while (websocket.bufferedAmount > 1_000_000) {
await new Promise((resolve) =>
setTimeout(resolve, 100),
);
if (websocket.readyState !== 1) {
console.log("WebSocket closed while buffering", id, websocket.bufferedAmount);
return;
}
}
websocket.send(JSON.stringify(msg));
}
},
close() {
if (websocket.readyState === 1) {
console.log("Trying to close", id, websocket.readyState)
if (websocket.readyState === 0) {
websocket.addEventListener("open", function handleClose() {
websocket.close();
}, { once: true });
} else if (websocket.readyState == 1) {
websocket.close();
}
},
},
role,
crashOnClose: false,
};
}

View File

@@ -3,10 +3,10 @@ module.exports = {
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:require-extensions/recommended",
"prettier"
"prettier",
],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint", "require-extensions"],
plugins: ["@typescript-eslint", "require-extensions", "neverthrow"],
parserOptions: {
project: "./tsconfig.json",
tsconfigRootDir: __dirname,
@@ -20,5 +20,6 @@ module.exports = {
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
],
"@typescript-eslint/no-floating-promises": "error",
"neverthrow/must-use-result": "error",
},
}
};

View File

@@ -1,5 +1,55 @@
# cojson
## 0.7.34-neverthrow.1
### Patch Changes
- Only one async transaction per CoValue at a time again
## 0.7.34-neverthrow.0
### Patch Changes
- Start introducing neverthrow, make tryAddNewTransactionsAsync and handleNewContent less throwy
## 0.7.33
### Patch Changes
- b297c93: Improve logging
- 3bf5127: Allow crashing whole node on peer errors
- a8b74ff: Throw properly on peer that should crash on close
## 0.7.33-hotfixes.5
### Patch Changes
- Make simulated errors even more likely
## 0.7.33-hotfixes.4
### Patch Changes
- Throw properly on peer that should crash on close
## 0.7.33-hotfixes.3
### Patch Changes
- Allow crashing whole node on peer errors
## 0.7.33-hotfixes.0
### Patch Changes
- Improve logging
## 0.7.31
### Patch Changes
- Close both ends of the peer on gracefulShutdown
## 0.7.29
### Patch Changes

View File

@@ -5,13 +5,14 @@
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.7.29",
"version": "0.7.34-neverthrow.1",
"devDependencies": {
"@types/jest": "^29.5.3",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"eslint": "^8.46.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-neverthrow": "^1.1.4",
"eslint-plugin-require-extensions": "^0.1.3",
"typescript": "5.0.2",
"vitest": "^0.34.6"
@@ -23,6 +24,7 @@
"@noble/hashes": "^1.4.0",
"@scure/base": "^1.1.1",
"hash-wasm": "^4.9.0",
"neverthrow": "^7.0.1",
"queueable": "^5.3.2"
},
"scripts": {

View File

@@ -7,6 +7,7 @@ import {
StreamingHash,
KeyID,
CryptoProvider,
SignerID,
} from "./crypto/crypto.js";
import { JsonObject, JsonValue } from "./jsonValue.js";
import { base58 } from "@scure/base";
@@ -16,7 +17,7 @@ import {
isKeyForKeyField,
} from "./permissions.js";
import { RawGroup } from "./coValues/group.js";
import { LocalNode } from "./localNode.js";
import { LocalNode, ResolveAccountAgentError } from "./localNode.js";
import { CoValueKnownState, NewContentMessage } from "./sync.js";
import { AgentID, RawCoID, SessionID, TransactionID } from "./ids.js";
import { AccountID, ControlledAccountOrAgent } from "./coValues/account.js";
@@ -25,6 +26,7 @@ import { coreToCoValue } from "./coreToCoValue.js";
import { expectGroup } from "./typeUtils/expectGroup.js";
import { isAccountID } from "./typeUtils/isAccountID.js";
import { accountOrAgentIDfromSessionID } from "./typeUtils/accountOrAgentIDfromSessionID.js";
import { err, ok, Result, ResultAsync } from "neverthrow";
/**
In order to not block other concurrently syncing CoValues we introduce a maximum size of transactions,
@@ -103,10 +105,10 @@ export class CoValueCore {
_decryptionCache: {
[key: Encrypted<JsonValue[], JsonValue>]: JsonValue[] | undefined;
} = {};
currentlyAsyncApplyingTxDone?: Promise<void>;
_cachedKnownState?: CoValueKnownState;
_cachedDependentOn?: RawCoID[];
_cachedNewContentSinceEmpty?: NewContentMessage[] | undefined;
_currentAsyncAddTransaction?: Promise<void>;
constructor(
header: CoValueHeader,
@@ -182,7 +184,9 @@ export class CoValueCore {
this.header.meta?.type === "account"
? (this.node.currentSessionID.replace(
this.node.account.id,
this.node.account.currentAgentID(),
this.node.account
.currentAgentID()
._unsafeUnwrap({ withStackTrace: true }),
) as SessionID)
: this.node.currentSessionID;
@@ -197,166 +201,197 @@ export class CoValueCore {
newTransactions: Transaction[],
givenExpectedNewHash: Hash | undefined,
newSignature: Signature,
): boolean {
const signerID = this.crypto.getAgentSignerID(
this.node.resolveAccountAgent(
): Result<true, TryAddTransactionsError> {
return this.node
.resolveAccountAgent(
accountOrAgentIDfromSessionID(sessionID),
"Expected to know signer of transaction",
),
);
)
.andThen((agent) => {
const signerID = this.crypto.getAgentSignerID(agent);
if (!signerID) {
console.warn(
"Unknown agent",
accountOrAgentIDfromSessionID(sessionID),
);
return false;
}
// const beforeHash = performance.now();
const { expectedNewHash, newStreamingHash } =
this.expectedNewHashAfter(sessionID, newTransactions);
// const afterHash = performance.now();
// console.log(
// "Hashing took",
// afterHash - beforeHash
// );
// const beforeHash = performance.now();
const { expectedNewHash, newStreamingHash } = this.expectedNewHashAfter(
sessionID,
newTransactions,
);
// const afterHash = performance.now();
// console.log(
// "Hashing took",
// afterHash - beforeHash
// );
if (
givenExpectedNewHash &&
givenExpectedNewHash !== expectedNewHash
) {
return err({
type: "InvalidHash",
id: this.id,
expectedNewHash,
givenExpectedNewHash,
} satisfies InvalidHashError);
}
if (givenExpectedNewHash && givenExpectedNewHash !== expectedNewHash) {
console.warn("Invalid hash", {
expectedNewHash,
givenExpectedNewHash,
// const beforeVerify = performance.now();
if (
!this.crypto.verify(newSignature, expectedNewHash, signerID)
) {
return err({
type: "InvalidSignature",
id: this.id,
newSignature,
sessionID,
signerID,
} satisfies InvalidSignatureError);
}
// const afterVerify = performance.now();
// console.log(
// "Verify took",
// afterVerify - beforeVerify
// );
this.doAddTransactions(
sessionID,
newTransactions,
newSignature,
expectedNewHash,
newStreamingHash,
"immediate",
);
return ok(true as const);
});
return false;
}
// const beforeVerify = performance.now();
if (!this.crypto.verify(newSignature, expectedNewHash, signerID)) {
console.warn(
"Invalid signature in",
this.id,
newSignature,
expectedNewHash,
signerID,
);
return false;
}
// const afterVerify = performance.now();
// console.log(
// "Verify took",
// afterVerify - beforeVerify
// );
this.doAddTransactions(
sessionID,
newTransactions,
newSignature,
expectedNewHash,
newStreamingHash,
"immediate",
);
return true;
}
async tryAddTransactionsAsync(
tryAddTransactionsAsync(
sessionID: SessionID,
newTransactions: Transaction[],
givenExpectedNewHash: Hash | undefined,
newSignature: Signature,
): Promise<boolean> {
if (this.currentlyAsyncApplyingTxDone) {
await this.currentlyAsyncApplyingTxDone;
}
let resolveDone!: () => void;
): ResultAsync<true, TryAddTransactionsError> {
const currentAsyncAddTransaction = this._currentAsyncAddTransaction;
let maybeAwaitPrevious:
| ResultAsync<void, TryAddTransactionsError>
| undefined;
let thisDone = () => {};
this.currentlyAsyncApplyingTxDone = new Promise((resolve) => {
resolveDone = resolve;
});
const signerID = this.crypto.getAgentSignerID(
await this.node.resolveAccountAgentAsync(
accountOrAgentIDfromSessionID(sessionID),
"Expected to know signer of transaction",
),
);
if (!signerID) {
console.warn(
"Unknown agent",
accountOrAgentIDfromSessionID(sessionID),
if (currentAsyncAddTransaction) {
// eslint-disable-next-line neverthrow/must-use-result
maybeAwaitPrevious = ResultAsync.fromSafePromise(
currentAsyncAddTransaction,
);
resolveDone();
return false;
}
const nTxBefore =
this.sessionLogs.get(sessionID)?.transactions.length ?? 0;
// const beforeHash = performance.now();
const { expectedNewHash, newStreamingHash } =
await this.expectedNewHashAfterAsync(sessionID, newTransactions);
// const afterHash = performance.now();
// console.log(
// "Hashing took",
// afterHash - beforeHash
// );
const nTxAfter =
this.sessionLogs.get(sessionID)?.transactions.length ?? 0;
if (nTxAfter !== nTxBefore) {
const newTransactionLengthBefore = newTransactions.length;
newTransactions = newTransactions.slice(nTxAfter - nTxBefore);
console.warn("Transactions changed while async hashing", {
nTxBefore,
nTxAfter,
newTransactionLengthBefore,
remainingNewTransactions: newTransactions.length,
} else {
// eslint-disable-next-line neverthrow/must-use-result
maybeAwaitPrevious = ResultAsync.fromSafePromise(Promise.resolve());
this._currentAsyncAddTransaction = new Promise((resolve) => {
thisDone = resolve;
});
}
if (givenExpectedNewHash && givenExpectedNewHash !== expectedNewHash) {
console.warn("Invalid hash", {
expectedNewHash,
givenExpectedNewHash,
return maybeAwaitPrevious
.andThen((_previousDone) =>
this.node
.resolveAccountAgentAsync(
accountOrAgentIDfromSessionID(sessionID),
"Expected to know signer of transaction",
)
.andThen((agent) => {
const signerID = this.crypto.getAgentSignerID(agent);
const nTxBefore =
this.sessionLogs.get(sessionID)?.transactions
.length ?? 0;
// const beforeHash = performance.now();
return ResultAsync.fromSafePromise(
this.expectedNewHashAfterAsync(
sessionID,
newTransactions,
),
).andThen(({ expectedNewHash, newStreamingHash }) => {
// const afterHash = performance.now();
// console.log(
// "Hashing took",
// afterHash - beforeHash
// );
const nTxAfter =
this.sessionLogs.get(sessionID)?.transactions
.length ?? 0;
if (nTxAfter !== nTxBefore) {
const newTransactionLengthBefore =
newTransactions.length;
newTransactions = newTransactions.slice(
nTxAfter - nTxBefore,
);
console.warn(
"Transactions changed while async hashing",
{
nTxBefore,
nTxAfter,
newTransactionLengthBefore,
remainingNewTransactions:
newTransactions.length,
},
);
}
if (
givenExpectedNewHash &&
givenExpectedNewHash !== expectedNewHash
) {
return err({
type: "InvalidHash",
id: this.id,
expectedNewHash,
givenExpectedNewHash,
} satisfies InvalidHashError);
}
performance.mark("verifyStart" + this.id);
if (
!this.crypto.verify(
newSignature,
expectedNewHash,
signerID,
)
) {
return err({
type: "InvalidSignature",
id: this.id,
newSignature,
sessionID,
signerID,
} satisfies InvalidSignatureError);
}
performance.mark("verifyEnd" + this.id);
performance.measure(
"verify" + this.id,
"verifyStart" + this.id,
"verifyEnd" + this.id,
);
this.doAddTransactions(
sessionID,
newTransactions,
newSignature,
expectedNewHash,
newStreamingHash,
"deferred",
);
return ok(true as const);
});
}),
)
.map((trueResult) => {
thisDone();
return trueResult;
})
.mapErr((err) => {
thisDone();
return err;
});
resolveDone();
return false;
}
performance.mark("verifyStart" + this.id);
if (!this.crypto.verify(newSignature, expectedNewHash, signerID)) {
console.warn(
"Invalid signature in",
this.id,
newSignature,
expectedNewHash,
signerID,
);
resolveDone();
return false;
}
performance.mark("verifyEnd" + this.id);
performance.measure(
"verify" + this.id,
"verifyStart" + this.id,
"verifyEnd" + this.id,
);
this.doAddTransactions(
sessionID,
newTransactions,
newSignature,
expectedNewHash,
newStreamingHash,
"deferred",
);
resolveDone();
return true;
}
private doAddTransactions(
@@ -367,6 +402,9 @@ export class CoValueCore {
newStreamingHash: StreamingHash,
notifyMode: "immediate" | "deferred",
) {
if (this.node.crashed) {
throw new Error("Trying to add transactions after node is crashed");
}
const transactions =
this.sessionLogs.get(sessionID)?.transactions ?? [];
transactions.push(...newTransactions);
@@ -542,7 +580,9 @@ export class CoValueCore {
this.header.meta?.type === "account"
? (this.node.currentSessionID.replace(
this.node.account.id,
this.node.account.currentAgentID(),
this.node.account
.currentAgentID()
._unsafeUnwrap({ withStackTrace: true }),
) as SessionID)
: this.node.currentSessionID;
@@ -560,7 +600,7 @@ export class CoValueCore {
[transaction],
expectedNewHash,
signature,
);
)._unsafeUnwrap({ withStackTrace: true });
if (success) {
void this.node.syncManager.syncCoValue(this);
@@ -706,7 +746,9 @@ export class CoValueCore {
// Try to find key revelation for us
const lookupAccountOrAgentID =
this.header.meta?.type === "account"
? this.node.account.currentAgentID()
? this.node.account
.currentAgentID()
._unsafeUnwrap({ withStackTrace: true })
: this.node.account.id;
const lastReadyKeyEdit = content.lastEditAt(
@@ -715,10 +757,9 @@ export class CoValueCore {
if (lastReadyKeyEdit?.value) {
const revealer = lastReadyKeyEdit.by;
const revealerAgent = this.node.resolveAccountAgent(
revealer,
"Expected to know revealer",
);
const revealerAgent = this.node
.resolveAccountAgent(revealer, "Expected to know revealer")
._unsafeUnwrap({ withStackTrace: true });
const secret = this.crypto.unseal(
lastReadyKeyEdit.value,
@@ -983,3 +1024,23 @@ function getNextKnownSignatureIdx(
idx >= (sentStateForSessionID ?? knownStateForSessionID ?? -1),
);
}
export type InvalidHashError = {
type: "InvalidHash";
id: RawCoID;
expectedNewHash: Hash;
givenExpectedNewHash: Hash;
};
export type InvalidSignatureError = {
type: "InvalidSignature";
id: RawCoID;
newSignature: Signature;
sessionID: SessionID;
signerID: SignerID;
};
export type TryAddTransactionsError =
| ResolveAccountAgentError
| InvalidHashError
| InvalidSignatureError;

View File

@@ -13,6 +13,7 @@ import { RawCoMap } from "./coMap.js";
import { RawGroup, InviteSecret } from "./group.js";
import { LocalNode } from "../index.js";
import { JsonObject } from "../jsonValue.js";
import { err, ok, Result } from "neverthrow";
export function accountHeaderForInitialAgentSecret(
agentSecret: AgentSecret,
@@ -30,28 +31,34 @@ export function accountHeaderForInitialAgentSecret(
};
}
export type InvalidAccountAgentIDError = {
type: "InvalidAccountAgentID";
reason: string;
};
export class RawAccount<
Meta extends AccountMeta = AccountMeta,
> extends RawGroup<Meta> {
_cachedCurrentAgentID: AgentID | undefined;
currentAgentID(): AgentID {
currentAgentID(): Result<AgentID, InvalidAccountAgentIDError> {
if (this._cachedCurrentAgentID) {
return this._cachedCurrentAgentID;
return ok(this._cachedCurrentAgentID);
}
const agents = this.keys().filter((k): k is AgentID =>
k.startsWith("sealer_"),
);
if (agents.length !== 1) {
throw new Error(
"Expected exactly one agent in account, got " + agents.length,
);
return err({
type: "InvalidAccountAgentID",
reason: "Account has " + agents.length + " agents",
});
}
this._cachedCurrentAgentID = agents[0];
return agents[0]!;
return ok(agents[0]!);
}
}
@@ -59,10 +66,10 @@ export interface ControlledAccountOrAgent {
id: AccountID | AgentID;
agentSecret: AgentSecret;
currentAgentID: () => AgentID;
currentSignerID: () => SignerID;
currentAgentID: () => Result<AgentID, InvalidAccountAgentIDError>;
currentSignerID: () => Result<SignerID, InvalidAccountAgentIDError>;
currentSignerSecret: () => SignerSecret;
currentSealerID: () => SealerID;
currentSealerID: () => Result<SealerID, InvalidAccountAgentIDError>;
currentSealerSecret: () => SealerSecret;
}
@@ -96,25 +103,29 @@ export class RawControlledAccount<Meta extends AccountMeta = AccountMeta>
return this.core.node.acceptInvite(groupOrOwnedValueID, inviteSecret);
}
currentAgentID(): AgentID {
currentAgentID(): Result<AgentID, InvalidAccountAgentIDError> {
if (this._cachedCurrentAgentID) {
return this._cachedCurrentAgentID;
return ok(this._cachedCurrentAgentID);
}
const agentID = this.crypto.getAgentID(this.agentSecret);
this._cachedCurrentAgentID = agentID;
return agentID;
return ok(agentID);
}
currentSignerID(): SignerID {
return this.crypto.getAgentSignerID(this.currentAgentID());
currentSignerID() {
return this.currentAgentID().map((id) =>
this.crypto.getAgentSignerID(id),
);
}
currentSignerSecret(): SignerSecret {
return this.crypto.getAgentSignerSecret(this.agentSecret);
}
currentSealerID(): SealerID {
return this.crypto.getAgentSealerID(this.currentAgentID());
currentSealerID() {
return this.currentAgentID().map((id) =>
this.crypto.getAgentSealerID(id),
);
}
currentSealerSecret(): SealerSecret {
@@ -133,20 +144,24 @@ export class ControlledAgent implements ControlledAccountOrAgent {
return this.crypto.getAgentID(this.agentSecret);
}
currentAgentID(): AgentID {
return this.crypto.getAgentID(this.agentSecret);
currentAgentID() {
return ok(this.crypto.getAgentID(this.agentSecret));
}
currentSignerID(): SignerID {
return this.crypto.getAgentSignerID(this.currentAgentID());
currentSignerID() {
return this.currentAgentID().map((id) =>
this.crypto.getAgentSignerID(id),
);
}
currentSignerSecret(): SignerSecret {
return this.crypto.getAgentSignerSecret(this.agentSecret);
}
currentSealerID(): SealerID {
return this.crypto.getAgentSealerID(this.currentAgentID());
currentSealerID() {
return this.currentAgentID().map((id) =>
this.crypto.getAgentSealerID(id),
);
}
currentSealerSecret(): SealerSecret {

View File

@@ -120,7 +120,9 @@ export class RawGroup<
const agent =
typeof account === "string"
? account
: account.currentAgentID();
: account
.currentAgentID()
._unsafeUnwrap({ withStackTrace: true });
this.set(memberKey, role, "trusting");
if (this.get(memberKey) !== role) {
@@ -175,7 +177,7 @@ export class RawGroup<
const reader = this.core.node.resolveAccountAgent(
readerID,
"Expected to know currently permitted reader",
);
)._unsafeUnwrap({ withStackTrace: true });
this.set(
`${newReadKey.id}_for_${readerID}`,

View File

@@ -22,9 +22,11 @@ import {
AccountID,
RawProfile,
RawAccountMigration,
InvalidAccountAgentIDError,
} from "./coValues/account.js";
import { Profile, RawCoValue } from "./index.js";
import { expectGroup } from "./typeUtils/expectGroup.js";
import { err, ok, okAsync, Result, ResultAsync } from "neverthrow";
/** A `LocalNode` represents a local view of a set of loaded `CoValue`s, from the perspective of a particular account (or primitive cryptographic agent).
@@ -49,6 +51,8 @@ export class LocalNode {
/** @category 3. Low-level */
syncManager = new SyncManager(this);
crashed: Error | undefined = undefined;
/** @category 3. Low-level */
constructor(
account: ControlledAccountOrAgent,
@@ -240,6 +244,12 @@ export class LocalNode {
/** @internal */
createCoValue(header: CoValueHeader): CoValueCore {
if (this.crashed) {
throw new Error("Trying to create CoValue after node has crashed", {
cause: this.crashed,
});
}
const coValue = new CoValueCore(header, this);
this.coValues[coValue.id] = { state: "loaded", coValue: coValue };
@@ -257,6 +267,12 @@ export class LocalNode {
onProgress?: (progress: number) => void;
} = {},
): Promise<CoValueCore | "unavailable"> {
if (this.crashed) {
throw new Error("Trying to load CoValue after node has crashed", {
cause: this.crashed,
});
}
let entry = this.coValues[id];
if (!entry) {
const peersToWaitFor = new Set(
@@ -519,9 +535,9 @@ export class LocalNode {
resolveAccountAgent(
id: AccountID | AgentID,
expectation?: string,
): AgentID {
): Result<AgentID, ResolveAccountAgentError> {
if (isAgentID(id)) {
return id;
return ok(id);
}
const coValue = this.expectCoValueLoaded(id, expectation);
@@ -533,49 +549,58 @@ export class LocalNode {
!("type" in coValue.header.meta) ||
coValue.header.meta.type !== "account"
) {
throw new Error(
`${
expectation ? expectation + ": " : ""
}CoValue ${id} is not an account`,
);
return err({
type: "UnexpectedlyNotAccount",
expectation,
id,
} satisfies UnexpectedlyNotAccountError);
}
return (coValue.getCurrentContent() as RawAccount).currentAgentID();
}
async resolveAccountAgentAsync(
resolveAccountAgentAsync(
id: AccountID | AgentID,
expectation?: string,
): Promise<AgentID> {
): ResultAsync<AgentID, ResolveAccountAgentError> {
if (isAgentID(id)) {
return id;
return okAsync(id);
}
const coValue = await this.loadCoValueCore(id);
return ResultAsync.fromPromise(
this.loadCoValueCore(id),
(e) =>
({
type: "ErrorLoadingCoValueCore",
expectation,
id,
error: e,
}) satisfies LoadCoValueCoreError,
).andThen((coValue) => {
if (coValue === "unavailable") {
return err({
type: "AccountUnavailableFromAllPeers" as const,
expectation,
id,
} satisfies AccountUnavailableFromAllPeersError);
}
if (coValue === "unavailable") {
throw new Error(
`${
expectation ? expectation + ": " : ""
}Account ${id} is unavailable from all peers`,
);
}
if (
coValue.header.type !== "comap" ||
coValue.header.ruleset.type !== "group" ||
!coValue.header.meta ||
!("type" in coValue.header.meta) ||
coValue.header.meta.type !== "account"
) {
return err({
type: "UnexpectedlyNotAccount" as const,
expectation,
id,
} satisfies UnexpectedlyNotAccountError);
}
if (
coValue.header.type !== "comap" ||
coValue.header.ruleset.type !== "group" ||
!coValue.header.meta ||
!("type" in coValue.header.meta) ||
coValue.header.meta.type !== "account"
) {
throw new Error(
`${
expectation ? expectation + ": " : ""
}CoValue ${id} is not an account`,
);
}
return (coValue.getCurrentContent() as RawAccount).currentAgentID();
return (coValue.getCurrentContent() as RawAccount).currentAgentID();
});
}
/**
@@ -600,7 +625,9 @@ export class LocalNode {
this.crypto.seal({
message: readKey.secret,
from: this.account.currentSealerSecret(),
to: this.account.currentSealerID(),
to: this.account
.currentSealerID()
._unsafeUnwrap({ withStackTrace: true }),
nOnceMaterial: {
in: groupCoValue.id,
tx: groupCoValue.nextTransactionID(),
@@ -700,6 +727,31 @@ type CoValueState =
onProgress?: (progress: number) => void;
};
export type LoadCoValueCoreError = {
type: "ErrorLoadingCoValueCore";
error: unknown;
expectation?: string;
id: AccountID;
};
export type AccountUnavailableFromAllPeersError = {
type: "AccountUnavailableFromAllPeers";
expectation?: string;
id: AccountID;
};
export type UnexpectedlyNotAccountError = {
type: "UnexpectedlyNotAccount";
expectation?: string;
id: AccountID;
};
export type ResolveAccountAgentError =
| InvalidAccountAgentIDError
| LoadCoValueCoreError
| AccountUnavailableFromAllPeersError
| UnexpectedlyNotAccountError;
/** @internal */
export function newLoadingState(
currentPeerIds: Set<PeerID>,

View File

@@ -249,8 +249,22 @@ export function determineValidTransactions(
const effectiveTransactor =
transactor === groupContent.id &&
groupAtTime instanceof RawAccount
? groupAtTime.currentAgentID()
? groupAtTime.currentAgentID().match(
(agentID) => agentID,
(e) => {
console.error(
"Error while determining current agent ID in valid transactions",
e,
);
return undefined;
},
)
: transactor;
if (!effectiveTransactor) {
return false;
}
const transactorRoleAtTxTime =
groupAtTime.get(effectiveTransactor) ||
groupAtTime.get(EVERYONE);

View File

@@ -562,6 +562,7 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
peer1role: "client",
peer2role: "server",
trace,
crashOnClose: true,
},
);

View File

@@ -9,10 +9,12 @@ export function connectedPeers(
trace = false,
peer1role = "peer",
peer2role = "peer",
crashOnClose = false,
}: {
trace?: boolean;
peer1role?: Peer["role"];
peer2role?: Peer["role"];
crashOnClose?: boolean;
} = {},
): [Peer, Peer] {
const [from1to2Rx, from1to2Tx] = newQueuePair(
@@ -27,6 +29,7 @@ export function connectedPeers(
incoming: from2to1Rx,
outgoing: from1to2Tx,
role: peer2role,
crashOnClose: crashOnClose,
};
const peer1AsPeer: Peer = {
@@ -34,6 +37,7 @@ export function connectedPeers(
incoming: from1to2Rx,
outgoing: from2to1Tx,
role: peer1role,
crashOnClose: crashOnClose,
};
return [peer1AsPeer, peer2AsPeer];

View File

@@ -72,8 +72,8 @@ export interface Peer {
incoming: IncomingSyncStream;
outgoing: OutgoingSyncQueue;
role: "peer" | "server" | "client";
delayOnError?: number;
priority?: number;
crashOnClose: boolean;
}
export interface PeerState {
@@ -83,8 +83,8 @@ export interface PeerState {
incoming: IncomingSyncStream;
outgoing: OutgoingSyncQueue;
role: "peer" | "server" | "client";
delayOnError?: number;
priority?: number;
crashOnClose: boolean;
}
export function combinedKnownStates(
@@ -343,8 +343,8 @@ export class SyncManager {
outgoing: peer.outgoing,
toldKnownState: new Set(),
role: peer.role,
delayOnError: peer.delayOnError,
priority: peer.priority,
crashOnClose: peer.crashOnClose,
};
this.peers[peer.id] = peerState;
@@ -392,9 +392,31 @@ export class SyncManager {
}
};
processMessages().catch((e) => {
console.error("Error processing messages from peer", peer.id, e);
});
processMessages()
.then(() => {
if (peer.crashOnClose) {
console.error("Unexepcted close from peer", peer.id);
this.local.crashed = new Error(
"Unexpected close from peer",
);
throw new Error("Unexpected close from peer");
}
})
.catch((e) => {
console.error(
"Error processing messages from peer",
peer.id,
e,
);
if (peer.crashOnClose) {
this.local.crashed = e;
throw new Error(e);
}
})
.finally(() => {
peer.outgoing.close();
delete this.peers[peer.id];
});
}
trySendToPeer(peer: PeerState, msg: SyncMessage) {
@@ -443,12 +465,12 @@ export class SyncManager {
}
if (entry.state === "loading") {
console.log(
"Waiting for loaded",
msg.id,
"after message from",
peer.id,
);
// console.debug(
// "Waiting for loaded",
// msg.id,
// "after message from",
// peer.id,
// );
const loaded = await entry.done;
// console.log("Loaded", msg.id, loaded);
if (loaded === "unavailable") {
@@ -539,9 +561,10 @@ export class SyncManager {
let entry = this.local.coValues[msg.id];
if (!entry) {
throw new Error(
console.error(
`Expected coValue entry for ${msg.id} to be created on new content, missing subscribe?`,
);
return;
}
let resolveAfterDone: ((coValue: CoValueCore) => void) | undefined;
@@ -549,14 +572,16 @@ export class SyncManager {
const peerOptimisticKnownState = peer.optimisticKnownStates[msg.id];
if (!peerOptimisticKnownState) {
throw new Error(
console.error(
"Expected optimisticKnownState to be set for coValue we receive new content for",
);
return;
}
if (entry.state === "loading") {
if (!msg.header) {
throw new Error("Expected header to be sent in first message");
console.error("Expected header to be sent in first message");
return;
}
const firstPeerStateEntry = entry.firstPeerState[peer.id];
@@ -608,7 +633,8 @@ export class SyncManager {
}
const before = performance.now();
const success = await coValue.tryAddTransactionsAsync(
// eslint-disable-next-line neverthrow/must-use-result
const result = await coValue.tryAddTransactionsAsync(
sessionID,
newTransactions,
undefined,
@@ -644,15 +670,14 @@ export class SyncManager {
entry.onProgress?.(ourTotalnTxs / theirTotalnTxs);
if (!success) {
if (result.isErr()) {
console.error(
"Failed to add transactions",
result.error,
msg.id,
JSON.stringify(newTransactions, (k, v) =>
k === "changes" || k === "encryptedChanges"
? v.slice(0, 20) + "..."
: v,
),
newTransactions.length + " new transactions",
"we have" + ourTotalnTxs,
"they have" + theirTotalnTxs,
);
continue;
}
@@ -747,7 +772,11 @@ export class SyncManager {
gracefulShutdown() {
for (const peer of Object.values(this.peers)) {
console.debug("Gracefully closing", peer.id);
peer.outgoing.close();
peer.incoming = (async function* () {
yield "Disconnected" as const;
})();
}
}
}

View File

@@ -36,12 +36,14 @@ test("Can create coValue with new agent credentials and add transaction to it",
);
expect(
coValue.tryAddTransactions(
node.currentSessionID,
[transaction],
expectedNewHash,
Crypto.sign(account.currentSignerSecret(), expectedNewHash),
),
coValue
.tryAddTransactions(
node.currentSessionID,
[transaction],
expectedNewHash,
Crypto.sign(account.currentSignerSecret(), expectedNewHash),
)
._unsafeUnwrap(),
).toBe(true);
});
@@ -72,8 +74,9 @@ test("transactions with wrong signature are rejected", () => {
[transaction],
);
expect(
coValue.tryAddTransactions(
// eslint-disable-next-line neverthrow/must-use-result
coValue
.tryAddTransactions(
node.currentSessionID,
[transaction],
expectedNewHash,
@@ -81,8 +84,8 @@ test("transactions with wrong signature are rejected", () => {
Crypto.getAgentSignerSecret(wrongAgent),
expectedNewHash,
),
),
).toBe(false);
)
._unsafeUnwrapErr({ withStackTrace: true });
});
test("transactions with correctly signed, but wrong hash are rejected", () => {
@@ -121,14 +124,15 @@ test("transactions with correctly signed, but wrong hash are rejected", () => {
],
);
expect(
coValue.tryAddTransactions(
// eslint-disable-next-line neverthrow/must-use-result
coValue
.tryAddTransactions(
node.currentSessionID,
[transaction],
expectedNewHash,
Crypto.sign(account.currentSignerSecret(), expectedNewHash),
),
).toBe(false);
)
._unsafeUnwrapErr({ withStackTrace: true });
});
test("New transactions in a group correctly update owned values, including subscriptions", async () => {
@@ -174,12 +178,14 @@ test("New transactions in a group correctly update owned values, including subsc
expect(map.core.getValidSortedTransactions().length).toBe(1);
const manuallyAdddedTxSuccess = group.core.tryAddTransactions(
node.currentSessionID,
[resignationThatWeJustLearnedAbout],
expectedNewHash,
signature,
);
const manuallyAdddedTxSuccess = group.core
.tryAddTransactions(
node.currentSessionID,
[resignationThatWeJustLearnedAbout],
expectedNewHash,
signature,
)
._unsafeUnwrap({ withStackTrace: true });
expect(manuallyAdddedTxSuccess).toBe(true);

View File

@@ -354,7 +354,7 @@ test("Admins can set group read key and then use it to create and read private t
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -410,7 +410,7 @@ test("Admins can set group read key and then writers can use it to create and re
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -422,7 +422,7 @@ test("Admins can set group read key and then writers can use it to create and re
const revelation2 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: writer.currentSealerID(),
to: writer.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -489,7 +489,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -501,7 +501,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation2 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader.currentSealerID(),
to: reader.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -576,7 +576,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -588,7 +588,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation2 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader1.currentSealerID(),
to: reader1.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -627,7 +627,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation3 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader2.currentSealerID(),
to: reader2.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -692,7 +692,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -722,7 +722,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation2 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -775,7 +775,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -802,7 +802,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation2 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -814,7 +814,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation3 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: reader.currentSealerID(),
to: reader.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -910,7 +910,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -922,7 +922,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const revelation2 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader.currentSealerID(),
to: reader.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -934,7 +934,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const revelation3 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader2.currentSealerID(),
to: reader2.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -980,7 +980,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const newRevelation1 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -996,7 +996,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const newRevelation2 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: reader2.currentSealerID(),
to: reader2.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1121,7 +1121,7 @@ test("Admins can create an adminInvite, which can add an admin", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1231,7 +1231,7 @@ test("Admins can create a writerInvite, which can add a writer", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1334,7 +1334,7 @@ test("Admins can create a readerInvite, which can add a reader", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1427,7 +1427,7 @@ test("WriterInvites can not invite admins", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1481,7 +1481,7 @@ test("ReaderInvites can not invite admins", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1535,7 +1535,7 @@ test("ReaderInvites can not invite writers", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID(),
to: admin.currentSealerID()._unsafeUnwrap(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1610,7 +1610,7 @@ test("Can give read permission to 'everyone'", () => {
childObject
.testWithDifferentAccount(
newAccount,
newRandomSessionID(newAccount.currentAgentID()),
newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
)
.getCurrentContent(),
);
@@ -1639,7 +1639,7 @@ test("Can give read permissions to 'everyone' (high-level)", async () => {
childObject.core
.testWithDifferentAccount(
new ControlledAgent(Crypto.newRandomAgentSecret(), Crypto),
newRandomSessionID(newAccount.currentAgentID()),
newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
)
.getCurrentContent(),
);
@@ -1680,7 +1680,7 @@ test("Can give write permission to 'everyone'", async () => {
childObject
.testWithDifferentAccount(
newAccount,
newRandomSessionID(newAccount.currentAgentID()),
newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
)
.getCurrentContent(),
);
@@ -1715,7 +1715,7 @@ test("Can give write permissions to 'everyone' (high-level)", async () => {
childObject.core
.testWithDifferentAccount(
newAccount,
newRandomSessionID(newAccount.currentAgentID()),
newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
)
.getCurrentContent(),
);

View File

@@ -32,6 +32,7 @@ test("Node replies with initial tx and header to empty subscribe", async () => {
incoming: inRx,
outgoing: outTx,
role: "peer",
crashOnClose: true,
});
await inTx.push({
@@ -109,6 +110,7 @@ test("Node replies with only new tx to subscribe with some known state", async (
incoming: inRx,
outgoing: outTx,
role: "peer",
crashOnClose: true,
});
await inTx.push({
@@ -182,6 +184,7 @@ test("After subscribing, node sends own known state and new txs to peer", async
incoming: inRx,
outgoing: outTx,
role: "peer",
crashOnClose: true,
});
await inTx.push({
@@ -294,6 +297,7 @@ test("Client replies with known new content to tellKnownState from server", asyn
incoming: inRx,
outgoing: outTx,
role: "peer",
crashOnClose: true,
});
// expect((await outRxQ.next()).value).toMatchObject(groupStateEx(group));
@@ -366,6 +370,7 @@ test("No matter the optimistic known state, node respects invalid known state me
incoming: inRx,
outgoing: outTx,
role: "peer",
crashOnClose: true,
});
await inTx.push({
@@ -463,6 +468,7 @@ test("If we add a peer, but it never subscribes to a coValue, it won't get any m
incoming: inRx,
outgoing: outTx,
role: "peer",
crashOnClose: true,
});
map.set("hello", "world", "trusting");
@@ -498,6 +504,7 @@ test.todo(
incoming: inRx,
outgoing: outTx,
role: "server",
crashOnClose: true,
});
// expect((await outRxQ.next()).value).toMatchObject({
@@ -573,6 +580,7 @@ test.skip("If we add a server peer, newly created coValues are auto-subscribed t
incoming: inRx,
outgoing: outTx,
role: "server",
crashOnClose: true,
});
// expect((await outRxQ.next()).value).toMatchObject({
@@ -627,6 +635,7 @@ test("When we connect a new server peer, we try to sync all existing coValues to
incoming: inRx,
outgoing: outTx,
role: "server",
crashOnClose: true,
});
// const _adminSubscribeMessage = await outRxQ.next();
@@ -662,6 +671,7 @@ test("When receiving a subscribe with a known state that is ahead of our own, pe
incoming: inRx,
outgoing: outTx,
role: "peer",
crashOnClose: true,
});
await inTx.push({
@@ -700,6 +710,7 @@ test.skip("When replaying creation and transactions of a coValue as new content,
incoming: inRx1,
outgoing: outTx1,
role: "server",
crashOnClose: true,
});
const node2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
@@ -713,6 +724,7 @@ test.skip("When replaying creation and transactions of a coValue as new content,
incoming: inRx2,
outgoing: outTx2,
role: "client",
crashOnClose: true,
});
const adminSubscribeMessage = (await outRxQ1.next()).value;

View File

@@ -1,5 +1,87 @@
# jazz-browser-media-images
## 0.7.34-neverthrow.2
### Patch Changes
- jazz-browser@0.7.34-neverthrow.2
## 0.7.34-neverthrow.1
### Patch Changes
- jazz-browser@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- jazz-browser@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- jazz-browser@0.7.33
- jazz-tools@0.7.33
## 0.7.33-hotfixes.5
### Patch Changes
- jazz-browser@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- jazz-browser@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- jazz-browser@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
## 0.7.33-hotfixes.2
### Patch Changes
- jazz-browser@0.7.33-hotfixes.2
## 0.7.33-hotfixes.1
### Patch Changes
- jazz-browser@0.7.33-hotfixes.1
## 0.7.33-hotfixes.0
### Patch Changes
- jazz-browser@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
## 0.7.32
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.32
- jazz-browser@0.7.32
## 0.7.31
### Patch Changes
- jazz-browser@0.7.31
- jazz-tools@0.7.31
## 0.7.30
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser-media-images",
"version": "0.7.30",
"version": "0.7.34-neverthrow.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,119 @@
# jazz-browser
## 0.7.34-neverthrow.2
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.34-neverthrow.2
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
- cojson-storage-indexeddb@0.7.34-neverthrow.1
- cojson-transport-ws@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
- cojson-storage-indexeddb@0.7.34-neverthrow.0
- cojson-transport-ws@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- Updated dependencies [fdde8db]
- Updated dependencies [b297c93]
- Updated dependencies [07fe2b9]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson-transport-ws@0.7.33
- cojson@0.7.33
- cojson-storage-indexeddb@0.7.33
- jazz-tools@0.7.33
## 0.7.33-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
- cojson-storage-indexeddb@0.7.33-hotfixes.5
- cojson-transport-ws@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
- cojson-storage-indexeddb@0.7.33-hotfixes.4
- cojson-transport-ws@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Updated dependencies
- cojson-storage-indexeddb@0.7.33-hotfixes.3
- cojson-transport-ws@0.7.33-hotfixes.3
- cojson@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
## 0.7.33-hotfixes.2
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.2
## 0.7.33-hotfixes.1
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.1
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
- cojson-storage-indexeddb@0.7.33-hotfixes.0
- cojson-transport-ws@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
## 0.7.32
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.32
## 0.7.31
### Patch Changes
- Updated dependencies
- Updated dependencies
- cojson-transport-ws@0.7.31
- cojson@0.7.31
- cojson-storage-indexeddb@0.7.31
- jazz-tools@0.7.31
## 0.7.30
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser",
"version": "0.7.30",
"version": "0.7.34-neverthrow.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,111 @@
# jazz-autosub
## 0.7.34-neverthrow.2
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.34-neverthrow.2
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
- cojson-transport-ws@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
- cojson-transport-ws@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- Updated dependencies [fdde8db]
- Updated dependencies [b297c93]
- Updated dependencies [07fe2b9]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson-transport-ws@0.7.33
- cojson@0.7.33
- jazz-tools@0.7.33
## 0.7.33-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
- cojson-transport-ws@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
- cojson-transport-ws@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.3
- cojson@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
## 0.7.33-hotfixes.2
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.2
## 0.7.33-hotfixes.1
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.1
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
- cojson-transport-ws@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
## 0.7.32
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.32
## 0.7.31
### Patch Changes
- Updated dependencies
- Updated dependencies
- cojson-transport-ws@0.7.31
- cojson@0.7.31
- jazz-tools@0.7.31
## 0.7.30
### Patch Changes

View File

@@ -5,7 +5,7 @@
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.7.30",
"version": "0.7.34-neverthrow.2",
"dependencies": {
"cojson": "workspace:*",
"cojson-transport-ws": "workspace:*",

View File

@@ -1,5 +1,106 @@
# jazz-react
## 0.7.34-neverthrow.2
### Patch Changes
- jazz-browser@0.7.34-neverthrow.2
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
- jazz-browser@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
- jazz-browser@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- Updated dependencies [b297c93]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson@0.7.33
- jazz-browser@0.7.33
- jazz-tools@0.7.33
## 0.7.33-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
- jazz-browser@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
- jazz-browser@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.3
- jazz-browser@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
## 0.7.33-hotfixes.2
### Patch Changes
- jazz-browser@0.7.33-hotfixes.2
## 0.7.33-hotfixes.1
### Patch Changes
- jazz-browser@0.7.33-hotfixes.1
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
- jazz-browser@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
## 0.7.32
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.32
- jazz-browser@0.7.32
## 0.7.31
### Patch Changes
- Updated dependencies
- cojson@0.7.31
- jazz-browser@0.7.31
- jazz-tools@0.7.31
## 0.7.30
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react",
"version": "0.7.30",
"version": "0.7.34-neverthrow.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,111 @@
# jazz-autosub
## 0.7.34-neverthrow.2
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.34-neverthrow.2
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
- cojson-transport-ws@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
- cojson-transport-ws@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- Updated dependencies [fdde8db]
- Updated dependencies [b297c93]
- Updated dependencies [07fe2b9]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson-transport-ws@0.7.33
- cojson@0.7.33
- jazz-tools@0.7.33
## 0.7.33-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
- cojson-transport-ws@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
- cojson-transport-ws@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.3
- cojson@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
## 0.7.33-hotfixes.2
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.2
## 0.7.33-hotfixes.1
### Patch Changes
- Updated dependencies
- cojson-transport-ws@0.7.33-hotfixes.1
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
- cojson-transport-ws@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
## 0.7.32
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.32
## 0.7.31
### Patch Changes
- Updated dependencies
- Updated dependencies
- cojson-transport-ws@0.7.31
- cojson@0.7.31
- jazz-tools@0.7.31
## 0.7.30
### Patch Changes

View File

@@ -3,7 +3,7 @@
"bin": "./dist/index.js",
"type": "module",
"license": "MIT",
"version": "0.7.30",
"version": "0.7.34-neverthrow.2",
"scripts": {
"lint": "eslint . --ext ts,tsx",
"format": "prettier --write './src/**/*.{ts,tsx}'",

View File

@@ -1,5 +1,70 @@
# jazz-autosub
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- Updated dependencies [b297c93]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson@0.7.33
## 0.7.33-hotfixes.5
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.3
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
## 0.7.32
### Patch Changes
- Adapt type of applyDiff to make CoMaps fully subclassable again
## 0.7.31
### Patch Changes
- Updated dependencies
- cojson@0.7.31
## 0.7.29
### Patch Changes

View File

@@ -5,7 +5,7 @@
"types": "./src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.7.29",
"version": "0.7.34-neverthrow.1",
"dependencies": {
"cojson": "workspace:*",
"fast-check": "^3.17.2"

View File

@@ -457,7 +457,7 @@ export class CoMap extends CoValueBase implements CoValue {
return subscribeToExistingCoValue(this, depth, listener);
}
applyDiff(newValues: Partial<CoMapInit<this>>) {
applyDiff<N extends Partial<CoMapInit<this>>>(newValues: N) {
for (const key in newValues) {
if (Object.prototype.hasOwnProperty.call(newValues, key)) {
const tKey = key as keyof typeof newValues & keyof this;
@@ -466,7 +466,7 @@ export class CoMap extends CoValueBase implements CoValue {
if (tKey in this._schema) {
const newValue = newValues[tKey];
const currentValue = this[tKey];
const currentValue = (this as unknown as N)[tKey];
if (descriptor === "json" || "encoded" in descriptor) {
if (currentValue !== newValue) {

78
pnpm-lock.yaml generated
View File

@@ -444,6 +444,9 @@ importers:
hash-wasm:
specifier: ^4.9.0
version: 4.11.0
neverthrow:
specifier: ^7.0.1
version: 7.0.1
queueable:
specifier: ^5.3.2
version: 5.3.2
@@ -463,6 +466,9 @@ importers:
eslint-config-prettier:
specifier: ^9.1.0
version: 9.1.0(eslint@8.56.0)
eslint-plugin-neverthrow:
specifier: ^1.1.4
version: 1.1.4(@typescript-eslint/parser@6.15.0(eslint@8.56.0)(typescript@5.0.2))(eslint@8.56.0)(typescript@5.0.2)
eslint-plugin-require-extensions:
specifier: ^0.1.3
version: 0.1.3(eslint@8.56.0)
@@ -1683,6 +1689,12 @@ packages:
'@types/chai@4.3.11':
resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==}
'@types/eslint-utils@3.0.5':
resolution: {integrity: sha512-dGOLJqHXpjomkPgZiC7vnVSJtFIOM1Y6L01EyUhzPuD0y0wfIGiqxiGs3buUBfzxLIQHrCvZsIMDaCZ8R5IIoA==}
'@types/eslint@9.6.0':
resolution: {integrity: sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==}
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
@@ -2504,6 +2516,13 @@ packages:
peerDependencies:
eslint: '>=7.0.0'
eslint-plugin-neverthrow@1.1.4:
resolution: {integrity: sha512-+8zsE5rDqsDfKYAOq0Fr2jbuxHXTmntIWWJqJA3ms1GAKcVCjl0ycetzOu/hTxot9ctr+WYQpCBgB3F2HATR7A==}
engines: {node: '>=14.17'}
peerDependencies:
'@typescript-eslint/parser': '>=4.20.0'
eslint: '>=5.16.0'
eslint-plugin-react-hooks@4.6.0:
resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
engines: {node: '>=10'}
@@ -2525,6 +2544,16 @@ packages:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
eslint-utils@3.0.0:
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
peerDependencies:
eslint: '>=5'
eslint-visitor-keys@2.1.0:
resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==}
engines: {node: '>=10'}
eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -3384,6 +3413,10 @@ packages:
resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
engines: {node: '>= 0.4.0'}
neverthrow@7.0.1:
resolution: {integrity: sha512-NY1sD1wZn6dwwzV9/5KZ4wRIpH4xC7ARy3fGmnEi2Pi8CHDTWlp+WSF+if8cudrwuCWGrk2y2BE/dnGh070iuA==}
engines: {node: '>=18'}
node-abi@3.62.0:
resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==}
engines: {node: '>=10'}
@@ -4257,9 +4290,18 @@ packages:
'@swc/wasm':
optional: true
tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
tsutils@3.21.0:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
tty-table@4.2.3:
resolution: {integrity: sha512-Fs15mu0vGzCrj8fmJNP7Ynxt5J7praPXqFN0leZeZBXJwkMxv9cb2D454k1ltrtUSJbZ4yH4e0CynsHLxmUfFA==}
engines: {node: '>=8.0.0'}
@@ -5644,6 +5686,16 @@ snapshots:
'@types/chai@4.3.11': {}
'@types/eslint-utils@3.0.5':
dependencies:
'@types/eslint': 9.6.0
'@types/estree': 1.0.5
'@types/eslint@9.6.0':
dependencies:
'@types/estree': 1.0.5
'@types/json-schema': 7.0.15
'@types/estree@1.0.5': {}
'@types/http-cache-semantics@4.0.4': {}
@@ -6724,6 +6776,16 @@ snapshots:
dependencies:
eslint: 8.56.0
eslint-plugin-neverthrow@1.1.4(@typescript-eslint/parser@6.15.0(eslint@8.56.0)(typescript@5.0.2))(eslint@8.56.0)(typescript@5.0.2):
dependencies:
'@types/eslint-utils': 3.0.5
'@typescript-eslint/parser': 6.15.0(eslint@8.56.0)(typescript@5.0.2)
eslint: 8.56.0
eslint-utils: 3.0.0(eslint@8.56.0)
tsutils: 3.21.0(typescript@5.0.2)
transitivePeerDependencies:
- typescript
eslint-plugin-react-hooks@4.6.0(eslint@8.56.0):
dependencies:
eslint: 8.56.0
@@ -6741,6 +6803,13 @@ snapshots:
esrecurse: 4.3.0
estraverse: 5.3.0
eslint-utils@3.0.0(eslint@8.56.0):
dependencies:
eslint: 8.56.0
eslint-visitor-keys: 2.1.0
eslint-visitor-keys@2.1.0: {}
eslint-visitor-keys@3.4.3: {}
eslint@8.56.0:
@@ -7641,6 +7710,8 @@ snapshots:
netmask@2.0.2: {}
neverthrow@7.0.1: {}
node-abi@3.62.0:
dependencies:
semver: 7.5.4
@@ -8606,8 +8677,15 @@ snapshots:
optionalDependencies:
'@swc/core': 1.3.101
tslib@1.14.1: {}
tslib@2.6.2: {}
tsutils@3.21.0(typescript@5.0.2):
dependencies:
tslib: 1.14.1
typescript: 5.0.2
tty-table@4.2.3:
dependencies:
chalk: 4.1.2