Compare commits

..

17 Commits

Author SHA1 Message Date
Guido D'Orsi
748c2ff751 Merge pull request #2688 from garden-co/changeset-release/main
Version Packages
2025-08-01 15:46:41 +02:00
github-actions[bot]
70938b0ab3 Version Packages 2025-08-01 13:42:25 +00:00
Guido D'Orsi
3c3acae803 Merge pull request #2689 from joeinnes/2687-fix-broken-link
Fix HTTP API link in inbox.mdx. Fixes #2687
2025-08-01 15:40:07 +02:00
Joe Innes
9b9bf44e2b Fix HTTP API link in inbox.mdx. Fixes #2687 2025-08-01 15:13:33 +02:00
Guido D'Orsi
392aa88d95 Merge pull request #2655 from joeinnes/docs/optional-references
Docs/optional references
2025-08-01 13:15:20 +02:00
Joe Innes
7ce82cd934 Merge branch 'main' into docs/optional-references 2025-08-01 13:13:26 +02:00
Guido D'Orsi
0c8158b91c Merge pull request #2676 from Gabrola/fix/jazz-run-exports
fix: jazz-run package.json exports
2025-08-01 13:07:30 +02:00
Guido D'Orsi
25c56146f5 Merge pull request #2686 from garden-co/test/logout-state
test: logout integration tests on browser
2025-08-01 09:57:18 +02:00
Guido D'Orsi
12481e14c2 test: logout integration tests on browser 2025-07-31 18:56:37 +02:00
Anselm
0ab4d7a20d Update meta description 2025-07-30 11:34:54 -07:00
Anselm Eickhoff
88ebcf58ab Merge pull request #2680 from garden-co/jazz-as-a-db
Jazz as a DB narrative MVP
2025-07-28 11:34:01 -07:00
Anselm
f379a168be Update garden co slogan 2025-07-28 10:30:18 -07:00
Anselm
bde6ac7d45 Jazz as a DB narrative MVP 2025-07-28 10:08:56 -07:00
Youssef Gaber
239da90c9f chore: changeset 2025-07-28 17:06:01 +04:00
Youssef Gaber
972791e7a8 fix: correct jazz-run package.json exports 2025-07-28 17:05:45 +04:00
Joe Innes
6b662b0efe Type fixes for twoslash 2025-07-18 15:06:03 +02:00
Joe Innes
a8b3ec7bb0 Add more detail regarding optional references
As the boundary becomes more defined between CoValue schemas and Zod schemas, we need to ensure folks pick the right `.optional()` between `co.optional()` for CoValues and `z.optional()` for primitives.
2025-07-17 20:24:03 +02:00
46 changed files with 417 additions and 178 deletions

View File

