Jazz 0.20.0 - Full native crypto
With this release, we complete our migration to a pure native Rust toolchain. We have removed the JavaScript compatibility layer, meaning our native Rust core now runs everywhere: React Native, Edge runtimes, all server-side environments, and the web.
Motivation
Before 0.20.0, Jazz relied on a JavaScript crypto implementation to work around compatibility issues in some runtimes-most notably React Native. As a result, our native Rust core wasn’t running in React Native and, on some Edge runtimes, only worked when WASM was explicitly initialized (see WASM on Edge runtimes).
The JavaScript crypto implementation is much slower than native Rust crypto. Although workarounds like RNQuickCrypto for React Native improved performance, they still only wrapped certain native libraries, rather than running Jazz's full Rust crypto.
With native Rust crypto now running everywhere, Jazz comes with good performance in every platform. This also helps us speed up the migration of Jazz Core to Rust which will help us improve the Jazz overall performance.
What changed
- There is no more fallback to Javascript crypto. If the crypto fails to initialize, it will throw an error. See Edge runtimes for upgrading.
- As Jazz crypto now runs natively in all environments, we no longer support
PureJSCrypto. See Expo and React Native for upgrade instructions. - RNCrypto is now the default crypto provider on React Native. As a result, we're also discontinuing support for
RNQuickCrypto. - Optimized the JS-to-Rust communication by implementing native data type exchange, eliminating serialization overhead.
- You can now only use strings or records of strings as
uniqueparameters. This ensures that serialisation is deterministic. See a more strictuniqueparam. - The
removeMembermethod now throws an error if the caller is not authorized. - We have introduced a way to permanently delete CoValues. This brings a new
deletedloading state. - The React context API in
jazz-tools/react-corechanged:useJazzContextValuereplacesuseJazzContextfor value access, and nestingJazzProvidernow throws. See React context/provider changes. - The
loadmethod now returns aCoValueobject instead of aPromise<CoValue>. See Removedloadmethod.
Breaking changes
Edge runtimes
If you use WASM crypto on Edge runtimes, you need to ensure that WASM is available and initialized, there is no more fallback to Javascript crypto. See more details at WASM on Edge runtimes.
import "jazz-tools/load-edge-wasm"; // Other Jazz Imports export default { async fetch(request: Request, env: Env, ctx: ExecutionContext) { // Jazz application logic return new Response("Hello from Jazz on Cloudflare!"); }, };
If you don't do this, you will get an error like this:
Critical Error: Failed to load WASM module You need to add \`import "jazz-tools/load-edge-wasm";\` on top of your entry module to make Jazz work with this runtime A native crypto module is required for Jazz to work. See https://jazz.tools/docs/react/reference/performance#use-the-best-crypto-implementation-for-your-platform for possible alternatives.
Before 0.20.0, you would get a warning like this:
Warning: WASM crypto is not available. Falling back to JavaScript crypto.
Expo
If you had previously installed QuickCrypto, then you should follow the steps below. Otherwise, no action is needed to take advantage of RNCrypto.
- Remove QuickCrypto dependencies/config (only if you previously added them for
RNQuickCrypto):
- Remove
react-native-quick-crypto(and any associated config you added for it). - Remove any
SODIUM_ENABLED/sodiumEnabledsettings you added specifically for QuickCrypto.
- Remove
CryptoProviderentirely (RNCrypto is now the default)
You have to remove the CryptoProvider option, it is no longer supported:
import { JazzExpoProvider } from "jazz-tools/expo"; import { MyAppAccount } from "./schema"; const apiKey = "you@example.com"; export function MyJazzProvider({ children }: { children: React.ReactNode }) { return ( <JazzExpoProvider sync={{ peer: `wss://cloud.jazz.tools/?key=${apiKey}` }} AccountSchema={MyAppAccount} > {children} </JazzExpoProvider> ); }
While you can distribute your own JS code changes OTA, if you update your Jazz version, this will result in changes in the native dependencies, which cannot be distributed over the air and requires a new store submission.
React Native (non-Expo)
If you use React Native, you need to install cojson-core-rn and make sure the version matches jazz-tools. cojson-core-rn is our new high-performance crypto provider for React Native,
and it is required for React Native applications.
- Install
cojson-core-rn(required) and make sure the version matchesjazz-tools:
npm install cojson-core-rn
"dependencies": { "cojson-core-rn": "x.x.x", # same version as jazz-tools "jazz-tools": "x.x.x" # same version as cojson-core-rn }
While you can distribute your own JS code changes OTA, if you update your Jazz version, this will result in changes in the native dependencies, which cannot be distributed over the air and requires a new store submission.
See also: React Native setup.
- Remove QuickCrypto dependencies/config (only if you previously added them for
RNQuickCrypto):
- Remove
react-native-quick-crypto(and any associated config you added for it). - Remove any
SODIUM_ENABLED/sodiumEnabledsettings you added specifically for QuickCrypto.
- Remove
CryptoProviderentirely (RNCrypto is now the default)
After installing cojson-core-rn, you have to remove the CryptoProvider option, it is no longer supported:
import { JazzReactNativeProvider } from "jazz-tools/react-native"; import { MyAppAccount } from "./schema"; const apiKey = "you@example.com"; export function MyJazzProvider({ children }: { children: React.ReactNode }) { return ( <JazzReactNativeProvider sync={{ peer: `wss://cloud.jazz.tools/?key=${apiKey}` }} AccountSchema={MyAppAccount} > {children} </JazzReactNativeProvider> ); }
A more strict unique param
Jazz uses uniqueness to help identify CoValues.
Occasionally, you may wish to produce a deterministic ID for the CoValue. To do so, you can manually define the uniqueness using the unique parameter.
Before 0.20.0, you could pass any JsonValue as unique param. This was not stable across languages and could lead to unexpected behavior.
The unique property now enforces strict type validation, limiting inputs to specific primitives rather than generic JsonValue types.
Accepted types are string, boolean, null, undefined, or objects containing string values.
Providing any other type will throw an error, with the following distinction for numbers:
- Floating-point numbers (e.g.,
1.5) will throw an error. - Integers (e.g.,
1) are accepted and will not throw an error, though their usage is deprecated and not supported in the type system anymore.
We expect that this change will not impact any projects in our hosted Cloud based on our analysis. However, since we do not have visibility into self-hosted sync server deployments, we cannot rule out the possibility that your code may rely on the previously allowed unique value types.
If you are migrating from an earlier version and your project passes type-checks, you are almost certainly unaffected.
If you do encounter issues (for example, errors about unsupported unique value types),
the recommended upgrade path is to convert your uniqueness constraint to a string (as shown below), or, if necessary, to an object containing only string properties.
If you are affected by this change and cannot migrate to a supported unique type, please reach us on Discord for help or guidance.
New deleted loading state
With the introduction of CoValue deletion, there's a new deleted loading state. If you're handling loading states explicitly, you should add a case for deleted:
if (!project.$isLoaded) { switch (project.$jazz.loadingState) { case "loading": return "Loading project..."; case "unavailable": return "Project not found"; case "unauthorized": return "Project not accessible"; case "deleted": return "Project deleted"; } }
React context/provider changes
The React context API in jazz-tools/react-core changed to prevent nested providers and clarify context access:
JazzContextManagerContextwas removed.useJazzContextwas renamed touseJazzContextValuefor accessing the context value.useJazzContextnow returns the context manager instead of the value.- Nesting
JazzProvidercomponents now throws an error.
If you were using useJazzContext to get the context value, rename it to useJazzContextValue:
- import { useJazzContext } from "jazz-tools/react-core"; + import { useJazzContextValue } from "jazz-tools/react-core"; - const context = useJazzContext(); + const context = useJazzContextValue();
If you need to provide context to children without creating a new context (e.g., for components that don't propagate React context), use:
<JazzContext.Provider value={useJazzContext()}> {children} </JazzContext.Provider>