Compare commits

..

23 Commits

Author SHA1 Message Date
Giordano Ricci
3f42a4ddf9 add test 2025-02-19 15:25:02 +00:00
Giordano Ricci
0eed228170 add changeset 2025-02-19 14:32:48 +00:00
Giordano Ricci
a519537701 remove unused import 2025-02-19 13:52:14 +00:00
Giordano Ricci
43c79cac2a add simple test 2025-02-19 13:46:37 +00:00
Giordano Ricci
44dbaa00d4 revert wrong change 2025-02-19 12:12:01 +00:00
Giordano Ricci
a0df32e81a add types test 2025-02-19 12:08:42 +00:00
Giordano Ricci
236d8226d8 remove prevContext promise 2025-02-19 10:39:32 +00:00
Giordano Ricci
1220fa5d97 remove reset 2025-02-19 10:37:33 +00:00
Giordano Ricci
5cc58c8e02 whoopsie 2025-02-18 22:40:01 +00:00
Giordano Ricci
9df644c578 fix 2025-02-18 22:35:35 +00:00
Giordano Ricci
6854f9930c wip: fix clerk auth flow 2025-02-18 16:47:49 +00:00
Guido D'Orsi
65f630fb44 Merge pull request #1367 from garden-co/changeset-release/main
Version Packages
2025-02-12 20:26:56 +01:00
github-actions[bot]
b68f85542b Version Packages 2025-02-12 18:32:59 +00:00
Guido D'Orsi
f122a9f938 Merge pull request #1366 from garden-co/fix-metro-config
fix: correctly setup the metro config on React Native templates
2025-02-12 19:31:50 +01:00
Guido D'Orsi
48ac92bc67 fix: correctly setup the metro config on React Native templates 2025-02-12 19:22:23 +01:00
Trisha Lim
d3603625fd Fix copy password button 2025-02-12 19:43:20 +07:00
Trisha Lim
fa94d8c171 Show button on mobile 2025-02-12 19:43:20 +07:00
Trisha Lim
aeb094baa1 Add "use as template" button to examples 2025-02-12 19:43:20 +07:00
Guido D'Orsi
18f3497397 Merge pull request #1361 from garden-co/changeset-release/main
Version Packages
2025-02-12 12:55:19 +01:00
github-actions[bot]
8be7158d1f Version Packages 2025-02-12 11:52:07 +00:00
Guido D'Orsi
cae3a9ee32 feat: add debug info to load failure end missing header errors 2025-02-12 12:50:29 +01:00
Guido D'Orsi
6260045140 docs: small improvement on the upgrade guide 2025-02-12 11:57:00 +01:00
Guido D'Orsi
466d79d9a6 docs: fix missing enclosing div 2025-02-12 11:47:46 +01:00
112 changed files with 959 additions and 182 deletions

View File

@@ -0,0 +1,9 @@
---
"jazz-react-auth-clerk": patch
"jazz-auth-clerk": patch
"jazz-browser": patch
"jazz-react": patch
"jazz-tools": patch
---
Fixes clerk auth flow

View File