@@ -1,5 +1,11 @@
# passkey-svelte
## 0.0.108
### Patch Changes
- jazz-tools@0.16.2
## 0.0.107
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-svelte",
"version": "0.0.107",
"version": "0.0.108",
"type": "module",
"private": true,
"scripts": {

View File

@@ -41,7 +41,9 @@ export function Footer({
</Link>
</div>
<p className="col-span-full sm:col-span-6 md:col-span-4 text-sm sm:text-base">
Playful software for serious problems.
Computers are magic.
<br />
Time to make them less complex.
</p>
</div>
<div className="grid gap-y-8 grid-cols-12">

View File

@@ -1,6 +1,5 @@
import { ChatDemoSection } from "@/components/home/ChatDemoSection";
import { CollaborationFeaturesSection } from "@/components/home/CollaborationFeaturesSection";
import { ComingSoonSection } from "@/components/home/ComingSoonSection";
import { EarlyAdopterSection } from "@/components/home/EarlyAdopterSection";
import { EncryptionSection } from "@/components/home/EncryptionSection";
import { FeaturesSection } from "@/components/home/FeaturesSection";
@@ -15,9 +14,9 @@ import { Testimonial } from "@garden-co/design-system/src/components/molecules/T
export default function Home() {
return (
<>
<HeroSection />
<HeroSection />
<div className="container flex flex-col gap-12 lg:gap-20">
<GetStartedSnippetSelect />
<SupportedEnvironmentsSection />
<HowJazzWorksSection />
@@ -54,8 +53,6 @@ export default function Home() {
<FeaturesSection />
<ComingSoonSection />
<EarlyAdopterSection />
</div>
</>

View File

@@ -1,54 +0,0 @@
import CoPlainTextDescription from "@/app/(others)/(home)/coValueDescriptions/coPlainTextDescription.mdx";
import CursorsAndCaretsDescription from "@/app/(others)/(home)/toolkit/cursorsAndCarets.mdx";
import TwoWaySyncDescription from "@/app/(others)/(home)/toolkit/twoWaySync.mdx";
import VideoPresenceCallsDescription from "@/app/(others)/(home)/toolkit/videoPresenceCalls.mdx";
import { CodeRef } from "@garden-co/design-system/src/components/atoms/CodeRef";
import { P } from "@garden-co/design-system/src/components/atoms/Paragraph";
import { FeatureCard } from "@garden-co/design-system/src/components/molecules/FeatureCard";
import { GappedGrid } from "@garden-co/design-system/src/components/molecules/GappedGrid";
import { Prose } from "@garden-co/design-system/src/components/molecules/Prose";
import { SectionHeader } from "@garden-co/design-system/src/components/molecules/SectionHeader";
export function ComingSoonSection() {
return (
<div>
<SectionHeader title="More features coming soon" />
<GappedGrid cols={4}>
<FeatureCard className="p-4" label={<h3>Cursors & carets</h3>}>
<P>Ready-made spatial presence.</P>
<Prose size="sm">
<CursorsAndCaretsDescription />
</Prose>
</FeatureCard>
<FeatureCard className="p-4" label={<h3>Two-way sync to your DB</h3>}>
<P>Add Jazz to an existing app.</P>
<Prose size="sm">
<TwoWaySyncDescription />
</Prose>
</FeatureCard>
<FeatureCard className="p-4" label={<h3>Video presence & calls</h3>}>
<P>Stream and record audio & video.</P>
<Prose size="sm">
<VideoPresenceCallsDescription />
</Prose>
</FeatureCard>
<FeatureCard
className="p-4"
label={
<h3>
<CodeRef>CoPlainText</CodeRef> & <CodeRef>CoRichText</CodeRef>
</h3>
}
>
<Prose size="sm">
<CoPlainTextDescription />
</Prose>
</FeatureCard>
</GappedGrid>
</div>
);
}

View File

@@ -16,81 +16,70 @@ const features: Array<{
title: string;
icon: IconName;
}> = [
{
title: "Instant updates",
icon: "instant",
},
{
title: "Real-time sync",
icon: "devices",
},
{
title: "Multiplayer",
icon: "spatialPresence",
},
{
title: "File uploads",
icon: "upload",
},
{
title: "Social features",
icon: "social",
},
{
title: "Permissions",
icon: "permissions",
},
{
title: "E2E encryption",
icon: "encryption",
},
{
title: "Authentication",
icon: "auth",
},
];
{
title: "Instant updates",
icon: "instant",
},
{
title: "Real-time sync",
icon: "devices",
},
{
title: "Multiplayer",
icon: "spatialPresence",
},
{
title: "File uploads",
icon: "upload",
},
{
title: "Social features",
icon: "social",
},
{
title: "Permissions",
icon: "permissions",
},
{
title: "E2E encryption",
icon: "encryption",
},
{
title: "Authentication",
icon: "auth",
},
];
export function HeroSection() {
return (
<div className="container grid items-center gap-x-8 gap-y-12 my-12 md:my-16 lg:my-24 lg:gap-x-10 lg:grid-cols-12">
<div className="container grid items-center gap-x-8 gap-y-12 mt-12 md:mt-16 lg:mt-24 mb-12 lg:gap-x-10 lg:grid-cols-12">
<div className="flex flex-col justify-center gap-5 lg:col-span-11 lg:gap-8">
<Kicker>Toolkit for backendless apps</Kicker>
<Kicker>Reactive, distributed, secure</Kicker>
<H1>
<span className="inline-block text-highlight">
{marketingCopy.headline}
</span>
</H1>
<Prose size="lg" className="text-pretty max-w-2xl dark:text-stone-200">
<Prose size="lg" className="text-pretty max-w-2xl dark:text-stone-200 prose-p:leading-normal">
<p>
Jazz gives you data without needing a database plus auth,
permissions, files and multiplayer without needing a backend.
Jazz is a new kind of database that's distributed across your frontend, containers, serverless functions and its own storage cloud.
</p>
<p>It syncs structured data, files and LLM streams instantly.<br/>It looks like local reactive JSON state.</p>
<p>And you get auth, orgs & teams, real-time multiplayer, edit histories, permissions, E2E encryption and offline-support out of the box.</p>
<p>
Do everything right from the frontend and ship better apps, faster.
This lets you get rid of 90% of the traditional backend, and most of your frontend state juggling.
You&apos;ll ship better apps, faster.
</p>
<p>
Open source. Self-host or use{" "}
<p className="text-base">
Self-host or use{" "}
<Link className="text-reset" href="/cloud">
Jazz Cloud
</Link>{" "}
for zero-config magic.
for a zero-deploy globally-scaled DB.
<br/>Open source (MIT)
</p>
</Prose>
<div className="grid grid-cols-2 gap-2 max-w-3xl sm:grid-cols-4 sm:gap-4">
{features.map(({ title, icon }) => (
<div
key={title}
className="flex text-xs sm:text-sm gap-2 items-center"
>
<span className="p-1.5 rounded-lg bg-primary-transparent">
<Icon size="xs" name={icon} intent="primary" />
</span>
<p>{title}</p>
</div>
))}
</div>
</div>
</div>
);

View File

@@ -83,7 +83,7 @@ export function HowJazzWorksSection() {
<div className="grid gap-3">
<Kicker>How it works</Kicker>
<H2>Build entire apps using only client-side code</H2>
<H2>Build entire apps with collaborative state</H2>
</div>
<GappedGrid>
<Step

View File

@@ -53,7 +53,7 @@ export function LocalFirstFeaturesSection() {
return (
<div>
<SectionHeader
title="The best of all worlds"
title="Local-first state with global sync"
slogan={
<>
<p>

View File

@@ -9,7 +9,7 @@ export default function ProblemStatementSection() {
<div className="grid gap-4 lg:gap-8">
<SectionHeader
className="sm:text-center sm:mx-auto"
title={"Powered by the first “flat stack”"}
title={"A database that does what's actually needed"}
slogan="A perspective shift worth 10,000 hours"
/>
@@ -41,8 +41,7 @@ export default function ProblemStatementSection() {
<Prose>
<p>
For each new app you tackle a{" "}
<strong>mess of moving parts and infra worries.</strong> Or, you
haven't even tried because "you're not full-stack".
<strong>mess of moving parts and infra worries.</strong> Your backend is responsible for shuffling data around in a myriad of ways.
</p>
<p>
Want to build a <strong>modern app</strong> with multiplayer or
@@ -68,7 +67,7 @@ export default function ProblemStatementSection() {
<strong>With users &amp; permissions built-in.</strong>
</p>
<p>
With completely <strong>app-independent infra,</strong> you get to
With a <strong>DB and infra made for modern apps</strong> you get to
focus on <strong>building the app your users want.</strong> You'll
notice that <strong>90% of the work is now the UI.</strong>
</p>

View File

@@ -1,5 +1,6 @@
import { BunLogo } from "@/components/icons/BunLogo";
import { CloudflareWorkerLogo } from "@/components/icons/CloudflareWorkerLogo";
import { VercelLogo } from "@/components/icons/VercelLogo";
import { ExpoLogo } from "@/components/icons/ExpoLogo";
import { JavascriptLogo } from "@/components/icons/JavascriptLogo";
import { NodejsLogo } from "@/components/icons/NodejsLogo";
@@ -44,14 +45,18 @@ const serverWorkers = [
icon: NodejsLogo,
href: "/docs/react/server-workers",
},
{
name: "Cloudflare Workers",
icon: CloudflareWorkerLogo,
},
{
name: "Bun",
icon: BunLogo,
},
{
name: "Vercel",
icon: VercelLogo,
},
{
name: "CF Workers",
icon: CloudflareWorkerLogo,
}
];
export function SupportedEnvironmentsSection() {

View File

@@ -0,0 +1,16 @@
import React from "react";
import type { SVGProps } from "react";
export function VercelLogo(props: SVGProps<SVGSVGElement>) {
return (
<svg
width="1.5em"
height="1.5em"
viewBox="0 0 76 65"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M37.5274 0L75.0548 65H0L37.5274 0Z" fill="currentColor" />
</svg>
);
}

View File

@@ -54,7 +54,7 @@ function AuthStateIndicator() {
const isGuest = agent._type !== "Account"
// Anonymous authentication: has an account but not fully authenticated
const isAnonymous = agent._type === "Account" && !isAuthenticated;
const isAnonymous = agent._type === "Account" && !isAuthenticated;
return (
<div>
{isGuest && <span>Guest Mode</span>}

View File

@@ -31,7 +31,7 @@ export const Organization = co.map({
name: z.string(),
// shared data between users of each organization
projects: co.list(Project),
projects: co.list(Project),
});
export const ListOfOrganizations = co.list(Organization);
@@ -115,7 +115,7 @@ import * as React from "react";
import { useAcceptInvite, useAccount } from "jazz-tools/react";
import { co, z } from "jazz-tools";
const Project = z.object({
const Project = co.map({
name: z.string(),
});

View File

@@ -7,9 +7,11 @@ export const metadata = {
# Learn some <span className="sr-only">Jazz</span> <JazzLogo className="h-[41px] -ml-0.5 -mt-[3px] inline" />
**Jazz is a toolkit for building backendless apps**. You get data without needing a database — plus auth, permissions, files and multiplayer without needing a backend. Jazz lets you do everything right from the frontend and you'll ship better apps, faster.
**Jazz is a new kind of database** that's **distributed** across your frontend, containers, serverless functions and its own storage cloud.
Instead of wrestling with databases, APIs, and server infrastructure, you work with **CoValues** ("collaborative values") — your new cloud-synced building blocks that feel like local state but automatically sync across all devices and users in real-time.
It syncs structured data, files and LLM streams instantly, and looks like local reactive JSON state.
It also provides auth, orgs & teams, real-time multiplayer, edit histories, permissions, E2E encryption and offline-support out of the box.
---
@@ -19,7 +21,7 @@ You can use [`create-jazz-app`](/docs/tools/create-jazz-app) to create a new Jaz
<CodeGroup>
```sh
npx create-jazz-app@latest --api-key you@example.com
npx create-jazz-app@latest --api-key you@example.com
```
</CodeGroup>
@@ -30,21 +32,10 @@ Or you can follow this [React step-by-step guide](/docs/react/guide) where we wa
</ContentByFramework> */}
## Why Jazz is different
Most apps rebuild the same thing: shared state that syncs between users and devices. Jazz starts from that shared state, giving you:
- **No backend required** — Focus on building features, not infrastructure
- **Real-time sync** — Changes appear everywhere immediately
- **Multiplayer by default** — Collaboration just works
- **Local-first** — Your app works offline and feels instant
Think Figma, Notion, or Linear — but you don't need years to build a custom stack.
## How it works
1. **Define your data** with CoValues schemas
2. **Connect to sync infrastructure** (Jazz Cloud or self-hosted)
2. **Connect to storage infrastructure** (Jazz Cloud or self-hosted)
3. **Create and edit CoValues** like normal objects
4. **Get automatic sync and persistence** across all devices and users

View File

@@ -320,6 +320,10 @@ const Company = co.map({
</CodeGroup>
#### Optional References
You can make schema fields optional using either `z.optional()` or `co.optional()`, depending on the type of value:
- Use `z.optional()` for primitive Zod values like `z.string()`, `z.number()`, or `z.boolean()`
- Use `co.optional()` for CoValues like `co.map()`, `co.list()`, or `co.record()`
You can make references optional with `co.optional()`:
@@ -331,7 +335,8 @@ const Pet = co.map({
});
// ---cut---
const Person = co.map({
pet: co.optional(Pet),
age: z.optional(z.number()), // primitive
pet: co.optional(Pet), // CoValue
});
```
</CodeGroup>

View File

@@ -7,7 +7,7 @@ import { Alert } from "@garden-co/design-system/src/components/atoms/Alert";
# Inbox API with Server Workers
The Inbox API provides a message-based communication system for Server Workers in Jazz.
The Inbox API provides a message-based communication system for Server Workers in Jazz.
It works on top of the Jazz APIs and uses sync to transfer messages between the client and the server.
@@ -154,8 +154,8 @@ function EventComponent({ event }: { event: Event }) {
```
</CodeGroup>
The `sendInboxMessage` API returns a Promise that waits for the message to be handled by a Worker.
A message is considered to be handled when the Promise returned by `inbox.subscribe` resolves.
The `sendInboxMessage` API returns a Promise that waits for the message to be handled by a Worker.
A message is considered to be handled when the Promise returned by `inbox.subscribe` resolves.
The value returned will be the id of the CoValue returned in the `inbox.subscribe` resolved promise.
@@ -163,4 +163,4 @@ The value returned will be the id of the CoValue returned in the `inbox.subscrib
Multi-region deployments are not supported when using the Inbox API.
If you need to split the workload across multiple regions, you can use the [HTTP API](./http-requests.mdx) instead.
If you need to split the workload across multiple regions, you can use the [HTTP API](./http-requests) instead.

View File

@@ -1,5 +1,5 @@
export const marketingCopy = {
headline: "Whip up an app",
headline: "Smooth database.",
description:
"Jazz gives you data without needing a database — plus auth, permissions, files and multiplayer without needing a backend. Do everything right from the frontend and ship better apps, faster.",
"Jazz is a database that's distributed across your frontend, containers and functions. It syncs structured data, files and LLM streams instantly and looks like local reactive JSON state.",
};

View File

@@ -1,5 +1,11 @@
# cojson-storage-indexeddb
## 0.16.2
### Patch Changes
- cojson@0.16.2
## 0.16.1
### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# cojson-storage-sqlite
## 0.16.2
### Patch Changes
- cojson@0.16.2
## 0.16.1
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.16.1",
"version": "0.16.2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",

View File

@@ -1,5 +1,11 @@
# cojson-transport-nodejs-ws
## 0.16.2
### Patch Changes
- cojson@0.16.2
## 0.16.1
### Patch Changes

View File

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

View File

@@ -1,5 +1,7 @@
# cojson
## 0.16.2
## 0.16.1
## 0.16.0

View File

@@ -25,7 +25,7 @@
},
"type": "module",
"license": "MIT",
"version": "0.16.1",
"version": "0.16.2",
"devDependencies": {
"@opentelemetry/sdk-metrics": "^2.0.0",
"libsql": "^0.5.13",

View File

@@ -1,5 +1,13 @@
# jazz-auth-betterauth
## 0.16.2
### Patch Changes
- cojson@0.16.2
- jazz-betterauth-client-plugin@0.16.2
- jazz-tools@0.16.2
## 0.16.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-auth-betterauth",
"version": "0.16.1",
"version": "0.16.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,11 @@
# jazz-betterauth-client-plugin
## 0.16.2
### Patch Changes
- jazz-betterauth-server-plugin@0.16.2
## 0.16.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-betterauth-client-plugin",
"version": "0.16.1",
"version": "0.16.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,12 @@
# jazz-betterauth-server-plugin
## 0.16.2
### Patch Changes
- cojson@0.16.2
- jazz-tools@0.16.2
## 0.16.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-betterauth-server-plugin",
"version": "0.16.1",
"version": "0.16.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,14 @@
# jazz-react-auth-betterauth
## 0.16.2
### Patch Changes
- cojson@0.16.2
- jazz-auth-betterauth@0.16.2
- jazz-betterauth-client-plugin@0.16.2
- jazz-tools@0.16.2
## 0.16.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react-auth-betterauth",
"version": "0.16.1",
"version": "0.16.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.tsx",

View File

@@ -1,5 +1,15 @@
# jazz-run
## 0.16.2
### Patch Changes
- 239da90: Fix jazz-run package.json exports
- cojson@0.16.2
- cojson-storage-sqlite@0.16.2
- cojson-transport-ws@0.16.2
- jazz-tools@0.16.2
## 0.16.1
### Patch Changes

View File

@@ -3,15 +3,15 @@
"bin": "./dist/index.js",
"type": "module",
"license": "MIT",
"version": "0.16.1",
"version": "0.16.2",
"exports": {
"./startSyncServer": {
"import": "./dist/startSyncServer.js",
"types": "./dist/startSyncServer.d.ts"
"types": "./dist/startSyncServer.d.ts",
"default": "./dist/startSyncServer.js"
},
"./createWorkerAccount": {
"import": "./dist/createWorkerAccount.js",
"types": "./dist/createWorkerAccount.d.ts"
"types": "./dist/createWorkerAccount.d.ts",
"default": "./dist/createWorkerAccount.js"
}
},
"scripts": {
@@ -28,11 +28,11 @@
"@effect/printer-ansi": "^0.34.5",
"@effect/schema": "^0.71.1",
"@effect/typeclass": "^0.25.5",
"cojson": "workspace:0.16.1",
"cojson-storage-sqlite": "workspace:0.16.1",
"cojson-transport-ws": "workspace:0.16.1",
"cojson": "workspace:0.16.2",
"cojson-storage-sqlite": "workspace:0.16.2",
"cojson-transport-ws": "workspace:0.16.2",
"effect": "^3.6.5",
"jazz-tools": "workspace:0.16.1",
"jazz-tools": "workspace:0.16.2",
"ws": "^8.14.2"
},
"devDependencies": {

View File

@@ -1,5 +1,13 @@
# jazz-tools
## 0.16.2
### Patch Changes
- cojson@0.16.2
- cojson-storage-indexeddb@0.16.2
- cojson-transport-ws@0.16.2
## 0.16.1
### Patch Changes

View File

@@ -139,7 +139,7 @@
},
"type": "module",
"license": "MIT",
"version": "0.16.1",
"version": "0.16.2",
"dependencies": {
"@manuscripts/prosemirror-recreate-steps": "^0.1.4",
"@scure/base": "1.2.1",

24
pnpm-lock.yaml generated
View File

@@ -1842,19 +1842,19 @@ importers:
specifier: ^0.25.5
version: 0.25.8(effect@3.11.9)
cojson:
specifier: workspace:0.16.1
specifier: workspace:0.16.2
version: link:../cojson
cojson-storage-sqlite:
specifier: workspace:0.16.1
specifier: workspace:0.16.2
version: link:../cojson-storage-sqlite
cojson-transport-ws:
specifier: workspace:0.16.1
specifier: workspace:0.16.2
version: link:../cojson-transport-ws
effect:
specifier: ^3.6.5
version: 3.11.9
jazz-tools:
specifier: workspace:0.16.1
specifier: workspace:0.16.2
version: link:../jazz-tools
ws:
specifier: ^8.14.2
@@ -2182,6 +2182,15 @@ importers:
tests/browser-integration:
dependencies:
'@testing-library/jest-dom':
specifier: 6.6.3
version: 6.6.3
'@testing-library/react':
specifier: 16.2.0
version: 16.2.0(@testing-library/dom@10.4.0)(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@vitejs/plugin-react-swc':
specifier: ^3.10.1
version: 3.10.1(@swc/helpers@0.5.17)(vite@6.3.5(@types/node@22.16.5)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.6.1))
cojson:
specifier: workspace:*
version: link:../../packages/cojson
@@ -2197,6 +2206,12 @@ importers:
jazz-tools:
specifier: workspace:*
version: link:../../packages/jazz-tools
react:
specifier: 19.1.0
version: 19.1.0
react-dom:
specifier: 19.1.0
version: 19.1.0(react@19.1.0)
devDependencies:
typescript:
specifier: 'catalog:'
@@ -12406,6 +12421,7 @@ packages:
source-map@0.8.0-beta.0:
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
engines: {node: '>= 8'}
deprecated: The work that was done in this beta branch won't be included in future versions
sourcemap-codec@1.4.8:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}

View File

@@ -1,5 +1,11 @@
# jazz-react-tailwind-starter
## 0.0.139
### Patch Changes
- jazz-tools@0.16.2
## 0.0.138
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-react-passkey-auth-starter",
"private": true,
"version": "0.0.138",
"version": "0.0.139",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,11 @@
# svelte-passkey-auth
## 0.0.113
### Patch Changes
- jazz-tools@0.16.2
## 0.0.112
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "svelte-passkey-auth",
"version": "0.0.112",
"version": "0.0.113",
"type": "module",
"private": true,
"scripts": {

View File

@@ -15,6 +15,11 @@
"cojson-storage-indexeddb": "workspace:*",
"cojson-storage-sqlite": "workspace:*",
"cojson-transport-ws": "workspace:*",
"jazz-tools": "workspace:*"
"jazz-tools": "workspace:*",
"react": "19.1.0",
"react-dom": "19.1.0",
"@vitejs/plugin-react-swc": "^3.10.1",
"@testing-library/react": "16.2.0",
"@testing-library/jest-dom": "6.6.3"
}
}

View File

@@ -0,0 +1,179 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { commands } from "@vitest/browser/context";
import { AuthSecretStorage, co, z } from "jazz-tools";
import { JazzReactProvider, useAccount, useCoState } from "jazz-tools/react";
import { afterAll, afterEach, describe, expect, test } from "vitest";
import { createAccountContext, startSyncServer } from "./testUtils";
// Define a simple account schema for testing
const TestMap = co.map({ count: co.map({ value: z.number() }) });
const TestAccount = co
.account({
profile: co.map({ name: z.string() }),
root: TestMap,
})
.withMigration((account) => {
if (!account.root) {
account.root = TestMap.create(
{ count: TestMap.shape.count.create({ value: 0 }) },
{ owner: account },
);
}
});
// React component that uses Jazz hooks for testing logout behavior
function TestLogoutComponent({
onLogout,
}: {
onLogout?: () => void;
}) {
const { logOut, me } = useAccount(TestAccount, {
resolve: {
profile: true,
},
});
const root = useCoState(TestAccount.shape.root, me?.root?.id, {
resolve: {
count: true,
},
});
const handleLogout = () => {
logOut();
onLogout?.();
};
if (me && root) {
return (
<div>
<p data-testid="user-name">Welcome, {me.profile.name}</p>
<p data-testid="root-value">{root.count.value}</p>
<button
data-testid="increment-button"
onClick={() => {
root.count.value++;
}}
>
Increment
</button>
<button data-testid="logout-button" onClick={handleLogout}>
Logout
</button>
</div>
);
}
return (
<div>
<p data-testid="not-authenticated">Not authenticated</p>
</div>
);
}
afterAll(async () => {
await commands.cleanup();
});
describe("Jazz logout behavior in React apps", () => {
afterEach(async () => {
await new AuthSecretStorage().clear();
});
test("should update the profile state on logout", async () => {
const syncServer = await startSyncServer();
let logoutCallbackCalled = false;
// Create an authenticated account context
await createAccountContext({
defaultProfileName: "John Doe",
sync: {
peer: syncServer.url,
},
storage: "indexedDB",
AccountSchema: TestAccount,
});
// Render the React component with Jazz provider
const { unmount } = render(
<JazzReactProvider
sync={{ peer: syncServer.url }}
storage="indexedDB"
AccountSchema={TestAccount}
defaultProfileName="Anonymous user"
>
<TestLogoutComponent
onLogout={() => {
logoutCallbackCalled = true;
}}
/>
</JazzReactProvider>,
);
await waitFor(() => {
expect(screen.getByTestId("user-name")).toBeInTheDocument();
});
expect(screen.getByTestId("user-name")).toHaveTextContent(
"Welcome, John Doe",
);
const logoutButton = screen.getByTestId("logout-button");
fireEvent.click(logoutButton);
expect(logoutCallbackCalled).toBe(true);
await waitFor(() => {
expect(screen.getByTestId("user-name")).toHaveTextContent(
"Welcome, Anonymous user",
);
});
unmount();
});
test("should reset nested co-state on logout", async () => {
const syncServer = await startSyncServer();
let logoutCallbackCalled = false;
render(
<JazzReactProvider
sync={{ peer: syncServer.url }}
storage="indexedDB"
AccountSchema={TestAccount}
defaultProfileName="Anonymous user"
>
<TestLogoutComponent
onLogout={() => {
logoutCallbackCalled = true;
}}
/>
</JazzReactProvider>,
);
await waitFor(() => {
expect(screen.getByTestId("root-value")).toBeInTheDocument();
});
expect(screen.getByTestId("root-value")).toHaveTextContent("0");
const incrementButton = screen.getByTestId("increment-button");
fireEvent.click(incrementButton);
expect(screen.getByTestId("root-value")).toHaveTextContent("1");
fireEvent.click(incrementButton);
expect(screen.getByTestId("root-value")).toHaveTextContent("2");
const logoutButton = screen.getByTestId("logout-button");
fireEvent.click(logoutButton);
expect(logoutCallbackCalled).toBe(true);
await waitFor(() => {
expect(screen.getByTestId("root-value")).toHaveTextContent("0");
});
});
});

View File

@@ -9,7 +9,8 @@
"sourceMap": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"outDir": "dist"
"outDir": "dist",
"jsx": "react-jsx"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]

View File

@@ -1,7 +1,9 @@
import react from "@vitejs/plugin-react-swc";
import { defineProject } from "vitest/config";
import { customCommands } from "./src/commands";
export default defineProject({
plugins: [react()],
test: {
name: "browser-integration-tests",
browser: {