Jazz – Apps with Distributed State
jazz.tools
jazz.tools
- Cursors & carets
- Two way sync to your DB
- Video presence & calls
- both the Group and BinaryCoStreams
All of these are the key reasons I would be evaluating this framework to handle my data. All of these are not fully implemented yet.It is these key topics of live reloading/updating data that make or break an app. In my opinion, if you haven't concretely solved these problems, you haven't really built a viable state framework for 2024.
I really like the patterns they've implemented though, looks a lot like the same framework I just built on top of MobX, websockets, and React for a recent project. They're headed in the right direction, but I'm not sure they realize how much more work they have to go before this is fully fleshed out.
The coming-soon badges are about interop with traditional systems and higher level features we will add later.
The fundamentals are solved and you can build full multiplayer, local-first apps with it.
Does that make sense?
Free tier is 1GB of storage, and it goes up from there.
Which brings in even more questions. What is the performance of these multiplayer experiences? Can I have 1000+ users all connected to the same chat session? What about 10,000?
(these numbers might seem high, but they're what I'm expected to deliver in my day-job)
This lets us more easily prioritise features vs performance.
The commenter seems to know a lot about Jazz, so I took the opportunity to ask further questions.
Let me know if you'd like to know anything else.
I’m reminded of the quasi meme “You have designed an infinitely scalable service for 10 clients “
Especially within time (latency), monetary hosting cost, and accuracy constraints.
For example, an MMO town with 10,000 connected clients all viewing the same complex session state of all other users and entities in one town.
That’s a lot of room for error. Or am I missing something?
That scenario is complex to me and has remained complex to me despite my various times building it out for various products.
Its one thing to use this service on the basis of encryption claims - its another thing to have to clean up the mess from a forgotten API key being leaked somewhere... is there, therefore, a third party involved in an audit of Jazz?
Of course we will also do public audit(s) with security companies to make sure our cryptographic protocols are sound and implemented correctly.
But, it also has to be stated, there is no guarantee that you're using only the open source components you've declared, which is why an impartial audit by a third party would be necessary before this project can be used to build products in some industries.
Anyway, I see that you have other concerns, so no worries and thanks for the honest answer.
Have you ever read this article, basically saying that every front end state (including mobx) basically ends up being a worse version of a standard database?
https://sqlsync.dev/posts/stop-building-databases/
I ended up finding that article after running into lots of the challenges with mobx State tree. I ended up trying to use watermelondb, a sqlite wrapped for react native, but gave up entirely on offline due to bugs and project abandonment
The database has more features relative to filesystem, so we wouldn't miss the filesystem whereas a powerful indexing system is a feature in database missing in frontend data stores.
Some other examples below(Firefox plugins which are file browsers, FTP clients, C programs informally implementing subset of Common LISP features).
https://en.wikipedia.org/wiki/Inner-platform_effect
It is an ongoing exploration for us to find the best way to store/consume reactive state data within our client sites/apps. So far, MobX has given us a lot of leeway since we can create the data store we want for our data.
Going forward, I foresee us switching to something closer to WatermelonDB or maybe even just SQLite with a thin wrapper in React to create observability. I'm not 100% sure where it's going to go, but I agree with you that flexible state management for large platforms evolves fast and the difficulty of creating fast look-ups rapidly approaches "reinventing the DB" client-side.
I've had to build similar on top of SQLite for various other mobile/desktop apps, the problem hasn't really changed, the only difference is we're now using React + JS instead of C++, C#, or Java.
All roads so far have led to SQLite though.
Long live sqlite :)
The only thing SQLite is missed, which is important when integrating with React, is incremental view maintenance: how do we maintain as much immutable state on an update as possible to avoid wasteful re-renders?
The issue imho is that multiplayer synchronization (like Jazz) should rely on primitives(CRDT or similar) that you really can't hide under abstractions but should be part of the datamodel to allow for custom synchronization protocols for different parts of the datamodel or even exposing synchronization faults to the user.
An analogy would perhaps be how wrongly abstracted systems like CORBA and DCOM lost out (Even if you can run into them in crevices of enterprise systems) to things centered around HTTP calls or simpler message oriented systems like gRPC.
This seems awesome, but my natural game-stopping questions are;
1. When will backends be supported?
2. Why doesn’t the site mention “local-first”?
Oh and just for fun;
3. Why “Collaborative Values” instead of what I learned in school, “Shared Memory”?
2. The next version will. I like to think of Jazz as distributed state, of which local-first is a special case.
3. Shared memory to me sounds like concurrency is handled with locks, while Jazz uses CRDTs
If you can push the distributed state problem below the framework level, it becomes dead simple to build apps, which feels great.
But that's not exactly convenient for the users.
There are some edge cases where you might loose easy access to some data if two clients migrate concurrently, but we’re hoping to provide patterns to mitigate these
Edit: Right now it all depends on you to implement migrations “the right way” but we hope to provide guardrails soon
Agreed, that’s the only sensible thing to do. Not sure it’s 90% though.
> but we’re hoping to provide patterns to mitigate these
Hope is not confidence inspiring for the most difficult problem at the heart of the system. That doesn’t mean it has to be impossible, but it needs to be taken seriously and not an afterthought.
Another thing you have to think about is what happens when data of a new schema is sent to a client on an older schema. Does the “merging” work with unknown fields? Does it ignore and drop them? Or do you enforce clients are up to date in some way so that you don’t have new-data-old-software?
This approach may require a central authority (with no access to user data) responsible solely for providing the schema and migration patterns as code transformations.
Since running arbitrary code from the payload introduces potential security risks, the migration code could be cryptographically signed, ensuring that only valid, trusted transformation code is executed. A possible additional security layer would be to have the transformation code execute in a sandbox which can only output JSON data. (keeping a possible full before-migration version as backup in case something went wrong would always be a good idea)
Another option would be to use a transformation library for migrations, but in this case, the approach would only describe (as JSON) the functions and parameters needed to transition the schema from one version to another.
But Jazz does so in a completely different (local-first) way: it implements shared state on top of CRDTs and implements user identity and permissions based on public-key cryptography. This means you can create, store and share data from the client (even while offline) while still benefitting from cloud storage and real-time sync between devices and users by default.
- how can I setup delivery receipts for messages in your chat app? I want to know if they got my message and when it was sent.
- how can I create a chat group where the entire list of access permissions is not transparently available to everyone? For example, customer support: I don’t want to give out a list of every employee because a customer opens a chat that any employee and respond to.
- how are you handling p2p sync to multiple devices with the same account? Are all of my devices made public to anyone I collaborate with? Or does one device always need to be online?
- groups not only allow adding exact accounts, but also allow for “invites” which in your example only one employee could accept for a new support chat
- devices aren’t synced p2p by default but through the syncing server like everything else. Right now, all devices in one account use the same keypair for signing, so people you collaborate with can’t tell (except that they’re using different anonymous session ids)
The number one thing I'm looking forward to is React Native support. Having local data that syncs is essential for many mobile apps, but there are no easy solutions yet. (Besides iCloud, which is limited to iOS/macOS)
With Jazz, I can see a future where building syncing, cross-platform apps becomes effortless.
I recently hired someone who is a big svelte fan so we’ll have bindings for that soon. Rust is coming a bit later.
Are there plans for supporting dart/Flutter as well in the future?
React Native is released (experimental)
After that will be really good support for Next.JS (Jazz for both SSR and client)
A bit later will probably be a Rust port, which then also makes bindings to Swift/Kotlin/Go/... easy
One thing I always find weird about these sorts of projects is I get the feeling this is a framework built up from scratch. I've always had really bad luck doing that. Extracting and refining something from a running application always feels like you catch the cases that actually matter.
It's neat that it's quick to start, but I think that's mostly because the framework has only been evaluated by making tiny toy examples. Staying reaaaaally close to the framework code is sort of like painting with your nose against the canvas. At the scale of features you want to fit in:
- live sync
- authorization
- video chat
- an open connection to your DB, presumably meaning this is your main data fetching API
you're basically building 20% of someones else's app that currently doesn't exist. Once it does exist, it'll only be a simple toy example for a short while.It's sensibly licensed though (MIT), and honestly, skimming the source, seems clean to work with! I hope people using this contribute back to it, to get over that starter-project hurdle.
Completely agree that this is the only way to create frameworks.
Edit: also other people are building full apps with it too which I’ll showcase soon. https://learn-anything.xyz/ is one example, https://invoiceradar.com/ is another.
Definitely get that showcase up, I think it just helps to confirm this isn't one of those stealth-mode "solves everything" dev tools that disappears along with it's VC funding.
But I was able to hire a couple really good first people recently! We’re based all over Europe.
Let me know what else you’d like to know!
I'm based in Europe.
I was planning to add a second main server in the US that would also receive everything but will think about how to keep data separate for users/companies that need that.
In any case all the data is end-to-end encrypted, but I guess some of the metadata that is stored could still be considered sensitive for your scenario.
So suppose you have 4 people, Alice, Bob, Clark and David, where Alice and Clark are "admins". A network partitioning happens and Alice removes Bob, so Alice changes an encryption key to X and sends a message to everybody, concurrently without knowing about the Alice's removal Clark removes David and also changes and encryption key to Y and sends a message to everyone.
So in this case if we allow the generation of new keys to happen simultaneously (without consensus) one of the deletions will not be effective, because what we wanted is both Bob and David to be removed and not know the new encryption key for the db. But now Bob knows Y and David knows X. Thus neither X, nor Y can be the encryption key, because it is known by one of the deleted persons.
Sorry for the long explanation, but I am wondering what is your solution to such a problem.
Currently making apps using convex.dev, how would you describe differnce between Jazz and Convex ?
Convex have their own db, would Jazz work with any database ?
With decentralised I always like to be very precise:
- Jazz is decentralised in a "source of truth" sense. You mutate data locally and sync edits between participants until you reach eventually consistent history (and thus state, as per the underlying CRDTs)
- the protocol is peer-to-peer
- the way you use it typically is in a very centralised way. You use a central sync and persistence peer (either your own, or my distributed Jazz Mesh service) and every device syncs to that. That way devices don't have to be online at the same time to sync
This one is open source, thus hopefully a safer choice.
npx jazz-run sync
Assume this is built into the way you think about the model (and my mental model definitely isn't there yet), but having read the permissions part of the jazz docs (on/off?) and thinking about how client-first platforms like firebase do it with private rules on a centralised server .. I don't get it. Is it possible to do complex validation against e.g writes? Is it a natural state of CRDTs, somehow handled in the PKC, or just a side effect of the data models demanded of the setup?
Any info or pointers to further reading would be ace!
But because the schemas are runtime constructs as well, we might be able to do more complex stuff in the future. Basically any rule you can express as a function of (previous history, new transaction) -> is new transaction valid? can be a rule in theory, and each client will verify it in an eventually consistent way.
For the time being, the Group abstraction with it's reader, writer and admin roles, plus composition of CoValues in different groups is sufficient for most permission-like rules, which is what most apps need most of the time.
Let me know if that makes sense
I guess what I'm probably getting at is how does it hold from a threat perspective? What is to stop an actor distributing something extra large or unscrupulous between nodes. TS is notoriously hard to use for validation within types (e.g. string of max length, number between), but clearly covalues go beyond this.
Anyway, I'm writing this having not yet tried the framework. So I'll do that first and then do some further reading, and then jump onto the discord if I have more questions. Cheers.
You'd think they'd test their tech demos on more than a handful of people before launching. This doesn't give much confidence at all in their product.
The good thing is we now have an easily reproducible case, thanks HN :)
Also, if you're using xsalsa20 anyway, why go through the trouble of doing incremental n0nces? One of the main benefits of opting for an extended-n0nce construction is that it simplifies n0nce handling greatly. Why not randomly generate the 24 byte n0nce and forget about the tricky and error prone project of ensuring n0nce uniqueness?
How difficult is it to run my own backend?
Edit:
> Completely DIY Mesh.
> Build your own network of sync and storage nodes. Handle networking, security and backups yourself.
> Costs:
> N × instance cost for your sync nodes.
> Very high self-hosted egress costs.
> High self-hosted storage costs.
Compared to Mesh Pro at $79 for 30,000 sync-minutes (“Sync-minutes are counted on a per-connected-device, per-minute basis.”) per month… I bet the cost of self-hosted storage and egress is very low, actually, of course assuming you have the competence and time to DIY it.
Either locally or on your server.
And then point the app to that!
Edit: re pricing
Super preliminary, curious to hear everyone’s thoughts
For a small storage-heavy indie app I have, I'd pay $79 for base price, $45 for additional storage, and $1500 for sync minutes.
If you have time, I'd love to hear about your app and work out alternatives (not just for you, but for everyone)
anselm@gcmp.io anselm_io on Twitter
Or book a chat directly: https://cal.com/anselm-io/talk-about-jazz
(everyone else who has opinions on pricing is welcome to do the same)
Also, do you think there will be a way to use python with it?
I haven't had someone ask for Python yet, but I want to eventually support as many environments as possible. Which use-case do you have in mind?
1) How high is the pubkey overhead / isn’t this a lot of cryptography?
2) How do migrations work?
Uncaught (in promise) DOMException: A mutation operation was attempted
on a database that did not allow mutations.In this case we should fall back to using in-memory state only
1) Differences from fire-svelte for core functionality?
2) For the beyond core aspects, like Group-WebRTC (great innovation btw), how will things like TURN/PEER servers work to manage the WebRTC connections?
Specifically, once I load something (say a document), if I edit in on another tab, it will re-render on my original tab so long as the document it references (by key) is the same and firebase permissions allow me to read it as that firebase user.
It means all my permissions and schema goes in firebase/firebase rules (e.g. users can only access their own documents of type "Car" but can read all documents of type "Road"). Which is quite handy to do stuff quickly that syncs across users and works as a single source of truth.
It's an add on that works with Svelte (and Firebase). *(sorry, I got the wrong phrase)
fyi on latest Chrome the navigation items blog, releases, roadmap are aligned top/start instead of center for me
Also you can use it as blog storage as well
I have not been able to read the docs fully, but some questions:
* How do you handle state that is too big to send to the client fully? In a chat application, does the client need to have the whole channel history, or is syncing a subset of that supported? * Does permissioning support partial CoValues? For example, "You can edit the contents but not the title of the 'blog post #11' object" * Do you have resources about the suggested data modelling? Things like how granular should a CoValue be and what the trade-offs are. * How do you handle deletion? Do you tombstone? Is there a way to fully scrub a value from history (to support, for example, GDPR's right to erasure)?
- CoValues can reference CoValues that belong to a different group and thus have different permissions. In your example the title would need to live in its own CoValue and group compared to the content, which is a tiny bit more setup, but totally viable
- no resources for data modelling yet, but the guide + example apps should give you a very good idea. If you have any questions, please ask on Discord! https://discord.gg/sesjU2W5
- deletion is typically soft-deletion with tombstones. Total erasure of entire CoValues is coming soon but should only be needed in compliance situations (such as GDPR)
In the web world, this is starting to be known as "local-first"
Jazz is a framework for building apps around locally mutable collaborative values which are granularly synced (you don't have to worry about data transport or coordinating sync between collaborators, you just set permissions and edit data)
Jazz implements essentially a distributed database with permissions based on public-key cryptography, so you can meaningfully create, edit, share and store data on the client (even while offline), which gets synced to other users and devices (and stored in the cloud) whenever you're online
I would more than love to have local networks that can be emergent and growing and shrinking in this way.
Reminds me of my student days when I was traveling in the train, wondering why we couldn't have a p2p social network for people who are in this train _right now_
Then I opened it again and clicked the back button and it didn't work again.
Seems like the website breaks basic browser navigation.
Click-and-holding or right-clicking the back button will give you a list of last N URLs in your tab history. This page only generates one auto-redirect, so the HN URL will show up.
https://github.com/black7375/Firefox-UI-Fix/wiki/%5BArticle%...