@@ -1,5 +1,14 @@
# chat-rn-clerk # chat-rn-clerk
## 1.0.67
### Patch Changes
- jazz-react-native@0.10.2
- jazz-react-native-auth-clerk@0.10.2
- jazz-tools@0.10.2
- jazz-react-native-media-images@0.10.2
## 1.0.66 ## 1.0.66
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# chat-rn # chat-rn
## 1.0.64
### Patch Changes
- jazz-react-native@0.10.2
- jazz-tools@0.10.2
## 1.0.63 ## 1.0.63
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# chat-vue # chat-vue
## 0.0.51
### Patch Changes
- jazz-browser@0.10.2
- jazz-tools@0.10.2
- jazz-vue@0.10.2
## 0.0.50 ## 0.0.50
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# jazz-example-chat # jazz-example-chat
## 0.0.147
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.146 ## 0.0.146
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# minimal-auth-clerk # minimal-auth-clerk
## 0.0.46
### Patch Changes
- jazz-react@0.10.2
- jazz-react-auth-clerk@0.10.2
- jazz-tools@0.10.2
## 0.0.45 ## 0.0.45
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "clerk", "name": "clerk",
"private": true, "private": true,
"version": "0.0.45", "version": "0.0.46",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -13,7 +13,7 @@
"dependencies": { "dependencies": {
"@clerk/clerk-react": "^5.4.1", "@clerk/clerk-react": "^5.4.1",
"jazz-react": "workspace:*", "jazz-react": "workspace:*",
"jazz-react-auth-clerk": "workspace:0.10.1", "jazz-react-auth-clerk": "workspace:0.10.2",
"jazz-tools": "workspace:*", "jazz-tools": "workspace:*",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1" "react-dom": "^18.3.1"

View File

@@ -1,5 +1,12 @@
# file-share-svelte # file-share-svelte
## 0.0.31
### Patch Changes
- jazz-svelte@0.10.2
- jazz-tools@0.10.2
## 0.0.30 ## 0.0.30
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# form # form
## 0.0.42
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.41 ## 0.0.41
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# image-upload # image-upload
## 0.0.44
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.43 ## 0.0.43
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# jazz-example-inspector # jazz-example-inspector
## 0.0.105
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- cojson-transport-ws@0.10.2
## 0.0.104 ## 0.0.104
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "jazz-inspector-app", "name": "jazz-inspector-app",
"private": true, "private": true,
"version": "0.0.104", "version": "0.0.105",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -16,8 +16,8 @@
"@radix-ui/react-toast": "^1.1.4", "@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"cojson": "workspace:0.10.1", "cojson": "workspace:0.10.2",
"cojson-transport-ws": "workspace:0.10.1", "cojson-transport-ws": "workspace:0.10.2",
"hash-slash": "workspace:0.2.1", "hash-slash": "workspace:0.2.1",
"lucide-react": "^0.274.0", "lucide-react": "^0.274.0",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",

View File

@@ -1,5 +1,13 @@
# jazz-example-musicplayer # jazz-example-musicplayer
## 0.0.68
### Patch Changes
- jazz-inspector@0.10.2
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.67 ## 0.0.67
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "jazz-example-music-player", "name": "jazz-example-music-player",
"private": true, "private": true,
"version": "0.0.67", "version": "0.0.68",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -22,8 +22,8 @@
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"jazz-inspector": "workspace:*", "jazz-inspector": "workspace:*",
"jazz-react": "workspace:0.10.1", "jazz-react": "workspace:0.10.2",
"jazz-tools": "workspace:0.10.1", "jazz-tools": "workspace:0.10.2",
"lucide-react": "^0.274.0", "lucide-react": "^0.274.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",

View File

@@ -1,5 +1,13 @@
# jazz-example-onboarding # jazz-example-onboarding
## 0.0.48
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.47 ## 0.0.47
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "jazz-example-onboarding", "name": "jazz-example-onboarding",
"private": true, "private": true,
"version": "0.0.47", "version": "0.0.48",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1,5 +1,12 @@
# organization # organization
## 0.0.40
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.39 ## 0.0.39
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# passkey-svelte # passkey-svelte
## 0.0.35
### Patch Changes
- jazz-svelte@0.10.2
## 0.0.34 ## 0.0.34
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# minimal-auth-passkey # minimal-auth-passkey
## 0.0.45
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.44 ## 0.0.44
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# passphrase # passphrase
## 0.0.42
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.41 ## 0.0.41
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# jazz-password-manager # jazz-password-manager
## 0.0.66
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.65 ## 0.0.65
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "jazz-password-manager", "name": "jazz-password-manager",
"private": true, "private": true,
"version": "0.0.65", "version": "0.0.66",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -12,8 +12,8 @@
"clean-install": "rm -rf node_modules pnpm-lock.yaml && pnpm install" "clean-install": "rm -rf node_modules pnpm-lock.yaml && pnpm install"
}, },
"dependencies": { "dependencies": {
"jazz-react": "workspace:0.10.1", "jazz-react": "workspace:0.10.2",
"jazz-tools": "workspace:0.10.1", "jazz-tools": "workspace:0.10.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.41.5", "react-hook-form": "^7.41.5",

View File

@@ -1,5 +1,13 @@
# jazz-example-pets # jazz-example-pets
## 0.0.164
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.163 ## 0.0.163
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "jazz-example-pets", "name": "jazz-example-pets",
"private": true, "private": true,
"version": "0.0.163", "version": "0.0.164",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -19,9 +19,9 @@
"@radix-ui/react-toast": "^1.1.4", "@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"jazz-browser-media-images": "workspace:0.10.1", "jazz-browser-media-images": "workspace:0.10.2",
"jazz-react": "workspace:0.10.1", "jazz-react": "workspace:0.10.2",
"jazz-tools": "workspace:0.10.1", "jazz-tools": "workspace:0.10.2",
"lucide-react": "^0.274.0", "lucide-react": "^0.274.0",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"react": "^18.3.1", "react": "^18.3.1",
@@ -41,7 +41,7 @@
"@vitejs/plugin-react-swc": "^3.3.2", "@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"is-ci": "^3.0.1", "is-ci": "^3.0.1",
"jazz-run": "workspace:0.10.1", "jazz-run": "workspace:0.10.2",
"postcss": "^8.4.27", "postcss": "^8.4.27",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"typescript": "~5.6.2", "typescript": "~5.6.2",

View File

@@ -1,5 +1,13 @@
# reactions # reactions
## 0.0.44
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.43 ## 0.0.43
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# todo-vue # todo-vue
## 0.0.49
### Patch Changes
- jazz-browser@0.10.2
- jazz-tools@0.10.2
- jazz-vue@0.10.2
## 0.0.48 ## 0.0.48
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# jazz-example-todo # jazz-example-todo
## 0.0.163
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.162 ## 0.0.162
### Patch Changes ### Patch Changes

View File

@@ -1,7 +1,7 @@
{ {
"name": "jazz-example-todo", "name": "jazz-example-todo",
"private": true, "private": true,
"version": "0.0.162", "version": "0.0.163",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -16,8 +16,8 @@
"@radix-ui/react-toast": "^1.1.4", "@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"jazz-react": "workspace:0.10.1", "jazz-react": "workspace:0.10.2",
"jazz-tools": "workspace:0.10.1", "jazz-tools": "workspace:0.10.2",
"lucide-react": "^0.274.0", "lucide-react": "^0.274.0",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"react": "^18.3.1", "react": "^18.3.1",

View File

@@ -1,5 +1,12 @@
# version-history # version-history
## 0.0.41
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.40 ## 0.0.40
### Patch Changes ### Patch Changes

View File

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

View File

@@ -77,6 +77,7 @@ const icons = {
// copied from tailwind line height https://tailwindcss.com/docs/font-size // copied from tailwind line height https://tailwindcss.com/docs/font-size
const sizes = { const sizes = {
"2xs": 14,
xs: 16, xs: 16,
sm: 20, sm: 20,
md: 24, md: 24,
@@ -93,6 +94,7 @@ const sizes = {
}; };
const strokeWidths = { const strokeWidths = {
"2xs": 2.5,
xs: 2, xs: 2,
sm: 2, sm: 2,
md: 1.5, md: 1.5,

View File

@@ -1,18 +1,18 @@
"use client"; "use client";
import { clsx } from "clsx"; import { clsx } from "clsx";
import { useEffect, useRef, useState } from "react"; import { useEffect, useId, useRef, useState } from "react";
import { Icon } from "../atoms/Icon"; import { Icon } from "../atoms/Icon";
// TODO: add tabs feature, and remove CodeExampleTabs // TODO: add tabs feature, and remove CodeExampleTabs
function CopyButton({ code, size }: { code: string; size: "md" | "lg" }) { function CopyButton({ code, size }: { code: string; size: "md" | "lg" }) {
let [copyCount, setCopyCount] = useState(0); const [copyCount, setCopyCount] = useState(0);
let copied = copyCount > 0; const copied = copyCount > 0;
useEffect(() => { useEffect(() => {
if (copyCount > 0) { if (copyCount > 0) {
let timeout = setTimeout(() => setCopyCount(0), 1000); const timeout = setTimeout(() => setCopyCount(0), 1000);
return () => { return () => {
clearTimeout(timeout); clearTimeout(timeout);
}; };
@@ -23,7 +23,8 @@ function CopyButton({ code, size }: { code: string; size: "md" | "lg" }) {
<button <button
type="button" type="button"
className={clsx( className={clsx(
"group/button absolute overflow-hidden rounded text-2xs font-medium opacity-0 backdrop-blur transition focus:opacity-100 group-hover:opacity-100", "group/button absolute overflow-hidden rounded text-2xs font-medium md:opacity-0 backdrop-blur transition md:focus:opacity-100 group-hover:opacity-100",
"right-[9px] top-[9px]",
copied copied
? "bg-emerald-400/10 ring-1 ring-inset ring-emerald-400/20" ? "bg-emerald-400/10 ring-1 ring-inset ring-emerald-400/20"
: "bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5", : "bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5",
@@ -72,13 +73,13 @@ export function CodeGroup({
size = "md", size = "md",
className, className,
}: { }: {
children: React.ReactNode; children?: React.ReactNode;
text?: string;
size?: "md" | "lg"; size?: "md" | "lg";
className?: string; className?: string;
}) { }) {
const textRef = useRef<HTMLPreElement | null>(null); const textRef = useRef<HTMLPreElement | null>(null);
const [code, setCode] = useState<string>(); const [code, setCode] = useState<string>();
useEffect(() => { useEffect(() => {
if (textRef.current) { if (textRef.current) {
setCode(textRef.current.innerText); setCode(textRef.current.innerText);

View File

@@ -0,0 +1,108 @@
import * as Headless from "@headlessui/react";
import clsx from "clsx";
import type React from "react";
const sizes = {
xs: "sm:max-w-xs",
sm: "sm:max-w-sm",
md: "sm:max-w-md",
lg: "sm:max-w-lg",
xl: "sm:max-w-xl",
"2xl": "sm:max-w-2xl",
"3xl": "sm:max-w-3xl",
"4xl": "sm:max-w-4xl",
"5xl": "sm:max-w-5xl",
};
export type DialogProps = {
size?: keyof typeof sizes;
className?: string;
children: React.ReactNode;
} & Omit<Headless.DialogProps, "as" | "className">;
export function Dialog({
size = "lg",
className,
children,
...props
}: DialogProps) {
return (
<Headless.Dialog {...props}>
<Headless.DialogBackdrop
transition
className="z-50 fixed inset-0 flex w-screen justify-center overflow-y-auto bg-stone-950/25 px-2 py-2 transition duration-100 focus:outline-0 data-[closed]:opacity-0 data-[enter]:ease-out data-[leave]:ease-in sm:px-6 sm:py-8 lg:px-8 lg:py-16 dark:bg-stone-950/70"
/>
<div className="z-50 fixed inset-0 w-screen overflow-y-auto pt-6 sm:pt-0">
<div className="grid min-h-full grid-rows-[1fr_auto] justify-items-center sm:grid-rows-[1fr_auto_3fr] sm:p-4">
<Headless.DialogPanel
transition
className={clsx(
className,
sizes[size],
"row-start-2 w-full min-w-0 rounded-t-3xl bg-white p-[--gutter] shadow-lg ring-1 ring-stone-950/10 [--gutter:theme(spacing.8)] sm:mb-auto sm:rounded-2xl dark:bg-stone-950 dark:ring-white/10 forced-colors:outline",
"transition duration-100 will-change-transform data-[closed]:translate-y-12 data-[closed]:opacity-0 data-[enter]:ease-out data-[leave]:ease-in sm:data-[closed]:translate-y-0 sm:data-[closed]:data-[enter]:scale-95",
)}
>
{children}
</Headless.DialogPanel>
</div>
</div>
</Headless.Dialog>
);
}
export function DialogTitle({
className,
...props
}: { className?: string } & Omit<
Headless.DialogTitleProps,
"as" | "className"
>) {
return (
<Headless.DialogTitle
{...props}
className={clsx(
className,
"text-balance text-lg/6 font-semibold text-stone-900 dark:text-white",
)}
/>
);
}
export function DialogDescription({
className,
...props
}: { className?: string } & Omit<
Headless.DescriptionProps,
"as" | "className"
>) {
return (
<Headless.Description
{...props}
className={clsx(className, "mt-2 text-pretty")}
/>
);
}
export function DialogBody({
className,
...props
}: React.ComponentPropsWithoutRef<"div">) {
return <div {...props} className={clsx(className, "mt-6")} />;
}
export function DialogActions({
className,
...props
}: React.ComponentPropsWithoutRef<"div">) {
return (
<div
{...props}
className={clsx(
className,
"mt-8 flex flex-col-reverse items-center justify-end gap-3 *:w-full sm:flex-row sm:*:w-auto",
)}
/>
);
}

View File

@@ -24,7 +24,8 @@ export const metadata = { title: "Jazz 0.10.0 is out!" };
- [Group inheritance with role mapping](/docs/upgrade/0-10-0#group-inheritance): Groups can now inherit members from other groups with a fixed role. - [Group inheritance with role mapping](/docs/upgrade/0-10-0#group-inheritance): Groups can now inherit members from other groups with a fixed role.
- Support for Node 14 dropped on cojson. - Support for Node 14 dropped on cojson.
- Bugfix: `Group.removeMember` now returns a promise. - Bugfix: `Group.removeMember` now returns a promise.
- Now cojson and jazz-tools don't export directly the crypto providers anymore. Replace the import with `cojson/crypto/WasmCrypto` or `cojson/crypto/PureJSCrypto` depending on your use case. - Now `cojson` and `jazz-tools` don't export directly the crypto providers anymore. Replace the import with `cojson/crypto/WasmCrypto` or `cojson/crypto/PureJSCrypto` depending on your use case.
</div>
<h3 id="new-authentication-flow">New authentication flow</h3> <h3 id="new-authentication-flow">New authentication flow</h3>
<div> <div>

View File

@@ -283,27 +283,31 @@ const PasswordManagerIllustration = () => (
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr className="border-b"> {[
<td className="p-2">user@gmail.com</td> {
<td className="p-2">gmail.com</td> email: "user@gmail.com",
<td className="p-2"> domain: "gmail.com",
<MockButton>Copy password</MockButton> },
</td> {
</tr> email: "user@gmail.com",
<tr className="border-b"> domain: "fb.com",
<td className="p-2">user@gmail.com</td> },
<td className="p-2">fb.com</td> {
<td className="p-2"> email: "user@gmail.com",
<MockButton>Copy password</MockButton> domain: "x.com",
</td> },
</tr> ].map(({ email, domain }) => (
<tr className="border-b"> <tr className="border-b max-sm:last:hidden" key={domain}>
<td className="p-2">user@gmail.com</td> <td className="p-2">{email}</td>
<td className="p-2">x.com</td> <td className="p-2">{domain}</td>
<td className="p-2"> <td className="p-2">
<MockButton>Copy password</MockButton> <MockButton>
</td> <Icon name="copy" size="2xs" className="mr-1" />
</tr> Password
</MockButton>
</td>
</tr>
))}
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@@ -0,0 +1,3 @@
```sh
npx create-jazz-app@latest --example $EXAMPLE
```

View File

@@ -1,21 +1,66 @@
"use client";
import { Example } from "@/lib/example"; import { Example } from "@/lib/example";
import { InterpolateInCode } from "@/mdx-components";
import { DialogDescription } from "@headlessui/react";
import { Button } from "gcmp-design-system/src/app/components/atoms/Button"; import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
import { CodeGroup } from "gcmp-design-system/src/app/components/molecules/CodeGroup";
import {
Dialog,
DialogActions,
DialogBody,
DialogTitle,
} from "gcmp-design-system/src/app/components/organisms/Dialog";
import { useState } from "react";
import CreateJazzApp from "./CreateJazzApp.mdx";
export function ExampleLinks({ example }: { example: Example }) { export function ExampleLinks({ example }: { example: Example }) {
const { slug, demoUrl } = example; const { slug, demoUrl } = example;
const githubUrl = `https://github.com/gardencmp/jazz/tree/main/examples/${slug}`; const githubUrl = `https://github.com/gardencmp/jazz/tree/main/examples/${slug}`;
const [isOpen, setIsOpen] = useState(false);
return ( return (
<div className="flex gap-2"> <>
<Button href={githubUrl} newTab variant="secondary" size="sm"> <div className="flex gap-2">
View code <Button variant="secondary" size="sm" onClick={() => setIsOpen(true)}>
</Button> Use as template
{demoUrl && (
<Button href={demoUrl} newTab variant="secondary" size="sm">
View demo
</Button> </Button>
)} <Button href={githubUrl} newTab variant="secondary" size="sm">
</div> <span className="md:hidden">Code</span>
<span className="hidden md:inline">View code</span>
</Button>
{demoUrl && (
<Button href={demoUrl} newTab variant="secondary" size="sm">
<span className="md:hidden">Demo</span>
<span className="hidden md:inline">View demo</span>
</Button>
)}
</div>
<Dialog onClose={() => setIsOpen(false)} open={isOpen}>
<DialogTitle>Use {example.name} example as a template</DialogTitle>
<DialogBody>
<div className="mb-6 aspect-[16/9] overflow-hidden w-full rounded-md bg-white border dark:bg-stone-925 sm:aspect-[2/1] md:aspect-[3/2]">
{example.illustration}
</div>
<p className="mb-3">
Generate a new Jazz app by running the command below.
</p>
<CodeGroup>
<CreateJazzApp
components={InterpolateInCode({
$EXAMPLE: example.slug,
})}
/>
</CodeGroup>
</DialogBody>
<DialogActions>
<Button onClick={() => setIsOpen(false)} variant="secondary">
Cancel
</Button>
</DialogActions>
</Dialog>
</>
); );
} }

View File

@@ -1,9 +1,31 @@
import { DocsLink } from "@/components/docs/DocsLink";
import type { MDXComponents } from "mdx/types"; import type { MDXComponents } from "mdx/types";
export function useMDXComponents(components: MDXComponents): MDXComponents { export function useMDXComponents(components: MDXComponents): MDXComponents {
return { return {
a: (props) => <DocsLink {...props} />,
...components, ...components,
CodeWithInterpolation: ({
highlightedCode,
}: { highlightedCode: string }) => {
return <div dangerouslySetInnerHTML={{ __html: highlightedCode }} />;
},
};
}
export function InterpolateInCode(replace: { [key: string]: string }) {
return {
CodeWithInterpolation: ({
highlightedCode,
}: { highlightedCode: string }) => {
const newHighlightedCode = Object.entries(replace).reduce(
(acc, [key, value]) => {
return acc.replaceAll(
key.replaceAll("$", "&#36;").replaceAll("_", "&#95;"),
value,
);
},
highlightedCode,
);
return <div dangerouslySetInnerHTML={{ __html: newHighlightedCode }} />;
},
}; };
} }

View File

@@ -38,7 +38,7 @@ function highlightPlugin() {
return async function transformer(tree) { return async function transformer(tree) {
const highlighter = await getHighlighter({ const highlighter = await getHighlighter({
langs: ["typescript", "bash", "tsx", "json", "svelte"], langs: ["typescript", "bash", "tsx", "json", "svelte"],
theme: "css-variables", // use the theme theme: "css-variables", // use css variables in shiki.css
}); });
visit(tree, "code", visitor); visit(tree, "code", visitor);
@@ -116,7 +116,7 @@ function remarkHtmlToJsx() {
const [ast] = args; const [ast] = args;
visit(ast, "html", (node) => { visit(ast, "html", (node) => {
const escapedHtml = JSON.stringify(node.value); const escapedHtml = JSON.stringify(node.value);
const jsx = `<div dangerouslySetInnerHTML={{__html: ${escapedHtml} }}/>`; const jsx = `<CodeWithInterpolation highlightedCode={${escapedHtml}}/>`;
const rawHtmlNode = fromMarkdown(jsx, { const rawHtmlNode = fromMarkdown(jsx, {
extensions: [mdxjs()], extensions: [mdxjs()],
mdastExtensions: [mdxFromMarkdown()], mdastExtensions: [mdxFromMarkdown()],

View File

@@ -1,5 +1,13 @@
# cojson-storage-indexeddb # cojson-storage-indexeddb
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- cojson-storage@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# cojson-storage-sqlite # cojson-storage-sqlite
## 0.8.62
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- cojson-storage@0.10.2
## 0.8.61 ## 0.8.61
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# cojson-storage-sqlite # cojson-storage-sqlite
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- cojson-storage@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# cojson-storage # cojson-storage
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,12 @@
# cojson-transport-nodejs-ws # cojson-transport-nodejs-ws
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# cojson # cojson
## 0.10.2
### Patch Changes
- cae3a9e: Add debug info to load failure end missing header errors
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

@@ -25,7 +25,7 @@
}, },
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"version": "0.10.1", "version": "0.10.2",
"devDependencies": { "devDependencies": {
"@opentelemetry/sdk-metrics": "^1.29.0", "@opentelemetry/sdk-metrics": "^1.29.0",
"typescript": "~5.6.2", "typescript": "~5.6.2",

View File

@@ -307,6 +307,7 @@ async function loadCoValueFromPeers(
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
if (coValueEntry.state.type === "loading") { if (coValueEntry.state.type === "loading") {
logger.warn("Failed to load coValue from peer", { logger.warn("Failed to load coValue from peer", {
coValueId: coValueEntry.id,
peerId: peer.id, peerId: peer.id,
peerRole: peer.role, peerRole: peer.role,
}); });

View File

@@ -531,7 +531,11 @@ export class SyncManager {
if (entry.state.type !== "available") { if (entry.state.type !== "available") {
if (!msg.header) { if (!msg.header) {
logger.error("Expected header to be sent in first message"); logger.error("Expected header to be sent in first message", {
coValueId: msg.id,
peerId: peer.id,
peerRole: peer.role,
});
return; return;
} }

View File

@@ -1,5 +1,11 @@
# create-jazz-app # create-jazz-app
## 0.1.10
### Patch Changes
- 48ac92b: Correctly setup the metro config on React Native templates
## 0.1.9 ## 0.1.9
### Patch Changes ### Patch Changes

View File

@@ -5,7 +5,7 @@
"types": "src/index.ts", "types": "src/index.ts",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"version": "0.1.9", "version": "0.1.10",
"bin": { "bin": {
"create-jazz-app": "./dist/index.js" "create-jazz-app": "./dist/index.js"
}, },

View File

@@ -67,35 +67,53 @@ export const configMap: ConfigStructure = {
}, },
}; };
export const PLATFORM = {
WEB: "web",
REACT_NATIVE: "react-native",
} as const;
export type FrameworkAuthPair = export type FrameworkAuthPair =
`${ValidFramework<Environment, ValidEngine<Environment>>}-${ValidAuth<Environment, ValidEngine<Environment>, ValidFramework<Environment, ValidEngine<Environment>>>}-auth`; `${ValidFramework<Environment, ValidEngine<Environment>>}-${ValidAuth<Environment, ValidEngine<Environment>, ValidFramework<Environment, ValidEngine<Environment>>>}-auth`;
export const frameworkToAuthExamples: Partial< export const frameworkToAuthExamples: Partial<
Record<FrameworkAuthPair, { name: string; repo: string | undefined }> Record<
FrameworkAuthPair,
{
name: string;
repo: string | undefined;
platform: (typeof PLATFORM)[keyof typeof PLATFORM];
}
>
> = { > = {
"react-demo-auth": { "react-demo-auth": {
name: "React + Jazz + Demo Auth + Tailwind", name: "React + Jazz + Demo Auth + Tailwind",
repo: "garden-co/jazz/starters/react-demo-auth-tailwind", repo: "garden-co/jazz/starters/react-demo-auth-tailwind",
platform: PLATFORM.WEB,
}, },
"react-passkey-auth": { "react-passkey-auth": {
name: "React + Jazz + Passkey Auth", name: "React + Jazz + Passkey Auth",
repo: "garden-co/jazz/examples/passkey", repo: "garden-co/jazz/examples/passkey",
platform: PLATFORM.WEB,
}, },
"react-clerk-auth": { "react-clerk-auth": {
name: "React + Jazz + Clerk Auth", name: "React + Jazz + Clerk Auth",
repo: "garden-co/jazz/examples/clerk", repo: "garden-co/jazz/examples/clerk",
platform: PLATFORM.WEB,
}, },
"vue-demo-auth": { "vue-demo-auth": {
name: "Vue + Jazz + Demo Auth", name: "Vue + Jazz + Demo Auth",
repo: "garden-co/jazz/examples/todo-vue", repo: "garden-co/jazz/examples/todo-vue",
platform: PLATFORM.WEB,
}, },
"svelte-passkey-auth": { "svelte-passkey-auth": {
name: "Svelte + Jazz + Passkey Auth", name: "Svelte + Jazz + Passkey Auth",
repo: "garden-co/jazz/examples/passkey-svelte", repo: "garden-co/jazz/examples/passkey-svelte",
platform: PLATFORM.WEB,
}, },
"rn-clerk-auth": { "rn-clerk-auth": {
name: "React Native Expo + Jazz + Clerk Auth", name: "React Native Expo + Jazz + Clerk Auth",
repo: "garden-co/jazz/examples/chat-rn-clerk", repo: "garden-co/jazz/examples/chat-rn-clerk",
platform: PLATFORM.REACT_NATIVE,
}, },
}; };

View File

@@ -12,6 +12,7 @@ import ora from "ora";
import { import {
Framework, Framework,
type FrameworkAuthPair, type FrameworkAuthPair,
PLATFORM,
frameworkToAuthExamples, frameworkToAuthExamples,
frameworks, frameworks,
} from "./config.js"; } from "./config.js";
@@ -82,6 +83,10 @@ async function getLatestPackageVersions(
return versions; return versions;
} }
function getPlatformFromTemplateName(template: string) {
return template.includes("-rn") ? PLATFORM.REACT_NATIVE : PLATFORM.WEB;
}
async function scaffoldProject({ async function scaffoldProject({
template, template,
projectName, projectName,
@@ -92,12 +97,14 @@ async function scaffoldProject({
const starterConfig = frameworkToAuthExamples[ const starterConfig = frameworkToAuthExamples[
template as FrameworkAuthPair template as FrameworkAuthPair
] || { name: template, repo: "garden-co/jazz/examples/" + template }; ] || {
if (!starterConfig) { name: template,
throw new Error(`Invalid template: ${template}`); repo: "garden-co/jazz/examples/" + template,
} platform: getPlatformFromTemplateName(template),
};
const devCommand = template.includes("rn-clerk") ? "ios" : "dev"; const devCommand =
starterConfig.platform === PLATFORM.REACT_NATIVE ? "ios" : "dev";
if (!starterConfig.repo) { if (!starterConfig.repo) {
throw new Error( throw new Error(
@@ -207,7 +214,7 @@ async function scaffoldProject({
} }
// Additional setup for React Native // Additional setup for React Native
if (template === "react-native-expo-clerk-auth") { if (starterConfig.platform === PLATFORM.REACT_NATIVE) {
const rnSpinner = ora({ const rnSpinner = ora({
text: chalk.blue("Setting up React Native project..."), text: chalk.blue("Setting up React Native project..."),
spinner: "dots", spinner: "dots",

View File

@@ -1,5 +1,14 @@
# jazz-browser-media-images # jazz-browser-media-images
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- jazz-browser@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,21 +1,18 @@
import { AgentSecret } from "cojson";
import { AuthSecretStorage } from "jazz-tools";
import { import {
Account, Account,
AuthCredentials, AuthCredentials,
AuthSecretStorage,
AuthenticateAccountFunction, AuthenticateAccountFunction,
ID,
} from "jazz-tools"; } from "jazz-tools";
import { getClerkUsername } from "./getClerkUsername.js"; import { getClerkUsername } from "./getClerkUsername.js";
import { MinimalClerkClient } from "./types.js"; import {
ClerkCredentials,
type ClerkCredentials = { MinimalClerkClient,
jazzAccountID: ID<Account>; isClerkCredentials,
jazzAccountSecret: AgentSecret; } from "./types.js";
jazzAccountSeed?: number[];
};
export type { MinimalClerkClient }; export type { MinimalClerkClient };
export { isClerkCredentials };
export class JazzClerkAuth { export class JazzClerkAuth {
constructor( constructor(
@@ -23,8 +20,27 @@ export class JazzClerkAuth {
private authSecretStorage: AuthSecretStorage, private authSecretStorage: AuthSecretStorage,
) {} ) {}
/**
* Loads the Jazz auth data from the Clerk user and sets it in the auth secret storage.
*/
static loadClerkAuthData(
credentials: ClerkCredentials,
storage: AuthSecretStorage,
) {
return storage.set({
accountID: credentials.jazzAccountID,
accountSecret: credentials.jazzAccountSecret,
secretSeed: credentials.jazzAccountSeed
? Uint8Array.from(credentials.jazzAccountSeed)
: undefined,
provider: "clerk",
});
}
onClerkUserChange = async (clerkClient: Pick<MinimalClerkClient, "user">) => { onClerkUserChange = async (clerkClient: Pick<MinimalClerkClient, "user">) => {
if (!clerkClient.user) return; if (!clerkClient.user) {
return;
}
const isAuthenticated = this.authSecretStorage.isAuthenticated; const isAuthenticated = this.authSecretStorage.isAuthenticated;
@@ -45,13 +61,8 @@ export class JazzClerkAuth {
throw new Error("Not signed in on Clerk"); throw new Error("Not signed in on Clerk");
} }
const clerkCredentials = clerkClient.user const clerkCredentials = clerkClient.user.unsafeMetadata;
.unsafeMetadata as ClerkCredentials; if (!isClerkCredentials(clerkCredentials)) {
if (
!clerkCredentials.jazzAccountID ||
!clerkCredentials.jazzAccountSecret
) {
throw new Error("No credentials found on Clerk"); throw new Error("No credentials found on Clerk");
} }
@@ -66,7 +77,14 @@ export class JazzClerkAuth {
await this.authenticate(credentials); await this.authenticate(credentials);
await this.authSecretStorage.set(credentials); await JazzClerkAuth.loadClerkAuthData(
{
jazzAccountID: credentials.accountID,
jazzAccountSecret: credentials.accountSecret,
jazzAccountSeed: clerkCredentials.jazzAccountSeed,
},
this.authSecretStorage,
);
}; };
signIn = async (clerkClient: Pick<MinimalClerkClient, "user">) => { signIn = async (clerkClient: Pick<MinimalClerkClient, "user">) => {
@@ -76,13 +94,15 @@ export class JazzClerkAuth {
throw new Error("No credentials found"); throw new Error("No credentials found");
} }
const jazzAccountSeed = credentials.secretSeed
? Array.from(credentials.secretSeed)
: undefined;
await clerkClient.user?.update({ await clerkClient.user?.update({
unsafeMetadata: { unsafeMetadata: {
jazzAccountID: credentials.accountID, jazzAccountID: credentials.accountID,
jazzAccountSecret: credentials.accountSecret, jazzAccountSecret: credentials.accountSecret,
jazzAccountSeed: credentials.secretSeed jazzAccountSeed,
? Array.from(credentials.secretSeed)
: undefined,
} satisfies ClerkCredentials, } satisfies ClerkCredentials,
}); });
@@ -96,12 +116,14 @@ export class JazzClerkAuth {
currentAccount.profile.name = username; currentAccount.profile.name = username;
} }
await this.authSecretStorage.set({ await JazzClerkAuth.loadClerkAuthData(
accountID: credentials.accountID, {
accountSecret: credentials.accountSecret, jazzAccountID: credentials.accountID,
secretSeed: credentials.secretSeed, jazzAccountSecret: credentials.accountSecret,
provider: "clerk", jazzAccountSeed,
}); },
this.authSecretStorage,
);
}; };
} }

View File

@@ -0,0 +1,49 @@
import { describe, expect, it } from "vitest";
import { isClerkCredentials } from "../types";
describe("isClerkCredentials", () => {
it.each([
{
metadata: {
jazzAccountID: "123",
jazzAccountSecret: "456",
jazzAccountSeed: [1, 2, 3],
},
description: "full credentials",
},
{
metadata: {
jazzAccountID: "123",
jazzAccountSecret: "456",
},
description: "missing jazzAccountSeed",
},
])("succeeds for valid credentials: $description", ({ metadata }) => {
expect(isClerkCredentials(metadata)).toBe(true);
});
it.each([
{
metadata: {},
description: "empty object",
},
{
metadata: undefined,
description: "undefined",
},
{
metadata: {
jazzAccountSecret: "456",
},
description: "missing jazzAccountID",
},
{
metadata: {
jazzAccountID: "123",
},
description: "missing jazzAccountSecret",
},
])("fails for invalid credentials: $description", ({ metadata }) => {
expect(isClerkCredentials(metadata)).toBe(false);
});
});

View File

@@ -1,3 +1,6 @@
import { AgentSecret } from "cojson";
import { Account, ID } from "jazz-tools";
export type MinimalClerkClient = { export type MinimalClerkClient = {
user: user:
| { | {
@@ -21,3 +24,19 @@ export type MinimalClerkClient = {
signOut: () => Promise<void>; signOut: () => Promise<void>;
addListener: (listener: (data: unknown) => void) => void; addListener: (listener: (data: unknown) => void) => void;
}; };
export type ClerkCredentials = {
jazzAccountID: ID<Account>;
jazzAccountSecret: AgentSecret;
jazzAccountSeed?: number[];
};
/**
* Checks if the Clerk user metadata contains the necessary credentials for Jazz auth.
* **Note**: It does not validate the credentials, only checks if the necessary fields are present in the metadata object.
*/
export function isClerkCredentials(
data: NonNullable<MinimalClerkClient["user"]>["unsafeMetadata"] | undefined,
): data is ClerkCredentials {
return !!data && "jazzAccountID" in data && "jazzAccountSecret" in data;
}

View File

@@ -1,5 +1,12 @@
# jazz-browser-media-images # jazz-browser-media-images
## 0.10.2
### Patch Changes
- jazz-browser@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,15 @@
# jazz-browser # jazz-browser
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- cojson-storage-indexeddb@0.10.2
- cojson-transport-ws@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

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

View File

@@ -26,6 +26,7 @@ export type JazzContextManagerProps<Acc extends Account> = {
export class JazzBrowserContextManager< export class JazzBrowserContextManager<
Acc extends Account, Acc extends Account,
> extends JazzContextManager<Acc, JazzContextManagerProps<Acc>> { > extends JazzContextManager<Acc, JazzContextManagerProps<Acc>> {
// TODO: When the storage changes, if the user is changed, update the context
getKvStore() { getKvStore() {
if (typeof window === "undefined") { if (typeof window === "undefined") {
// To handle running in SSR // To handle running in SSR

View File

@@ -15,6 +15,8 @@ setupInspector();
export * from "./createBrowserContext.js"; export * from "./createBrowserContext.js";
export * from "./BrowserContextManager.js"; export * from "./BrowserContextManager.js";
export { LocalStorageKVStore } from "./auth/LocalStorageKVStore.js";
/** @category Invite Links */ /** @category Invite Links */
export function createInviteLink<C extends CoValue>( export function createInviteLink<C extends CoValue>(
value: C, value: C,

View File

@@ -1,5 +1,14 @@
# jazz-inspector # jazz-inspector
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- jazz-react-core@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "jazz-inspector", "name": "jazz-inspector",
"version": "0.10.1", "version": "0.10.2",
"type": "module", "type": "module",
"main": "./dist/app.js", "main": "./dist/app.js",
"types": "./dist/app.d.ts", "types": "./dist/app.d.ts",

View File

@@ -1,5 +1,14 @@
# jazz-autosub # jazz-autosub
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- cojson-transport-ws@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,15 @@
# jazz-browser-media-images # jazz-browser-media-images
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- jazz-auth-clerk@0.10.2
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "jazz-react-auth-clerk", "name": "jazz-react-auth-clerk",
"version": "0.10.1", "version": "0.10.2",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"types": "src/index.tsx", "types": "src/index.tsx",
@@ -8,6 +8,7 @@
"dependencies": { "dependencies": {
"cojson": "workspace:*", "cojson": "workspace:*",
"jazz-auth-clerk": "workspace:*", "jazz-auth-clerk": "workspace:*",
"jazz-browser": "workspace:*",
"jazz-react": "workspace:*", "jazz-react": "workspace:*",
"jazz-tools": "workspace:*" "jazz-tools": "workspace:*"
}, },

View File

@@ -1,11 +1,17 @@
import { JazzClerkAuth, type MinimalClerkClient } from "jazz-auth-clerk"; import {
JazzClerkAuth,
type MinimalClerkClient,
isClerkCredentials,
} from "jazz-auth-clerk";
import { LocalStorageKVStore } from "jazz-browser";
import { import {
JazzProvider, JazzProvider,
JazzProviderProps, JazzProviderProps,
useAuthSecretStorage, useAuthSecretStorage,
useJazzContext, useJazzContext,
} from "jazz-react"; } from "jazz-react";
import { useEffect, useMemo } from "react"; import { AuthSecretStorage, InMemoryKVStore, KvStoreContext } from "jazz-tools";
import { useEffect, useMemo, useState } from "react";
function useJazzClerkAuth(clerk: MinimalClerkClient) { function useJazzClerkAuth(clerk: MinimalClerkClient) {
const context = useJazzContext(); const context = useJazzContext();
@@ -39,6 +45,28 @@ function RegisterClerkAuth(props: {
export const JazzProviderWithClerk = ( export const JazzProviderWithClerk = (
props: { clerk: MinimalClerkClient } & JazzProviderProps, props: { clerk: MinimalClerkClient } & JazzProviderProps,
) => { ) => {
const [isLoaded, setIsLoaded] = useState(false);
setupKvStore();
const secretStorage = new AuthSecretStorage();
useEffect(() => {
if (!isClerkCredentials(props.clerk.user?.unsafeMetadata)) {
setIsLoaded(true);
return;
}
JazzClerkAuth.loadClerkAuthData(
props.clerk.user.unsafeMetadata,
secretStorage,
).then(() => {
setIsLoaded(true);
});
}, []);
if (!isLoaded) {
return null;
}
return ( return (
<JazzProvider {...props} onLogOut={props.clerk.signOut}> <JazzProvider {...props} onLogOut={props.clerk.signOut}>
<RegisterClerkAuth clerk={props.clerk}> <RegisterClerkAuth clerk={props.clerk}>
@@ -47,3 +75,11 @@ export const JazzProviderWithClerk = (
</JazzProvider> </JazzProvider>
); );
}; };
function setupKvStore() {
KvStoreContext.getInstance().initialize(
typeof window === "undefined"
? new InMemoryKVStore()
: new LocalStorageKVStore(),
);
}

View File

@@ -1,9 +1,9 @@
// @vitest-environment happy-dom // @vitest-environment happy-dom
import { act, render, waitFor } from "@testing-library/react"; import { act, render, waitFor } from "@testing-library/react";
import type { MinimalClerkClient } from "jazz-auth-clerk"; import { JazzClerkAuth, type MinimalClerkClient } from "jazz-auth-clerk";
import { AuthSecretStorage, InMemoryKVStore, KvStoreContext } from "jazz-tools"; import { AuthSecretStorage, InMemoryKVStore, KvStoreContext } from "jazz-tools";
import { beforeEach, describe, expect, it, vi } from "vitest"; import { MockInstance, beforeEach, describe, expect, it, vi } from "vitest";
import { JazzProviderWithClerk } from "../index"; import { JazzProviderWithClerk } from "../index";
vi.mock("jazz-react", async (importOriginal) => { vi.mock("jazz-react", async (importOriginal) => {
@@ -27,12 +27,24 @@ vi.mock("jazz-react", async (importOriginal) => {
}; };
}); });
vi.mock("jazz-auth-clerk", async (importOriginal) => {
const { JazzClerkAuth } = await import("jazz-auth-clerk");
JazzClerkAuth.loadClerkAuthData = vi.fn().mockResolvedValue(undefined);
return {
...(await importOriginal<typeof import("jazz-auth-clerk")>()),
JazzClerkAuth,
};
});
const authSecretStorage = new AuthSecretStorage(); const authSecretStorage = new AuthSecretStorage();
KvStoreContext.getInstance().initialize(new InMemoryKVStore()); KvStoreContext.getInstance().initialize(new InMemoryKVStore());
describe("JazzProviderWithClerk", () => { describe("JazzProviderWithClerk", () => {
beforeEach(async () => { beforeEach(async () => {
await authSecretStorage.clear(); await authSecretStorage.clear();
vi.clearAllMocks();
}); });
const setup = ( const setup = (
@@ -94,4 +106,60 @@ describe("JazzProviderWithClerk", () => {
}, },
}); });
}); });
it("should load the clerk credentials when the user is authenticated", async () => {
render(
<JazzProviderWithClerk
clerk={{
addListener: vi.fn(),
signOut: vi.fn(),
user: {
update: vi.fn(),
unsafeMetadata: {
jazzAccountID: "test",
jazzAccountSecret: "test",
jazzAccountSeed: "test",
},
firstName: "Test",
lastName: "User",
username: "test",
fullName: "Test User",
id: "test",
primaryEmailAddress: {
emailAddress: "test@test.com",
},
},
}}
sync={{ peer: "wss://test.jazz.tools" }}
>
<div data-testid="test-child">Test Content</div>
</JazzProviderWithClerk>,
);
expect(JazzClerkAuth.loadClerkAuthData).toHaveBeenCalledWith(
{
jazzAccountID: "test",
jazzAccountSecret: "test",
jazzAccountSeed: "test",
},
authSecretStorage,
);
});
it("should not load the clerk credentials when the user is not authenticated", async () => {
render(
<JazzProviderWithClerk
clerk={{
addListener: vi.fn(),
signOut: vi.fn(),
user: null,
}}
sync={{ peer: "wss://test.jazz.tools" }}
>
<div data-testid="test-child">Test Content</div>
</JazzProviderWithClerk>,
);
expect(JazzClerkAuth.loadClerkAuthData).not.toHaveBeenCalledWith();
});
}); });

View File

@@ -1,5 +1,13 @@
# jazz-react-core # jazz-react-core
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "jazz-react-core", "name": "jazz-react-core",
"version": "0.10.1", "version": "0.10.2",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"types": "src/index.ts", "types": "src/index.ts",

View File

@@ -1,5 +1,15 @@
# jazz-react-native-auth-clerk # jazz-react-native-auth-clerk
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- jazz-auth-clerk@0.10.2
- jazz-react-native@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "jazz-react-native-auth-clerk", "name": "jazz-react-native-auth-clerk",
"version": "0.10.1", "version": "0.10.2",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"types": "src/index.tsx", "types": "src/index.tsx",

View File

@@ -1,5 +1,11 @@
# jazz-browser-media-images # jazz-browser-media-images
## 0.10.2
### Patch Changes
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "jazz-react-native-media-images", "name": "jazz-react-native-media-images",
"version": "0.10.1", "version": "0.10.2",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"types": "src/index.ts", "types": "src/index.ts",

View File

@@ -1,5 +1,16 @@
# jazz-browser # jazz-browser
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- cojson-storage-rn-sqlite@0.8.62
- cojson-transport-ws@0.10.2
- jazz-react-core@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "jazz-react-native", "name": "jazz-react-native",
"version": "0.10.1", "version": "0.10.2",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js", "module": "./dist/index.js",

View File

@@ -1,5 +1,15 @@
# jazz-react # jazz-react
## 0.10.2
### Patch Changes
- Updated dependencies [cae3a9e]
- cojson@0.10.2
- jazz-browser@0.10.2
- jazz-react-core@0.10.2
- jazz-tools@0.10.2
## 0.10.1 ## 0.10.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "jazz-react", "name": "jazz-react",
"version": "0.10.1", "version": "0.10.2",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"types": "src/index.ts", "types": "src/index.ts",
@@ -17,10 +17,10 @@
}, },
"dependencies": { "dependencies": {
"@scure/bip39": "^1.3.0", "@scure/bip39": "^1.3.0",
"cojson": "workspace:0.10.1", "cojson": "workspace:0.10.2",
"jazz-browser": "workspace:0.10.1", "jazz-browser": "workspace:0.10.2",
"jazz-react-core": "workspace:*", "jazz-react-core": "workspace:*",
"jazz-tools": "workspace:0.10.1" "jazz-tools": "workspace:0.10.2"
}, },
"devDependencies": { "devDependencies": {
"@testing-library/dom": "^10.4.0", "@testing-library/dom": "^10.4.0",

View File

@@ -47,7 +47,8 @@ export function JazzProvider<Acc extends Account = RegisteredAccount>({
defaultProfileName, defaultProfileName,
onLogOut: onLogOutRefCallback, onLogOut: onLogOutRefCallback,
onAnonymousAccountDiscarded: onAnonymousAccountDiscardedRefCallback, onAnonymousAccountDiscarded: onAnonymousAccountDiscardedRefCallback,
}; } satisfies JazzContextManagerProps<Acc>;
if (contextManager.propsChanged(props)) { if (contextManager.propsChanged(props)) {
contextManager.createContext(props).catch((error) => { contextManager.createContext(props).catch((error) => {
console.error("Error creating Jazz browser context:", error); console.error("Error creating Jazz browser context:", error);

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