Compare commits

...

40 Commits

Author SHA1 Message Date
github-actions[bot]
fe82631db6 Version Packages 2025-04-09 16:33:15 +07:00
Trisha Lim
ae4be2be7a fix(inspector): CoMaps showing as table instead of grid (#1842) 2025-04-09 15:40:21 +07:00
Benjamin S. Leveritt
abdf4a3577 Merge pull request #1796 from garden-co/1795-add-create-jazz-app-doc
1795 Add create-jazz-app doc
2025-04-08 19:13:53 +01:00
Giordano Ricci
6b0e772c9f Merge pull request #1784 from garden-co/gio/queue-counters
chore: replace queue size updown counter with 2 monotonic counters (push & pull)
2025-04-08 18:01:39 +01:00
Benjamin S. Leveritt
039b1151bf Add api-key notes 2025-04-08 16:35:05 +01:00
Guido D'Orsi
6c79cfb109 Merge pull request #1835 from garden-co/vitest-typecheck
chore: upgrade Vitest and enable typecheck tests
2025-04-08 17:33:11 +02:00
Guido D'Orsi
b9f42bb733 chore: enable typecheck selectively on jazz-tools 2025-04-08 17:32:50 +02:00
Benjamin S. Leveritt
542d839ed6 Adds Command-line option explanation 2025-04-08 16:30:17 +01:00
Benjamin S. Leveritt
3c1a4f124c Improves explanation for starter/example apps 2025-04-08 16:02:44 +01:00
Guido D'Orsi
f6cc06b8dc chore: upgrade Vitest and enable typecheck tests 2025-04-08 15:56:33 +02:00
Guido D'Orsi
6202436c9a Merge pull request #1828 from garden-co/feat--updating-design-system-readme-&-meta-data
1827 feat: updating design system readme & meta data
2025-04-08 14:54:37 +02:00
Guido D'Orsi
65929a8e7e Merge pull request #1804 from garden-co/fix/toc-hidden-headings
fix: show/hide heading on table of contents based on framework
2025-04-08 14:52:22 +02:00
Guido D'Orsi
20e5786fc0 Merge pull request #1821 from garden-co/fix/remove-idea
remove .idea dir
2025-04-08 14:50:41 +02:00
Sammii
91bc3c432d update text 2025-04-08 13:46:45 +01:00
Benjamin S. Leveritt
1ff11cebf6 Clarifies suggestions you can pick any framework/auth method 2025-04-08 13:00:21 +01:00
Benjamin S. Leveritt
25cd967207 Use the cli tool name for title 2025-04-08 12:52:45 +01:00
Benjamin S. Leveritt
bcdc468a5d Adds create-jazz-app doc page
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-04-08 12:52:44 +01:00
Sammii
72d5112bac updating design system readme & meta data 2025-04-08 12:08:46 +01:00
Giordano Ricci
c1193c3c63 add explainer for counters restarts 2025-04-08 11:43:48 +01:00
Giordano Ricci
f30130b92f reduce possible priority values 2025-04-08 11:43:48 +01:00
Giordano Ricci
1a77233ecb force metric creation on queue creation 2025-04-08 11:43:48 +01:00
Giordano Ricci
09a95b8542 move queue initialization into constructor 2025-04-08 11:43:48 +01:00
Giordano Ricci
f46329ac68 move meter 2025-04-08 11:43:48 +01:00
Giordano Ricci
c551839179 extract queue meter logic, add tests 2025-04-08 11:43:47 +01:00
Giordano Ricci
a0683f9d21 add role attribute to queue metrics 2025-04-08 11:43:47 +01:00
Giordano Ricci
a56958c69e WIP: queue counters 2025-04-08 11:43:47 +01:00
Trisha Lim
0b11a5f567 remove .idea dir 2025-04-08 12:49:30 +07:00
Trisha Lim
fac2d4a3b1 show/hide headings on table of contents based on framework 2025-04-08 11:37:34 +07:00
Guido D'Orsi
9f336103e8 Merge pull request #1820 from garden-co/changeset-release/main
Version Packages
2025-04-07 21:13:46 +02:00
github-actions[bot]
1174942a4e Version Packages 2025-04-07 19:12:40 +00:00
Guido D'Orsi
267920b7dc Merge pull request #1819 from garden-co/re-export-clerk
fix: add exports for clerk and crypto to make import shortcuts work everywhere
2025-04-07 21:10:16 +02:00
Guido D'Orsi
63a7aa0f54 fix: add exports for clerk and crypto to make import shortcuts work everywhere 2025-04-07 20:51:43 +02:00
Benjamin S. Leveritt
2b7534d30c Merge pull request #1808 from garden-co/docs/add-multicursor-example
Docs for multicursor example
2025-04-07 16:03:49 +01:00
Trisha Lim
be23a81b1b fix: create-jazz-app command showing $EXAMPLE instead of app slug 2025-04-07 19:55:03 +07:00
Guido D'Orsi
68416784fd docs(expo-clerk): fix outdated storage property 2025-04-07 14:39:49 +02:00
Guido D'Orsi
84d3c09cb1 docs: remove the nativewind section 2025-04-07 14:38:41 +02:00
Guido D'Orsi
53e8c39e8d docs: fix the clerk expo import 2025-04-07 14:36:46 +02:00
Trisha Lim
87b41fefad add multicursors example to cofeeds docs 2025-04-07 18:56:35 +07:00
Trisha Lim
265a4e8cc5 update readme for multi-cursors example 2025-04-07 18:53:03 +07:00
Trisha Lim
623467503f add multicursors example to examples page 2025-04-07 18:33:50 +07:00
138 changed files with 1521 additions and 451 deletions

4
.gitignore vendored
View File

@@ -23,11 +23,9 @@ test-results
.husky
.vscode/*
.idea/*
.svelte-kit
.cursorrules
.windsurfrules
.idea

8
.idea/.gitignore generated vendored
View File

@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

8
.idea/jazz.iml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/jazz.iml" filepath="$PROJECT_DIR$/.idea/jazz.iml" />
</modules>
</component>
</project>

19
.idea/php.xml generated
View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

6
.idea/prettier.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PrettierConfiguration">
<option name="myConfigurationMode" value="AUTOMATIC" />
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -1,5 +1,20 @@
# chat-rn-expo-clerk
## 1.0.95
### Patch Changes
- jazz-expo@0.13.2
- jazz-tools@0.13.2
- jazz-react-native-media-images@0.13.2
## 1.0.94
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-expo@0.13.1
## 1.0.93
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-expo-clerk",
"main": "index.js",
"version": "1.0.93",
"version": "1.0.95",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",

View File

@@ -1,6 +1,5 @@
import { useClerk } from "@clerk/clerk-expo";
// FIXME: why isn't the export working? IDE is fine, Metro doesn't like the non 'dist' import
import { JazzProviderWithClerk } from "jazz-expo/dist/auth/clerk";
import { JazzProviderWithClerk } from "jazz-expo/auth/clerk";
import React, { PropsWithChildren } from "react";
import { apiKey } from "./apiKey";

View File

@@ -1,5 +1,19 @@
# chat-rn-expo
## 1.0.82
### Patch Changes
- jazz-expo@0.13.2
- jazz-tools@0.13.2
## 1.0.81
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-expo@0.13.1
## 1.0.80
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn-expo",
"version": "1.0.80",
"version": "1.0.82",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",

View File

@@ -1,5 +1,22 @@
# chat-rn
## 1.0.91
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
- cojson-transport-ws@0.13.2
- jazz-react-native@0.13.2
- jazz-tools@0.13.2
## 1.0.90
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-react-native@0.13.1
## 1.0.89
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.89",
"version": "1.0.91",
"main": "index.js",
"scripts": {
"android": "react-native run-android",

View File

@@ -1,5 +1,13 @@
# chat-vue
## 0.0.75
### Patch Changes
- jazz-browser@0.13.2
- jazz-tools@0.13.2
- jazz-vue@0.13.2
## 0.0.74
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.74",
"version": "0.0.75",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,14 @@
# jazz-example-chat
## 0.0.172
### Patch Changes
- Updated dependencies [ae4be2b]
- jazz-inspector@0.13.2
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.171
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.171",
"version": "0.0.172",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,13 @@
# minimal-auth-clerk
## 0.0.71
### Patch Changes
- jazz-react@0.13.2
- jazz-react-auth-clerk@0.13.2
- jazz-tools@0.13.2
## 0.0.70
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.70",
"version": "0.0.71",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# file-share-svelte
## 0.0.55
### Patch Changes
- jazz-svelte@0.13.2
- jazz-tools@0.13.2
## 0.0.54
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.54",
"version": "0.0.55",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,14 @@
# jazz-tailwind-demo-auth-starter
## 0.0.11
### Patch Changes
- Updated dependencies [ae4be2b]
- jazz-inspector@0.13.2
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.10
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "filestream",
"private": true,
"version": "0.0.10",
"version": "0.0.11",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# form
## 0.1.13
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.1.12
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.1.12",
"version": "0.1.13",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# image-upload
## 0.0.69
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.68
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.68",
"version": "0.0.69",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,15 @@
# jazz-example-inspector
## 0.0.122
### Patch Changes
- Updated dependencies [ae4be2b]
- Updated dependencies [c551839]
- jazz-inspector@0.13.2
- cojson@0.13.2
- cojson-transport-ws@0.13.2
## 0.0.121
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector-app",
"private": true,
"version": "0.0.121",
"version": "0.0.122",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# multi-cursors
## 0.0.65
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.64
### Patch Changes

View File

@@ -1,3 +1,64 @@
# Multi-cursor example
# Jazz Multi-Cursors Example
An example app of using Jazz for showing multiple-cursors on a simple canvas.
Track user presence on a canvas with multiple cursors and out of bounds indicators.
## Getting started
You can either
1. Clone the jazz repository, and run the app within the monorepo.
2. Or create a new Jazz project using this example as a template.
### Using the example as a template
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest multi-cursors-app --example multi-cursors
```
Go to the new project directory.
```bash
cd multi-cursors-app
```
Run the dev server.
```bash
npm run dev
```
### Using the monorepo
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
Clone the jazz repository.
```bash
git clone https://github.com/garden-co/jazz.git
```
Install and build dependencies.
```bash
pnpm i && npx turbo build
```
Go to the example directory.
```bash
cd jazz/examples/multi-cursors/
```
Start the dev server.
```bash
pnpm dev
```
Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.
## Questions / problems / feedback
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 Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
You can also run a local sync server by running `npx jazz-run sync` and adding the query param `?sync=ws://localhost:4200` to the URL of the example app (for example: `http://localhost:5173/?peer=ws://localhost:4200`), or by setting the `sync` parameter of `JazzProvider` component in [./src/main.tsx](./src/main.tsx).

View File

@@ -1,7 +1,7 @@
{
"name": "multi-cursors",
"private": true,
"version": "0.0.64",
"version": "0.0.65",
"type": "module",
"scripts": {
"dev": "vite",
@@ -30,6 +30,6 @@
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2",
"vite": "^6.0.11",
"vitest": "3.0.5"
"vitest": "3.1.1"
}
}

View File

@@ -1,5 +1,13 @@
# multiauth
## 0.0.12
### Patch Changes
- jazz-react@0.13.2
- jazz-react-auth-clerk@0.13.2
- jazz-tools@0.13.2
## 0.0.11
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "multiauth",
"private": true,
"version": "0.0.11",
"version": "0.0.12",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,14 @@
# jazz-example-musicplayer
## 0.0.93
### Patch Changes
- Updated dependencies [ae4be2b]
- jazz-inspector@0.13.2
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.92
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.92",
"version": "0.0.93",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# organization
## 0.0.65
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.64
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "organization",
"private": true,
"version": "0.0.64",
"version": "0.0.65",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,11 @@
# passkey-svelte
## 0.0.59
### Patch Changes
- jazz-svelte@0.13.2
## 0.0.58
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "passkey-svelte",
"version": "0.0.58",
"version": "0.0.59",
"type": "module",
"private": true,
"scripts": {

View File

@@ -1,5 +1,12 @@
# minimal-auth-passkey
## 0.0.70
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.69
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "passkey",
"private": true,
"version": "0.0.69",
"version": "0.0.70",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# passphrase
## 0.0.67
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.66
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "passphrase",
"private": true,
"version": "0.0.66",
"version": "0.0.67",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# jazz-password-manager
## 0.0.91
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.90
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.90",
"version": "0.0.91",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# jazz-example-pets
## 0.0.189
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.188
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.188",
"version": "0.0.189",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# reactions
## 0.0.69
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.68
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "reactions",
"private": true,
"version": "0.0.68",
"version": "0.0.69",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,13 @@
# todo-vue
## 0.0.73
### Patch Changes
- jazz-browser@0.13.2
- jazz-tools@0.13.2
- jazz-vue@0.13.2
## 0.0.72
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "todo-vue",
"version": "0.0.72",
"version": "0.0.73",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,12 @@
# jazz-example-todo
## 0.0.188
### Patch Changes
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.187
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.187",
"version": "0.0.188",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,14 @@
# version-history
## 0.0.66
### Patch Changes
- Updated dependencies [ae4be2b]
- jazz-inspector@0.13.2
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.65
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "version-history",
"private": true,
"version": "0.0.65",
"version": "0.0.66",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,36 +1,20 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
# Jazz Design System
## Getting Started
First, run the development server:
First, install packages
```bash
pnpm i
```
Then run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

View File

@@ -1,5 +1,4 @@
import {
AlertCircleIcon,
AlertTriangleIcon,
ArrowDownIcon,
ArrowRightIcon,
@@ -27,6 +26,7 @@ import {
MessageCircleQuestionIcon,
MonitorSmartphoneIcon,
MoonIcon,
MousePointer2Icon,
MousePointerSquareDashedIcon,
ScanFace,
ScrollIcon,
@@ -50,6 +50,7 @@ const icons = {
close: XIcon,
code: CodeIcon,
copy: ClipboardIcon,
cursor: MousePointer2Icon,
darkTheme: MoonIcon,
delete: TrashIcon,
devices: MonitorSmartphoneIcon,

View File

@@ -34,8 +34,8 @@ const commitMono = localFont({
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "Jazz Design System by Garden Computing, Inc",
description: "Jazz Design System by Garden Computing, Inc",
};
export default function RootLayout({

View File

@@ -13,7 +13,7 @@ Without any additional steps the user can use Jazz normally, but they would be l
To make Accounts work across devices, you can store/retrieve the account keys from an authentication method by using the corresponding hooks and providers.
<ContentByFramework framework={["react", "vue", "svelte"]}>
## Authentication with passkeys
## Authentication with passkeys [!framework=react,vue,svelte]
Passkey authentication is fully local-first and the most secure of the auth methods that Jazz provides (because keys are managed by the device/operating system itself).
@@ -209,13 +209,14 @@ However, once authenticated, your users won't need to interact with Clerk anymor
<ContentByFramework framework="react">
The clerk provider is not built into `jazz-react` and needs the `jazz-react-auth-clerk` package to be installed.
After installing the package you can use the `JazzProviderWithClerk` component to wrap your app:
</ContentByFramework>
<ContentByFramework framework="react-native-expo">
The clerk provider is not built into `jazz-expo` and needs the `jazz-expo/auth/clerk` import to be installed. Note the `__experimental_resourceCache` option. This helps render Clerk components when offline.
You can use the `JazzProviderWithClerk` component to wrap your app. Note the `__experimental_resourceCache` option. This helps render Clerk components when offline.
</ContentByFramework>
After installing the package you can use the `JazzProviderWithClerk` component to wrap your app:
<ContentByFramework framework="react">
<CodeGroup>
```tsx

View File

@@ -15,11 +15,11 @@ The Jazz docs are currently heavily work in progress, sorry about that!
## Quickstart
Run the following command to create a new Jazz project from one of our example apps:
You can use [`create-jazz-app`](/docs/tools/create-jazz-app) to create a new Jazz project from one of our starter templates or example apps:
<CodeGroup>
```sh
npx create-jazz-app@latest
npx create-jazz-app@latest --api-key you@example.com
```
</CodeGroup>

View File

@@ -53,10 +53,19 @@ export default async function Page({
try {
const mdxSource = await getMdxSource(framework, slugPath);
const { default: Content, tableOfContents } = mdxSource;
const {
default: Content,
tableOfContents,
headingsFrameworkVisibility,
test,
} = mdxSource;
// Exclude h1 from table of contents
const tocItems = (tableOfContents as Toc)?.[0]?.children;
// Remove items that should not be shown for the current framework
const tocItems = (tableOfContents as Toc).filter(({ id }) =>
id && id in headingsFrameworkVisibility
? headingsFrameworkVisibility[id]?.includes(framework)
: true,
);
return (
<>

View File

@@ -0,0 +1,94 @@
export const metadata = {
title: "create-jazz-app",
};
import { CodeGroup } from "@/components/forMdx";
# create-jazz-app
Jazz comes with a CLI tool that helps you quickly scaffold new Jazz applications. There are two main ways to get started:
1. **Starter templates** - Pre-configured setups to start you off with your preferred framework
2. **Example apps** - Extend one of our [example applications](https://jazz.tools/examples) to build your project
## Quick Start with Starter Templates
Create a new Jazz app from a starter template in seconds:
<CodeGroup>
```bash
npx create-jazz-app@latest --api-key you@example.com
```
</CodeGroup>
This launches an interactive CLI that guides you through selecting:
- Pre-configured frameworks and authentication methods (See [Available Starters](#available-starters))
- Package manager
- Project name
- Jazz Cloud API key (optional) - Provides seamless sync and storage for your app
## Command Line Options
If you know what you want, you can specify options directly from the command line:
<CodeGroup>
```bash
# Basic usage with project name
npx create-jazz-app@latest my-app --framework react --api-key you@example.com
# Specify a starter template
npx create-jazz-app@latest my-app --starter react-passkey-auth --api-key you@example.com
# Specify example app
npx create-jazz-app@latest my-app --example chat --api-key you@example.com
```
</CodeGroup>
### Available Options
- `directory` - Directory to create the project in (defaults to project name)
- `-f, --framework` - Framework to use (React, React Native, Svelte, Vue)
- `-s, --starter` - Starter template to use
- `-e, --example` - Example project to use
- `-p, --package-manager` - Package manager to use (npm, yarn, pnpm, bun, deno)
- `-k, --api-key` - Jazz Cloud API key (during our [free public alpha](/docs/react/sync-and-storage#free-public-alpha), you can use your email as the API key)
- `-h, --help` - Display help information
## Start From an Example App
Want to start from one of [our example apps](https://jazz.tools/examples)? Our example apps include specific examples of features and use cases. They demonstrate real-world patterns for building with Jazz. Use one as your starting point:
<CodeGroup>
```bash
npx create-jazz-app@latest --example chat
```
</CodeGroup>
## Available Starters
Starter templates are minimal setups that include the basic configuration needed to get started with Jazz. They're perfect when you want a clean slate to build on.
Choose from these ready-to-use starter templates:
- `react-passkey-auth` - React with Passkey authentication (easiest to start with)
- `react-clerk-auth` - React with Clerk authentication
- `vue-demo-auth` - Vue with Demo authentication
- `svelte-passkey-auth` - Svelte with Passkey authentication
- `rn-clerk-auth` - React Native with Clerk authentication
Run `npx create-jazz-app --help` to see the latest list of available starters.
## What Happens Behind the Scenes
When you run `create-jazz-app`, we'll:
1. Ask for your preferences (or use your command line arguments)
2. Clone the appropriate starter template
3. Update dependencies to their latest versions
4. Install all required packages
5. Set up your project and show next steps
## Requirements
- Node.js 14.0.0 or later
- Your preferred package manager (npm, yarn, pnpm, bun, or deno)

View File

@@ -79,10 +79,10 @@ If you're using Clerk auth in your Expo application, you'll need to:
```tsx twoslash
// @noErrors: 2300 2307
// Before
import { ClerkAuthProvider, useClerkAuth } from "jazz-react-native-clerk"; // [!code --]
import { JazzProviderWithClerk } from "jazz-react-native-clerk"; // [!code --]
// After
import { ClerkAuthProvider, useClerkAuth } from "jazz-expo/auth/clerk"; // [!code ++]
import { JazzProviderWithClerk } from "jazz-expo/auth/clerk"; // [!code ++]
```
</CodeGroup>
@@ -134,31 +134,6 @@ declare module "jazz-expo" { // [!code ++:5]
The `jazz-expo` implementation supports the Expo New Architecture.
## Styling with NativeWind
For Expo projects, remember to use NativeWind CSS for styling, which is the recommended approach for Jazz applications built with Expo:
<CodeGroup>
```tsx twoslash
// @noErrors: 2305 2686
import { View, Text } from "react-native";
import { styled } from "nativewind";
const StyledView = styled(View);
const StyledText = styled(Text);
export function MyComponent() {
return (
<StyledView className="p-4 bg-white dark:bg-slate-800">
<StyledText className="text-black dark:text-white text-lg font-bold">
Hello, Jazz with Expo!
</StyledText>
</StyledView>
);
}
```
</CodeGroup>
## For More Information
For detailed setup instructions, refer to the [React Native Expo Setup Guide](/docs/react-native-expo/project-setup)

View File

@@ -8,7 +8,9 @@ CoFeeds are append-only data structures that track entries from different user s
Each account can have multiple sessions (different browser tabs, devices, or app instances), making CoFeeds ideal for building features like activity logs, presence indicators, and notification systems.
The [Reactions example](https://github.com/garden-co/jazz/tree/main/examples/reactions) demonstrates a practical use of CoFeeds.
The following examples demonstrate a practical use of CoFeeds:
- [Multi-cursors](https://github.com/garden-co/jazz/tree/main/examples/multi-cursors) - track user presence on a canvas with multiple cursors and out of bounds indicators
- [Reactions](https://github.com/garden-co/jazz/tree/main/examples/reactions) - store per-user emoji reaction using a CoFeed
## Creating CoFeeds

View File

@@ -253,6 +253,38 @@ const ReactionsIllustration = () => (
</div>
);
const MultiCursorIllustration = () => (
<div className="flex bg-stone-100 h-full flex-col items-center justify-center dark:bg-transparent p-4">
<div className=" bg-white md:aspect-[3/2] flex flex-col rounded-md shadow-xl shadow-stone-400/20 dark:shadow-none">
<div className="w-full py-2 flex items-center gap-1.5 px-2 border-b dark:border-b-stone-200">
<span className="rounded-full size-2 bg-stone-200"></span>
<span className="rounded-full size-2 bg-stone-200"></span>
<span className="rounded-full size-2 bg-stone-200"></span>
</div>
<div className="h-full mx-auto flex flex-col justify-center p-12 sm:p-16">
<div className="inline-block relative px-1 ring-1 ring-blue-400">
<div className="absolute size-2 bg-white border border-blue-400 -left-1 -top-1"></div>
<div className="absolute size-2 bg-white border border-blue-400 -right-1 -top-1"></div>
<div className="absolute size-2 bg-white border border-blue-400 -left-1 -bottom-1"></div>
<div className="absolute size-2 bg-white border border-blue-400 -right-1 -bottom-1"></div>
<span className="text-lg font-semibold md:text-2xl md:font-bold text-stone-800 ">
Hello, world!
</span>
<div className="absolute -top-10 right-4 text-rose-600 flex items-end gap-1">
<Icon name="cursor"></Icon> <span className="text-xs">Mia</span>
</div>
<div className="absolute -bottom-10 left-4 text-green-600 flex items-end gap-1">
<Icon name="cursor"></Icon>{" "}
<span className="text-xs">Sebastian</span>
</div>
</div>
</div>
</div>
</div>
);
const PetIllustration = () => (
<div className="h-full p-4 bg-[url('/dog.jpg')] bg-cover bg-center p-4 flex items-end">
<div className="inline-flex justify-center gap-1 mx-auto">
@@ -395,6 +427,16 @@ const reactExamples: Example[] = [
demoUrl: "https://reactions-demo.jazz.tools",
illustration: <ReactionsIllustration />,
},
{
name: "Cursor presence",
slug: "multi-cursors",
description:
"Track user presence on a canvas with multiple cursors and out of bounds indicators.",
tech: [tech.react],
features: [features.coFeed],
demoUrl: "https://jazz-multi-cursors.vercel.app",
illustration: <MultiCursorIllustration />,
},
{
name: "Rate my pet",
slug: "pets",
@@ -484,7 +526,8 @@ const rnExamples: Example[] = [
{
name: "Chat",
slug: "chat-rn",
description: "A simple React Native app that creates a chat room with a shareable link.",
description:
"A simple React Native app that creates a chat room with a shareable link.",
tech: [tech.reactNative],
illustration: <ChatIllustration />,
},
@@ -492,7 +535,8 @@ const rnExamples: Example[] = [
{
name: "Chat",
slug: "chat-rn-expo",
description: "A simple Expo app that creates a chat room with a shareable link.",
description:
"A simple Expo app that creates a chat room with a shareable link.",
tech: [tech.reactNative, tech.expo],
illustration: <ChatIllustration />,
},
@@ -500,7 +544,8 @@ const rnExamples: Example[] = [
{
name: "Chat",
slug: "chat-rn-expo-clerk",
description: "Exactly like the React Native Expo chat app, with Clerk for auth.",
description:
"Exactly like the React Native Expo chat app, with Clerk for auth.",
tech: [tech.reactNative, tech.expo],
features: [features.clerk],
illustration: <ClerkIllustration />,

View File

@@ -51,7 +51,7 @@ export default function DocsLayout({
</div>
<div className={clsx("md:col-span-8 lg:col-span-9 flex gap-12")}>
{children}
{tocItems?.length && (
{!!tocItems?.length && (
<>
<TableOfContents
className="pl-3 py-6 shrink-0 text-sm sticky align-start top-[61px] w-[16rem] h-[calc(100vh-61px)] overflow-y-auto hidden lg:block"

View File

@@ -20,7 +20,7 @@ const TocList = ({
};
return (
<ul className="space-y-2" style={{ paddingLeft: "1rem" }}>
<ul className="space-y-2" style={{ paddingLeft: level ? "1rem" : "0" }}>
{items.map((item) => (
<li key={item.id} className="space-y-2">
{item.id && (

View File

@@ -56,8 +56,8 @@ export const docNavigationItems = [
"react-native": 100,
"react-native-expo": 100,
},
}
]
},
],
},
{
name: "Tools",
@@ -67,6 +67,11 @@ export const docNavigationItems = [
href: "/docs/ai-tools",
done: 100,
},
{
name: "create-jazz-app",
href: "/docs/tools/create-jazz-app",
done: 100,
},
{
name: "Inspector",
href: "/docs/inspector",
@@ -82,7 +87,7 @@ export const docNavigationItems = [
{
name: "0.13.0 - React Native Split",
href: "/docs/upgrade/0-13-0",
done: 100
done: 100,
},
{
// upgrade guides

View File

@@ -26,13 +26,11 @@ export function InterpolateInCode(replace: { [key: string]: string }) {
}: { highlightedCode: string }) => {
const newHighlightedCode = Object.entries(replace).reduce(
(acc, [key, value]) => {
return acc.replaceAll(
key.replaceAll("$", "&#36;").replaceAll("_", "&#95;"),
value,
);
return acc.replaceAll(key, value);
},
highlightedCode,
);
return <div dangerouslySetInnerHTML={{ __html: newHighlightedCode }} />;
},
};

View File

@@ -2,8 +2,10 @@ import createMDX from "@next/mdx";
import { transformerNotationDiff } from "@shikijs/transformers";
import { transformerTwoslash } from "@shikijs/twoslash";
import withToc from "@stefanprobst/rehype-extract-toc";
import withTocExport from "@stefanprobst/rehype-extract-toc/mdx";
import rehypeSlug from "rehype-slug";
import { valueToEstree } from "estree-util-value-to-estree";
import GithubSlugger from "github-slugger";
import { headingRank } from "hast-util-heading-rank";
import { toString } from "hast-util-to-string";
import { createHighlighter } from "shiki";
import { SKIP, visit } from "unist-util-visit";
import { jazzDark } from "./themes/jazzDark.mjs";
@@ -20,7 +22,18 @@ const withMDX = createMDX({
// Add markdown plugins here, as desired
options: {
remarkPlugins: [highlightPlugin, remarkHtmlToJsx],
rehypePlugins: [rehypeSlug, withToc, withTocExport],
rehypePlugins: [
// Add id to heading elements, and indicate which frameworks to show the heading for
// This is a modified version of rehype-slug
withSlugAndHeadingsFrameworkVisibility,
// Create table of contents array
withToc,
// Return the table of contents and framework visibility data when importing a .mdx file
// This is a modified version of withTocExport from @stefanprobst/rehype-extract-toc
withTocAndFrameworkHeadingsVisibilityExport,
],
},
});
@@ -85,10 +98,6 @@ function highlightPlugin() {
};
}
function escape(s) {
return s.replace(/[^0-9A-Za-z ]/g, (c) => "&#" + c.charCodeAt(0) + ";");
}
function remarkHtmlToJsx() {
async function transform(...args) {
// Async import since these packages are all in ESM
@@ -116,4 +125,83 @@ function remarkHtmlToJsx() {
return transform;
}
const slugs = new GithubSlugger();
export function withSlugAndHeadingsFrameworkVisibility() {
return function (tree, vfile) {
slugs.reset();
vfile.data.headingsFrameworkVisibility = {};
visit(tree, "element", function (node) {
if (headingRank(node) && !node.properties.id) {
const lastChild = node.children?.[node.children.length - 1];
if (!lastChild || lastChild.type !== "text") return;
const match = lastChild.value.match(
/\s*\[\!framework=([a-zA-Z0-9,_-]+)\]\s*$/,
);
if (match) {
const frameworks = match[1];
lastChild.value = lastChild.value.replace(
/\s*\[\!framework=[a-zA-Z0-9,_-]+\]\s*$/,
"",
);
node.properties.id = slugs.slug(lastChild.value);
vfile.data.headingsFrameworkVisibility[node.properties.id] =
frameworks.split(",");
} else {
node.properties.id = slugs.slug(toString(node));
}
}
});
};
}
export function withTocAndFrameworkHeadingsVisibilityExport() {
return function transformer(tree, vfile) {
if (vfile.data.toc == null) return;
tree.children.unshift({
type: "mdxjsEsm",
data: {
estree: {
type: "Program",
sourceType: "module",
body: [
{
type: "ExportNamedDeclaration",
source: null,
specifiers: [],
declaration: {
type: "VariableDeclaration",
kind: "const",
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "headingsFrameworkVisibility",
},
init: valueToEstree(vfile.data.headingsFrameworkVisibility),
},
{
type: "VariableDeclarator",
id: { type: "Identifier", name: "tableOfContents" },
init: valueToEstree(
// exclude h1
vfile.data.toc.length ? vfile.data.toc[0].children : [],
),
},
],
},
},
],
},
},
});
};
}
export default config;

View File

@@ -32,7 +32,11 @@
"@vercel/analytics": "^1.3.1",
"@vercel/speed-insights": "^1.0.12",
"clsx": "^2.1.1",
"estree-util-value-to-estree": "^3.3.2",
"gcmp-design-system": "workspace:*",
"github-slugger": "^2.0.0",
"hast-util-heading-rank": "^3.0.0",
"hast-util-to-string": "^3.0.1",
"jazz-browser": "link:../../packages/jazz-browser",
"jazz-browser-media-images": "link:../../packages/jazz-browser-media-images",
"jazz-nodejs": "link:../../packages/jazz-nodejs",
@@ -47,7 +51,6 @@
"qrcode": "^1.5.4",
"react": "^18",
"react-dom": "^18",
"rehype-slug": "^6.0.0",
"shiki": "^3.2.1",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",

View File

@@ -223,9 +223,21 @@ importers:
clsx:
specifier: ^2.1.1
version: 2.1.1
estree-util-value-to-estree:
specifier: ^3.3.2
version: 3.3.2
gcmp-design-system:
specifier: workspace:*
version: link:../design-system
github-slugger:
specifier: ^2.0.0
version: 2.0.0
hast-util-heading-rank:
specifier: ^3.0.0
version: 3.0.0
hast-util-to-string:
specifier: ^3.0.1
version: 3.0.1
jazz-browser:
specifier: link:../../packages/jazz-browser
version: link:../../packages/jazz-browser
@@ -268,9 +280,6 @@ importers:
react-dom:
specifier: ^18
version: 18.3.1(react@18.3.1)
rehype-slug:
specifier: ^6.0.0
version: 6.0.0
shiki:
specifier: ^3.2.1
version: 3.2.1
@@ -1982,6 +1991,9 @@ packages:
resolution: {integrity: sha512-Y+ughcF9jSUJvncXwqRageavjrNPAI+1M/L3BI3PyLp1nmgYTGUXU6t5z1Y7OWuThoDdhPME07bQU+d5LxdJqw==}
engines: {node: '>=12.0.0'}
estree-util-value-to-estree@3.3.2:
resolution: {integrity: sha512-hYH1aSvQI63Cvq3T3loaem6LW4u72F187zW4FHpTrReJSm6W66vYTFNO1vH/chmcOulp1HlAj1pxn8Ag0oXI5Q==}
estree-util-visit@1.2.1:
resolution: {integrity: sha512-xbgqcrkIVbIG+lI/gzbvd9SGTJL4zqJKBFttUl5pP27KhAjtMKbX/mQXJ7qgyXpMgVy/zvpm0xoQQaGL8OloOw==}
@@ -2860,9 +2872,6 @@ packages:
regex@6.0.1:
resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==}
rehype-slug@6.0.0:
resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==}
remark-mdx@2.3.0:
resolution: {integrity: sha512-g53hMkpM0I98MU266IzDFMrTD980gNF3BJnkyFcmN+dD873mQeD5rdMO3Y2X+x8umQfbSE0PcoEDl7ledSA+2g==}
@@ -5138,7 +5147,7 @@ snapshots:
'@types/acorn@4.0.6':
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
'@types/d3-voronoi@1.1.12': {}
@@ -5158,7 +5167,7 @@ snapshots:
'@types/estree-jsx@1.0.5':
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
'@types/estree@1.0.5': {}
@@ -5647,7 +5656,7 @@ snapshots:
estree-util-attach-comments@2.1.1:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
estree-util-build-jsx@2.2.2:
dependencies:
@@ -5669,6 +5678,10 @@ snapshots:
dependencies:
is-plain-obj: 3.0.0
estree-util-value-to-estree@3.3.2:
dependencies:
'@types/estree': 1.0.6
estree-util-visit@1.2.1:
dependencies:
'@types/estree-jsx': 1.0.5
@@ -5681,7 +5694,7 @@ snapshots:
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
events@3.3.0: {}
@@ -5780,7 +5793,7 @@ snapshots:
hast-util-to-estree@2.3.3:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
'@types/estree-jsx': 1.0.5
'@types/hast': 2.3.10
'@types/unist': 2.0.10
@@ -5887,7 +5900,7 @@ snapshots:
is-reference@3.0.2:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
isexe@2.0.0: {}
@@ -6228,7 +6241,7 @@ snapshots:
micromark-extension-mdx-expression@1.0.8:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
micromark-factory-mdx-expression: 1.0.9
micromark-factory-space: 1.1.0
micromark-util-character: 1.2.0
@@ -6251,7 +6264,7 @@ snapshots:
micromark-extension-mdx-jsx@1.0.5:
dependencies:
'@types/acorn': 4.0.6
'@types/estree': 1.0.5
'@types/estree': 1.0.6
estree-util-is-identifier-name: 2.1.0
micromark-factory-mdx-expression: 1.0.9
micromark-factory-space: 1.1.0
@@ -6284,7 +6297,7 @@ snapshots:
micromark-extension-mdxjs-esm@1.0.5:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
micromark-core-commonmark: 1.1.0
micromark-util-character: 1.2.0
micromark-util-events-to-acorn: 1.2.3
@@ -6356,7 +6369,7 @@ snapshots:
micromark-factory-mdx-expression@1.0.9:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
micromark-util-character: 1.2.0
micromark-util-events-to-acorn: 1.2.3
micromark-util-symbol: 1.1.0
@@ -6367,7 +6380,7 @@ snapshots:
micromark-factory-mdx-expression@2.0.1:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
devlop: 1.1.0
micromark-util-character: 2.1.0
micromark-util-events-to-acorn: 2.0.2
@@ -6483,7 +6496,7 @@ snapshots:
micromark-util-events-to-acorn@1.2.3:
dependencies:
'@types/acorn': 4.0.6
'@types/estree': 1.0.5
'@types/estree': 1.0.6
'@types/unist': 2.0.10
estree-util-visit: 1.2.1
micromark-util-symbol: 1.1.0
@@ -6494,7 +6507,7 @@ snapshots:
micromark-util-events-to-acorn@2.0.2:
dependencies:
'@types/acorn': 4.0.6
'@types/estree': 1.0.5
'@types/estree': 1.0.6
'@types/unist': 3.0.2
devlop: 1.1.0
estree-util-visit: 2.0.0
@@ -6801,7 +6814,7 @@ snapshots:
periscopic@3.1.0:
dependencies:
'@types/estree': 1.0.5
'@types/estree': 1.0.6
estree-walker: 3.0.3
is-reference: 3.0.2
@@ -6942,14 +6955,6 @@ snapshots:
dependencies:
regex-utilities: 2.3.0
rehype-slug@6.0.0:
dependencies:
'@types/hast': 3.0.4
github-slugger: 2.0.0
hast-util-heading-rank: 3.0.0
hast-util-to-string: 3.0.1
unist-util-visit: 5.0.0
remark-mdx@2.3.0:
dependencies:
mdast-util-mdx: 2.0.1

View File

@@ -16,16 +16,17 @@
"@changesets/cli": "^2.27.10",
"@playwright/test": "^1.50.1",
"@vitejs/plugin-react": "^4.3.3",
"@vitest/browser": "^3.0.5",
"@vitest/coverage-istanbul": "3.0.5",
"@vitest/ui": "3.0.5",
"happy-dom": "^16.8.1",
"@vitest/browser": "^3.1.1",
"@vitest/coverage-istanbul": "3.1.1",
"@vitest/coverage-v8": "3.1.1",
"@vitest/ui": "3.1.1",
"happy-dom": "^17.4.4",
"lefthook": "^1.8.2",
"pkg-pr-new": "^0.0.39",
"playwright": "^1.50.1",
"turbo": "^2.3.1",
"typedoc": "^0.25.13",
"vitest": "3.0.5"
"vitest": "3.1.1"
},
"scripts": {
"dev": "turbo dev",

View File

@@ -1,5 +1,13 @@
# cojson-storage-indexeddb
## 0.13.2
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
- cojson-storage@0.13.2
## 0.13.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "cojson-storage-indexeddb",
"version": "0.13.0",
"version": "0.13.2",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",
@@ -10,9 +10,7 @@
"cojson-storage": "workspace:*"
},
"devDependencies": {
"@vitest/browser": "^3.0.5",
"typescript": "~5.6.2",
"vitest": "3.0.5",
"webdriverio": "^8.15.0"
},
"scripts": {

View File

@@ -1,5 +1,13 @@
# cojson-storage-sqlite
## 0.13.2
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
- cojson-storage@0.13.2
## 0.13.0
### Patch Changes

View File

@@ -1,13 +1,13 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.13.0",
"version": "0.13.2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",
"dependencies": {
"better-sqlite3": "^11.7.0",
"cojson": "workspace:0.13.0",
"cojson": "workspace:0.13.2",
"cojson-storage": "workspace:*"
},
"devDependencies": {

View File

@@ -1,5 +1,12 @@
# cojson-storage
## 0.13.2
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
## 0.13.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "cojson-storage",
"version": "0.13.0",
"version": "0.13.2",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",

View File

@@ -1,5 +1,12 @@
# cojson-transport-nodejs-ws
## 0.13.2
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
## 0.13.0
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-transport-ws",
"type": "module",
"version": "0.13.0",
"version": "0.13.2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",

View File

@@ -126,7 +126,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -214,7 +214,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -243,7 +243,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -269,7 +269,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
const stream: SyncMessage[] = [];
@@ -316,7 +316,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
const stream: SyncMessage[] = [];
@@ -365,7 +365,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -411,7 +411,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);
@@ -450,7 +450,7 @@ describe("createWebSocketPeer", () => {
action: "content",
id: "co_zlow",
new: {},
priority: 1,
priority: 6,
};
void peer.outgoing.push(message1);

View File

@@ -1,5 +1,11 @@
# cojson
## 0.13.2
### Patch Changes
- c551839: Add jazz.messagequeue.pushed/pulled counters, remove jazz.messagequeue.size gauge
## 0.13.0
### Minor Changes

View File

@@ -25,11 +25,10 @@
},
"type": "module",
"license": "MIT",
"version": "0.13.0",
"version": "0.13.2",
"devDependencies": {
"@opentelemetry/sdk-metrics": "^2.0.0",
"typescript": "~5.6.2",
"vitest": "3.0.5"
"typescript": "~5.6.2"
},
"dependencies": {
"@noble/ciphers": "^0.1.3",

View File

@@ -10,10 +10,21 @@ import { CO_VALUE_PRIORITY } from "./priority.js";
import { Peer, SyncMessage } from "./sync.js";
export class PeerState {
private queue: PriorityBasedMessageQueue;
constructor(
private peer: Peer,
knownStates: PeerKnownStates | undefined,
) {
/**
* We set as default priority HIGH to handle all the messages without a
* priority property as HIGH priority.
*
* This way we consider all the non-content messsages as HIGH priority.
*/
this.queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.HIGH, {
peerRole: peer.role,
});
this.optimisticKnownStates = knownStates?.clone() ?? new PeerKnownStates();
// We assume that exchanges with storage peers are always successful
@@ -76,13 +87,6 @@ export class PeerState {
return this.peer.role === "server" || this.peer.role === "storage";
}
/**
* We set as default priority HIGH to handle all the messages without a
* priority property as HIGH priority.
*
* This way we consider all the non-content messsages as HIGH priority.
*/
private queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.HIGH);
private processing = false;
public closed = false;

View File

@@ -1,5 +1,5 @@
import { ValueType, metrics } from "@opentelemetry/api";
import type { CoValuePriority } from "./priority.js";
import { Counter, ValueType, metrics } from "@opentelemetry/api";
import { CO_VALUE_PRIORITY, type CoValuePriority } from "./priority.js";
import type { SyncMessage } from "./sync.js";
function promiseWithResolvers<R>() {
@@ -34,7 +34,7 @@ type Tuple<T, N extends number, A extends unknown[] = []> = A extends {
? A
: Tuple<T, N, [...A, T]>;
type QueueTuple = Tuple<LinkedList<QueueEntry>, 8>;
type QueueTuple = Tuple<LinkedList<QueueEntry>, 3>;
type LinkedListNode<T> = {
value: T;
@@ -46,6 +46,8 @@ type LinkedListNode<T> = {
* as our queues can grow very large when the system is under pressure.
*/
export class LinkedList<T> {
constructor(private meter?: QueueMeter) {}
head: LinkedListNode<T> | undefined = undefined;
tail: LinkedListNode<T> | undefined = undefined;
length = 0;
@@ -64,6 +66,7 @@ export class LinkedList<T> {
}
this.length++;
this.meter?.push();
}
shift() {
@@ -82,34 +85,83 @@ export class LinkedList<T> {
this.length--;
this.meter?.pull();
return value;
}
}
export class PriorityBasedMessageQueue {
private queues: QueueTuple = [
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
new LinkedList<QueueEntry>(),
];
queueSizeCounter = metrics
.getMeter("cojson")
.createUpDownCounter("jazz.messagequeue.size", {
description: "Size of the message queue",
valueType: ValueType.INT,
unit: "entry",
});
class QueueMeter {
private pullCounter: Counter;
private pushCounter: Counter;
private getQueue(priority: CoValuePriority) {
return this.queues[priority];
constructor(
prefix: string,
private attrs?: Record<string, string | number>,
) {
this.pullCounter = metrics
.getMeter("cojosn")
.createCounter(`${prefix}.pulled`, {
description: "Number of messages pulled from the queue",
valueType: ValueType.INT,
unit: "1",
});
this.pushCounter = metrics
.getMeter("cojosn")
.createCounter(`${prefix}.pushed`, {
description: "Number of messages pushed to the queue",
valueType: ValueType.INT,
unit: "1",
});
/**
* This makes sure that those metrics are generated (and emitted) as soon as the queue is created.
* This is to avoid edge cases where one series reset is delayed, which would cause spikes or dips
* when queried - and it also more correctly represents the actual state of the queue after a restart.
*/
this.pullCounter.add(0, this.attrs);
this.pushCounter.add(0, this.attrs);
}
constructor(private defaultPriority: CoValuePriority) {}
public pull() {
this.pullCounter.add(1, this.attrs);
}
public push() {
this.pushCounter.add(1, this.attrs);
}
}
function meteredList<T>(attrs?: Record<string, string | number>) {
return new LinkedList<T>(new QueueMeter("jazz.messagequeue", attrs));
}
const PRIORITY_TO_QUEUE_INDEX = {
[CO_VALUE_PRIORITY.HIGH]: 0,
[CO_VALUE_PRIORITY.MEDIUM]: 1,
[CO_VALUE_PRIORITY.LOW]: 2,
} as const;
export class PriorityBasedMessageQueue {
private queues: QueueTuple;
constructor(
private defaultPriority: CoValuePriority,
/**
* Optional attributes to be added to the generated metrics.
* By default the metrics will have the priority as an attribute.
*/
attrs?: Record<string, string | number>,
) {
this.queues = [
meteredList({ priority: CO_VALUE_PRIORITY.HIGH, ...attrs }),
meteredList({ priority: CO_VALUE_PRIORITY.MEDIUM, ...attrs }),
meteredList({ priority: CO_VALUE_PRIORITY.LOW, ...attrs }),
];
}
private getQueue(priority: CoValuePriority) {
return this.queues[PRIORITY_TO_QUEUE_INDEX[priority]];
}
public push(msg: SyncMessage) {
const { promise, resolve, reject } = promiseWithResolvers<void>();
@@ -119,24 +171,12 @@ export class PriorityBasedMessageQueue {
this.getQueue(priority).push(entry);
this.queueSizeCounter.add(1, {
priority,
});
return promise;
}
public pull() {
const priority = this.queues.findIndex((queue) => queue.length > 0);
if (priority === -1) {
return;
}
this.queueSizeCounter.add(-1, {
priority,
});
return this.queues[priority]?.shift();
}
}

View File

@@ -1,4 +1,3 @@
import { randomBytes } from "@noble/ciphers/webcrypto/utils";
import { base58 } from "@scure/base";
import { RawAccountID } from "../coValues/account.js";
import { AgentID, RawCoID, TransactionID } from "../ids.js";
@@ -7,6 +6,10 @@ import { Stringified, parseJSON, stableStringify } from "../jsonStringify.js";
import { JsonValue } from "../jsonValue.js";
import { logger } from "../logger.js";
function randomBytes(bytesLength = 32): Uint8Array {
return crypto.getRandomValues(new Uint8Array(bytesLength));
}
export type SignerSecret = `signerSecret_z${string}`;
export type SignerID = `signer_z${string}`;
export type Signature = `signature_z${string}`;

View File

@@ -7,7 +7,7 @@ import { type CoValueHeader } from "./coValueCore.js";
* The priority value is handled as weight in the weighed round robin algorithm
* used to determine the order in which messages are sent.
*
* Follows the HTTP urgency range and order:
* Loosely follows the HTTP urgency range and order, but limited to 3 values:
* - https://www.rfc-editor.org/rfc/rfc9218.html#name-urgency
*/
export const CO_VALUE_PRIORITY = {
@@ -16,7 +16,7 @@ export const CO_VALUE_PRIORITY = {
LOW: 6,
} as const;
export type CoValuePriority = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export type CoValuePriority = 0 | 3 | 6;
export function getPriorityFromHeader(
header: CoValueHeader | undefined | boolean,

View File

@@ -7,9 +7,9 @@ import {
tearDownTestMetricReader,
} from "./testUtils.js";
function setup() {
function setup(attrs?: Record<string, string | number>) {
const metricReader = createTestMetricReader();
const queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.MEDIUM);
const queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.MEDIUM, attrs);
return { queue, metricReader };
}
@@ -18,10 +18,133 @@ describe("PriorityBasedMessageQueue", () => {
tearDownTestMetricReader();
});
describe("meteredQueue", () => {
test("should corretly count pushes", async () => {
const { queue, metricReader } = setup();
const message: SyncMessage = {
action: "load",
id: "co_ztest-id",
header: false,
sessions: {},
};
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(0);
void queue.push(message);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(1);
void queue.push(message);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(2);
});
test("should corretly count pulls", async () => {
const { queue, metricReader } = setup();
const message: SyncMessage = {
action: "load",
id: "co_ztest-id",
header: false,
sessions: {},
};
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(0);
void queue.push(message);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(0);
void queue.pull();
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(1);
// We only have one item in the queue, so this should not change the metric value
void queue.pull();
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
}),
).toBe(1);
});
test("should corretly set custom attributes to the metrics", async () => {
const { queue, metricReader } = setup({ role: "server" });
const message: SyncMessage = {
action: "load",
id: "co_ztest-id",
header: false,
sessions: {},
};
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(0);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "client",
}),
).toBeUndefined();
void queue.push(message);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(1);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(0);
void queue.pull();
expect(
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(1);
expect(
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
priority: CO_VALUE_PRIORITY.MEDIUM,
role: "server",
}),
).toBe(1);
});
});
test("should initialize with correct properties", () => {
const { queue } = setup();
expect(queue["defaultPriority"]).toBe(CO_VALUE_PRIORITY.MEDIUM);
expect(queue["queues"].length).toBe(8);
expect(queue["queues"].length).toBe(3);
expect(queue["queues"].every((q) => !q.length)).toBe(true);
});
@@ -52,7 +175,7 @@ describe("PriorityBasedMessageQueue", () => {
});
test("should pull messages in priority order", async () => {
const { queue, metricReader } = setup();
const { queue } = setup();
const lowPriorityMsg: SyncMessage = {
action: "content",
id: "co_zlow",
@@ -73,42 +196,12 @@ describe("PriorityBasedMessageQueue", () => {
};
void queue.push(lowPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: lowPriorityMsg.priority,
}),
).toBe(1);
void queue.push(mediumPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: mediumPriorityMsg.priority,
}),
).toBe(1);
void queue.push(highPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: highPriorityMsg.priority,
}),
).toBe(1);
expect(queue.pull()?.msg).toEqual(highPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: highPriorityMsg.priority,
}),
).toBe(0);
expect(queue.pull()?.msg).toEqual(mediumPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: mediumPriorityMsg.priority,
}),
).toBe(0);
expect(queue.pull()?.msg).toEqual(lowPriorityMsg);
expect(
await metricReader.getMetricValue("jazz.messagequeue.size", {
priority: lowPriorityMsg.priority,
}),
).toBe(0);
});
test("should return undefined when pulling from empty queue", () => {

View File

@@ -1,5 +1,14 @@
# jazz-auth-clerk
## 0.13.2
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
- jazz-browser@0.13.2
- jazz-tools@0.13.2
## 0.13.0
### Patch Changes

View File

@@ -1,14 +1,14 @@
{
"name": "jazz-auth-clerk",
"version": "0.13.0",
"version": "0.13.2",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:0.13.0",
"jazz-browser": "workspace:0.13.0",
"jazz-tools": "workspace:0.13.0"
"cojson": "workspace:0.13.2",
"jazz-browser": "workspace:0.13.2",
"jazz-tools": "workspace:0.13.2"
},
"scripts": {
"format-and-lint": "biome check .",

View File

@@ -1,5 +1,12 @@
# jazz-browser-media-images
## 0.13.2
### Patch Changes
- jazz-browser@0.13.2
- jazz-tools@0.13.2
## 0.13.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser-media-images",
"version": "0.13.0",
"version": "0.13.2",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -8,8 +8,8 @@
"dependencies": {
"@types/image-blob-reduce": "^4.1.1",
"image-blob-reduce": "^4.1.0",
"jazz-browser": "workspace:0.13.0",
"jazz-tools": "workspace:0.13.0",
"jazz-browser": "workspace:0.13.2",
"jazz-tools": "workspace:0.13.2",
"pica": "^9.0.1",
"typescript": "~5.6.2"
},

View File

@@ -1,5 +1,15 @@
# jazz-browser
## 0.13.2
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
- cojson-storage-indexeddb@0.13.2
- cojson-transport-ws@0.13.2
- jazz-tools@0.13.2
## 0.13.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser",
"version": "0.13.0",
"version": "0.13.2",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@@ -1,5 +1,23 @@
# jazz-browser
## 0.13.2
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
- cojson-transport-ws@0.13.2
- jazz-auth-clerk@0.13.2
- jazz-react-core@0.13.2
- jazz-react-native-core@0.13.2
- jazz-tools@0.13.2
## 0.13.1
### Patch Changes
- 63a7aa0: Add exports for clerk and crypto to make import shortcuts work everywhere
## 0.13.0
### Minor Changes

2
packages/jazz-expo/auth/clerk.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
// Re-export the Clerk provider from the dist folder to make the `jazz-expo/auth/clerk` import work everywhere
export * from "../dist/auth/clerk";

Some files were not shown because too many files have changed in this diff Show More