Compare commits

..

1 Commits

Author SHA1 Message Date
Guido D'Orsi
4fd1d5a3a4 crazy auth refactoring 2025-01-20 18:36:00 +01:00
552 changed files with 9805 additions and 32570 deletions

View File

@@ -11,7 +11,7 @@
"cojson-storage-sqlite",
"cojson-transport-ws",
"jazz-browser",
"jazz-auth-clerk",
"jazz-browser-auth-clerk",
"jazz-browser-media-images",
"jazz-nodejs",
"jazz-react",

View File

@@ -1,36 +0,0 @@
name: Get and Build Source Code
runs:
using: "composite"
steps:
- name: Enable latestcorepack
shell: bash
run: |
echo "Before: corepack version => $(corepack --version || echo 'not installed')"
npm install -g corepack@latest
echo "After : corepack version => $(corepack --version)"
corepack enable
pnpm --version
- name: Install Node.js
uses: useblacksmith/setup-node@v5
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: useblacksmith/cache@v5
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile

View File

@@ -6,7 +6,7 @@ on:
jobs:
build-examples:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
strategy:
matrix:
example: [
@@ -23,13 +23,36 @@ jobs:
]
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: |

View File

@@ -2,25 +2,51 @@ name: Build Starters
on:
push:
branches: ["main"]
branches: [ "main" ]
jobs:
build-starters:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
strategy:
matrix:
starter: ["react-demo-auth-tailwind"]
starter: [
"react-demo-auth-tailwind",
]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Pnpm Build
run: |
pnpm install
pnpm turbo build;
working-directory: ./starters/${{ matrix.starter }}
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: |
pnpm install
pnpm turbo build;
working-directory: ./starters/${{ matrix.starter }}

View File

@@ -6,7 +6,7 @@ on:
jobs:
quality:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

View File

@@ -1,91 +0,0 @@
name: End-to-End Tests for React Native
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- ".github/workflows/e2e-rn-test.yml"
- "examples/chat-rn/**"
- "examples/chat-rn-clerk/**"
- "packages/jazz-react-native*/**"
jobs:
e2e-tests:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Create Output Directory
run: |
mkdir -p ~/output
- name: Pnpm Build
run: pnpm turbo build --filter="./packages/*"
- name: iOS Simulator
id: ios-simulator
uses: futureware-tech/simulator-action@v4
with:
os: iOS
wait_for_boot: true
- name: chat-rn App Pre Build
working-directory: ./examples/chat-rn
run: |
pnpm build
pnpm expo prebuild --clean
- name: chat-rn App Build
working-directory: ./examples/chat-rn/ios
run: |
xcodebuild -scheme "jazzchatrn" \
-workspace jazzchatrn.xcworkspace \
-archivePath $RUNNER_TEMP/jazzchatrn.xcarchive \
-derivedDataPath $RUNNER_TEMP/build \
-destination "id=${{ steps.ios-simulator.outputs.udid }}" \
-configuration Release \
-sdk iphonesimulator \
build
xcrun simctl install booted $RUNNER_TEMP/build/Build/Products/Release-iphonesimulator/jazzchatrn.app
xcrun simctl spawn booted log stream --level debug | tee ~/output/sim.log &
- name: Install Maestro
run: |
curl -fsSL "https://get.maestro.mobile.dev" | bash
- name: chat-rn App Test
id: e2e_test
working-directory: ./examples/chat-rn
continue-on-error: true
run: |
export PATH="$PATH":"$HOME/.maestro/bin"
export MAESTRO_DRIVER_STARTUP_TIMEOUT=300000 # setting to 5 mins 👀
export MAESTRO_CLI_NO_ANALYTICS=1
maestro test test/e2e/flow.yml
- name: Copy Maestro and Diagnostic Files
if: steps.e2e_test.outcome != 'success'
run: |
cp -r ~/Library/Logs/DiagnosticReports/* ~/output
cp -r ~/.maestro/tests/* ~/output
- name: Upload Output Files
if: steps.e2e_test.outcome != 'success'
uses: actions/upload-artifact@v4
with:
name: e2e-test-output
path: ~/output/*
retention-days: 5
- name: Exit with Test Result
if: always()
run: |
if [ "${{ steps.e2e_test.outcome }}" != "success" ]; then
exit 1
fi

View File

@@ -8,16 +8,38 @@ on:
jobs:
test:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build jazz-run
run: pnpm exec turbo build && chmod +x dist/index.js;
@@ -26,3 +48,4 @@ jobs:
- name: Run create account
run: ./dist/index.js account create --name "Jazz Run CI test"
working-directory: ./packages/jazz-run

View File

@@ -9,19 +9,41 @@ on:
jobs:
test:
timeout-minutes: 60
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
continue-on-error: true
strategy:
matrix:
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "examples/onboarding", "starters/react-demo-auth-tailwind"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: pnpm turbo build

View File

@@ -1,102 +0,0 @@
name: Pre-Publish tagged Pull Requests
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
pre-release:
if: contains(github.event.pull_request.labels.*.name, 'pre-release')
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Pnpm Build
run: pnpm turbo build --filter="./packages/*"
- name: Pre publish
run: pnpm exec pkg-pr-new publish --json output.json --comment=off "./packages/*"
- name: Post or update comment
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const output = JSON.parse(fs.readFileSync('output.json', 'utf8'));
const packages = output.packages
.map((p) => `- ${p.name}: ${p.url}`)
.join('\n');
const sha =
context.event_name === 'pull_request'
? context.payload.pull_request.head.sha
: context.payload.after;
const resolutions = Object.fromEntries(
output.packages.map((p) => [p.name, p.url])
);
const commitUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`;
const body = `## Jazz pre-release
### Packages:
\`\`\`json
${JSON.stringify(resolutions, null, 4)}
\`\`\`
[View Commit](${commitUrl})`;
async function logPublishInfo() {
console.log('\n' + '='.repeat(50));
console.log('Publish Information');
console.log('='.repeat(50));
console.log('\nPublished Packages:');
console.log(output.packages);
console.log('\nTemplates:');
console.log(templates);
console.log(`\nCommit URL: ${commitUrl}`);
console.log('\n' + '='.repeat(50));
}
if (context.eventName === 'pull_request') {
if (context.issue.number) {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body,
});
}
} else if (context.eventName === 'push') {
const pullRequests = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${context.ref.replace(
'refs/heads/',
''
)}`,
});
if (pullRequests.data.length > 0) {
await github.rest.issues.createComment({
issue_number: pullRequests.data[0].number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body,
});
} else {
console.log(
'No open pull request found for this push. Logging publish information to console:'
);
await logPublishInfo();
}
}

View File

@@ -17,13 +17,35 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
name: Release
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Create Release Pull Request or Publish to npm
id: changesets

View File

@@ -9,20 +9,39 @@ on:
jobs:
unit-tests:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: pnpm turbo build --filter="./packages/*"
- name: Install Playwright Browsers
run: pnpm exec playwright install
- name: Unit Tests
run: pnpm test:ci

2
.gitignore vendored
View File

@@ -19,5 +19,3 @@ test-results
.husky
.vscode/settings.json
.svelte-kit

View File

@@ -1,4 +1,4 @@
Copyright 2025, Garden Computing, Inc.
Copyright 2024, Garden Computing, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

View File

@@ -17,4 +17,4 @@ For community and support, please join our [Discord](https://discord.gg/utDMjHYg
- Community & support: [Discord](https://discord.gg/utDMjHYg42)
- Updates: [X](https://x.com/jazz_tools) & [Email](https://garden.co/news)
Copyright 2025 — Garden Computing, Inc.
Copyright 2024 — Garden Computing, Inc.

View File

@@ -42,15 +42,6 @@
}
},
"overrides": [
{
"include": ["**/package.json"],
"linter": {
"enabled": false
},
"formatter": {
"enabled": false
}
},
{
"include": ["packages/**/src/**"],
"linter": {

View File

@@ -1,150 +1,5 @@
# chat-rn-clerk
## 1.0.66
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react-native@0.10.1
- jazz-react-native-auth-clerk@0.10.1
- jazz-react-native-media-images@0.10.1
## 1.0.65
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react-native-auth-clerk@0.10.0
- jazz-react-native@0.10.0
- jazz-tools@0.10.0
- jazz-react-native-media-images@0.10.0
## 1.0.64
### Patch Changes
- jazz-react-native@0.9.23
- jazz-react-native-auth-clerk@0.9.23
- jazz-tools@0.9.23
- jazz-react-native-media-images@0.9.23
## 1.0.63
### Patch Changes
- jazz-react-native@0.9.22
- jazz-react-native-auth-clerk@0.9.22
## 1.0.62
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react-native@0.9.21
- jazz-react-native-auth-clerk@0.9.21
- jazz-react-native-media-images@0.9.21
## 1.0.61
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react-native@0.9.20
- jazz-react-native-auth-clerk@0.9.20
- jazz-react-native-media-images@0.9.20
## 1.0.60
### Patch Changes
- jazz-react-native@0.9.19
- jazz-react-native-auth-clerk@0.9.19
- jazz-tools@0.9.19
- jazz-react-native-media-images@0.9.19
## 1.0.59
### Patch Changes
- jazz-react-native@0.9.18
- jazz-react-native-auth-clerk@0.9.18
- jazz-tools@0.9.18
- jazz-react-native-media-images@0.9.18
## 1.0.58
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react-native@0.9.17
- jazz-react-native-auth-clerk@0.9.17
- jazz-react-native-media-images@0.9.17
## 1.0.57
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-react-native-auth-clerk@0.9.16
- jazz-tools@0.9.16
- jazz-react-native@0.9.16
- jazz-react-native-media-images@0.9.16
## 1.0.56
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-react-native@0.9.15
- jazz-react-native-auth-clerk@0.9.15
- jazz-react-native-media-images@0.9.15
## 1.0.55
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-react-native@0.9.14
- jazz-react-native-auth-clerk@0.9.14
- jazz-react-native-media-images@0.9.14
## 1.0.54
### Patch Changes
- jazz-react-native@0.9.13
- jazz-react-native-auth-clerk@0.9.13
- jazz-tools@0.9.13
- jazz-react-native-media-images@0.9.13
## 1.0.53
### Patch Changes
- jazz-react-native@0.9.12
- jazz-react-native-auth-clerk@0.9.12
- jazz-tools@0.9.12
- jazz-react-native-media-images@0.9.12
## 1.0.52
### Patch Changes
- jazz-react-native@0.9.11
- jazz-react-native-auth-clerk@0.9.11
- jazz-tools@0.9.11
- jazz-react-native-media-images@0.9.11
## 1.0.51
### Patch Changes

View File

@@ -1,9 +1,9 @@
import { Redirect, Stack } from "expo-router";
import { useIsAuthenticated } from "jazz-react-native";
import React from "react";
import { useAuth } from "../../src/auth-context";
export default function HomeLayout() {
const isAuthenticated = useIsAuthenticated();
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
return <Redirect href={"/chat"} />;

View File

@@ -1,8 +1,8 @@
import { Redirect, Stack } from "expo-router";
import { useIsAuthenticated } from "jazz-react-native";
import { useAuth } from "../../src/auth-context";
export default function UnAuthenticatedLayout() {
const isAuthenticated = useIsAuthenticated();
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
return <Redirect href={"/chat"} />;

View File

@@ -20,15 +20,10 @@ export default function ChatScreen() {
const navigation = useNavigation();
const { user } = useUser();
function handleLogOut() {
logOut();
router.navigate("/");
}
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: "Chat",
headerRight: () => <Button onPress={handleLogOut} title="Logout" />,
headerRight: () => <Button onPress={logOut} title="Logout" />,
});
}, [navigation]);

View File

@@ -19,6 +19,7 @@ config.resolver.nodeModulesPaths = [
path.resolve(workspaceRoot, "node_modules"),
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.unstable_enablePackageExports = true;
config.resolver.requireCycleIgnorePatterns = [
/(^|\/|\\)node_modules($|\/|\\)/,
/(^|\/|\\)packages($|\/|\\)/,

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-clerk",
"main": "index.js",
"version": "1.0.66",
"version": "1.0.51",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
@@ -72,7 +72,7 @@
"jest": "^29.2.1",
"jest-expo": "~52.0.2",
"react-test-renderer": "18.2.0",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2"
},
"private": true

View File

@@ -1 +0,0 @@
export const apiKey = "chat-rn-clerk-example-jazz@garden.co";

View File

@@ -1,21 +1,63 @@
import { useClerk } from "@clerk/clerk-expo";
import { JazzProviderWithClerk } from "jazz-react-native-auth-clerk";
import React, { PropsWithChildren } from "react";
import { apiKey } from "./apiKey";
import { useClerk, useUser } from "@clerk/clerk-expo";
import { JazzProvider, setupKvStore } from "jazz-react-native";
import { useJazzClerkAuth } from "jazz-react-native-auth-clerk";
import React, {
createContext,
PropsWithChildren,
useContext,
useEffect,
useState,
} from "react";
import { Text, View } from "react-native";
const AuthContext = createContext<{
isAuthenticated: boolean;
isLoading: boolean;
}>({
isAuthenticated: false,
isLoading: true,
});
export function useAuth() {
return useContext(AuthContext);
}
const kvStore = setupKvStore();
export function JazzAndAuth({ children }: PropsWithChildren) {
const { isSignedIn, isLoaded: isClerkLoaded } = useUser();
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk, kvStore);
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
if (isSignedIn && isClerkLoaded && auth) {
setIsAuthenticated(true);
} else {
setIsAuthenticated(false);
}
}, [isSignedIn, isClerkLoaded, auth]);
return (
<JazzProviderWithClerk
clerk={clerk}
storage="sqlite"
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
when: "signedUp", // This makes the app work in local mode when the user is not authenticated
}}
<AuthContext.Provider
value={{ isAuthenticated, isLoading: !isClerkLoaded || !auth }}
>
{children}
</JazzProviderWithClerk>
{state?.errors?.length > 0 &&
state.errors.map((error) => (
<View key={error}>
<Text style={{ color: "red" }}>{error}</Text>
</View>
))}
{auth && clerk.user ? (
<JazzProvider
auth={auth}
storage="sqlite"
peer="wss://cloud.jazz.tools/?key=chat-rn-clerk-example-jazz@garden.co"
>
{children}
</JazzProvider>
) : (
children
)}
</AuthContext.Provider>
);
}

View File

@@ -1,121 +1,5 @@
# chat-rn
## 1.0.63
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react-native@0.10.1
## 1.0.62
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react-native@0.10.0
- jazz-tools@0.10.0
## 1.0.61
### Patch Changes
- jazz-react-native@0.9.23
- jazz-tools@0.9.23
## 1.0.60
### Patch Changes
- jazz-react-native@0.9.22
## 1.0.59
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react-native@0.9.21
## 1.0.58
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react-native@0.9.20
## 1.0.57
### Patch Changes
- jazz-react-native@0.9.19
- jazz-tools@0.9.19
## 1.0.56
### Patch Changes
- jazz-react-native@0.9.18
- jazz-tools@0.9.18
## 1.0.55
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react-native@0.9.17
## 1.0.54
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-react-native@0.9.16
## 1.0.53
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-react-native@0.9.15
## 1.0.52
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-react-native@0.9.14
## 1.0.51
### Patch Changes
- jazz-react-native@0.9.13
- jazz-tools@0.9.13
## 1.0.50
### Patch Changes
- jazz-react-native@0.9.12
- jazz-tools@0.9.12
## 1.0.49
### Patch Changes
- jazz-react-native@0.9.11
- jazz-tools@0.9.11
## 1.0.48
### Patch Changes

View File

@@ -19,6 +19,7 @@ config.resolver.nodeModulesPaths = [
path.resolve(workspaceRoot, "node_modules"),
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.unstable_enablePackageExports = true;
config.resolver.requireCycleIgnorePatterns = [
/(^|\/|\\)node_modules($|\/|\\)/,
/(^|\/|\\)packages($|\/|\\)/,

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.63",
"version": "1.0.48",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",
@@ -46,7 +46,7 @@
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "^18.3.12",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2"
},
"private": true

View File

@@ -9,8 +9,7 @@ import * as Linking from "expo-linking";
import React, { StrictMode, useEffect, useState } from "react";
import HandleInviteScreen from "./invite";
import { JazzProvider } from "jazz-react-native";
import { apiKey } from "./apiKey";
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react-native";
import ChatScreen from "./chat";
const Stack = createNativeStackNavigator();
@@ -29,6 +28,7 @@ const linking = {
};
function App() {
const [auth, state] = useDemoAuth();
const [initialRoute, setInitialRoute] = useState<
"ChatScreen" | "HandleInviteScreen"
>("ChatScreen");
@@ -43,13 +43,16 @@ function App() {
});
}, []);
if (!auth) {
return null;
}
return (
<StrictMode>
<JazzProvider
auth={auth}
storage="sqlite"
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
peer="wss://cloud.jazz.tools/?key=chat-rn-example-jazz@garden.co"
>
<NavigationContainer linking={linking} ref={navigationRef}>
<Stack.Navigator initialRouteName={initialRoute}>
@@ -66,6 +69,9 @@ function App() {
</Stack.Navigator>
</NavigationContainer>
</JazzProvider>
{state.state !== "signedIn" ? (
<DemoAuthBasicUI appName="Jazz Chat" state={state} />
) : null}
</StrictMode>
);
}

View File

@@ -1 +0,0 @@
export const apiKey = "chat-rn-example-jazz@garden.co";

View File

@@ -1,6 +1,6 @@
import clsx from "clsx";
import * as Clipboard from "expo-clipboard";
import { Group, ID, Profile } from "jazz-tools";
import { Group, ID } from "jazz-tools";
import { useEffect, useState } from "react";
import React, {
Button,
@@ -22,16 +22,10 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
const [chatId, setChatId] = useState<ID<Chat>>();
const loadedChat = useCoState(Chat, chatId, [{}]);
const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});
function handleLogOut() {
setChatId(undefined);
logOut();
}
useEffect(() => {
navigation.setOptions({
headerRight: () => <Button onPress={handleLogOut} title="Logout" />,
headerRight: () => <Button onPress={logOut} title="Logout" />,
headerLeft: () =>
loadedChat ? (
<Button
@@ -137,19 +131,6 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
<View className="flex flex-col h-full">
{!loadedChat ? (
<View className="flex flex-col h-full items-center justify-center">
<Text className="text-m font-bold mb-6">Username</Text>
<TextInput
className="rounded h-12 p-2 mb-12 w-40 border border-gray-200 block"
value={profile?.name ?? ""}
onChangeText={(value) => {
if (profile) {
profile.name = value;
}
}}
textAlignVertical="center"
onSubmitEditing={sendMessage}
testID="username-input"
/>
<TouchableOpacity
onPress={createChat}
className="bg-blue-500 p-4 rounded-md"
@@ -191,12 +172,10 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
placeholder="Type a message..."
textAlignVertical="center"
onSubmitEditing={sendMessage}
testID="message-input"
/>
<TouchableOpacity
onPress={sendMessage}
className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center"
testID="send-button"
>
<Text></Text>
</TouchableOpacity>

View File

@@ -1,16 +0,0 @@
# this sub-flow exists to work around an ios issue where the text field is not
# fully erased. The tap into the input field hits the middle, and clears all
# text to the left. If there's more to the right, it slides left, and thus we
# repeat this step. https://maestro.mobile.dev/api-reference/commands/erasetext
appId: com.jazz.chatrn
---
- copyTextFrom:
id: ${id}
- repeat:
times: 4
commands:
- tapOn:
id: ${id}
- eraseText
- copyTextFrom:
id: ${id}

View File

@@ -1,47 +0,0 @@
appId: com.jazz.chatrn
---
- launchApp
# # handle Expo screens (for local dev)
# - assertVisible: "Continue"
# - tapOn: "Continue"
# - assertVisible: "Reload"
# - tapOn: "Reload"
# login
- assertVisible: "Anonymous user"
- runFlow:
label: "Erase existing username"
file: erase_text.yml
env:
id: "username-input"
- inputText: "boorad"
- assertVisible: "boorad"
# start new chat
- tapOn: "Start new chat"
- assertVisible: "Share"
- assertVisible: "Jazz Chat"
- assertVisible: "Logout"
# send a message
- runFlow:
label: "Erase existing message"
file: erase_text.yml
env:
id: "message-input"
- inputText: "bro, low key, it do be like that tho"
- tapOn:
id: "send-button"
- assertVisible: "bro, low key, it do be like that tho"
# get invite code
- tapOn: "Share"
- assertVisible: "Copied to clipboard"
- tapOn: "OK"
# this assert doesn't work. maestro.copiedText only populates from `copyTextFrom`
# - assertTrue: ${maestro.copiedText.startsWith("co_z")}
# logout
- tapOn: "Logout"
- assertVisible: "Anonymous user"

View File

@@ -1,136 +1,5 @@
# chat-vue
## 0.0.50
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser@0.10.1
- jazz-vue@0.10.1
## 0.0.49
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-browser@0.10.0
- jazz-tools@0.10.0
- jazz-vue@0.10.0
## 0.0.48
### Patch Changes
- jazz-browser@0.9.23
- jazz-tools@0.9.23
- jazz-vue@0.9.23
## 0.0.47
### Patch Changes
- jazz-browser@0.9.22
- jazz-vue@0.9.22
## 0.0.46
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser@0.9.21
- jazz-vue@0.9.21
## 0.0.45
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser@0.9.20
- jazz-vue@0.9.20
## 0.0.44
### Patch Changes
- jazz-browser@0.9.19
- jazz-tools@0.9.19
- jazz-vue@0.9.19
## 0.0.43
### Patch Changes
- jazz-browser@0.9.18
- jazz-tools@0.9.18
- jazz-vue@0.9.18
## 0.0.42
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser@0.9.17
- jazz-vue@0.9.17
## 0.0.41
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser@0.9.16
- jazz-vue@0.9.16
## 0.0.40
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-browser@0.9.15
- jazz-vue@0.9.15
## 0.0.39
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-browser@0.9.14
- jazz-vue@0.9.14
## 0.0.38
### Patch Changes
- jazz-browser@0.9.13
- jazz-tools@0.9.13
- jazz-vue@0.9.13
## 0.0.37
### Patch Changes
- jazz-browser@0.9.12
- jazz-tools@0.9.12
- jazz-vue@0.9.12
## 0.0.36
### Patch Changes
- jazz-browser@0.9.11
- jazz-tools@0.9.11
- jazz-vue@0.9.11
## 0.0.35
### Patch Changes

View File

@@ -11,6 +11,10 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npm create jazz-app@latest --example chat-vue --project-name chat-vue
```
or
```bash
npx create-jazz-app@latest --example chat-vue --project-name chat-vue
```

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.50",
"version": "0.0.35",
"private": true,
"type": "module",
"scripts": {
@@ -30,9 +30,9 @@
"eslint-plugin-vue": "^9.28.0",
"npm-run-all2": "^6.2.3",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11",
"vite": "^5.4.10",
"vite-plugin-vue-devtools": "^7.4.6",
"vue-tsc": "^2.1.6"
}

View File

@@ -1 +0,0 @@
export const apiKey = "chat-example-jazz@garden.co";

View File

@@ -1,31 +1,32 @@
import { DemoAuthBasicUI, JazzProvider } from "jazz-vue";
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-vue";
import { createApp, defineComponent, h } from "vue";
import App from "./App.vue";
import "./index.css";
import { apiKey } from "@/apiKey";
import router from "./router";
const RootComponent = defineComponent({
name: "RootComponent",
setup() {
return () =>
const { authMethod, state } = useDemoAuth();
return () => [
h(
JazzProvider,
{
sync: {
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
},
auth: authMethod.value,
peer: "wss://cloud.jazz.tools/?key=chat-example-jazz@garden.co",
},
h(
DemoAuthBasicUI,
{
appName: "Jazz Vue Chat",
},
{
default: () => h(App),
},
),
);
{
default: () => h(App),
},
),
state.state !== "signedIn" &&
h(DemoAuthBasicUI, {
appName: "Jazz Chat",
state,
}),
];
},
});

View File

@@ -1,136 +1,5 @@
# jazz-example-chat
## 0.0.146
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser-media-images@0.10.1
- jazz-react@0.10.1
## 0.0.145
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
- jazz-browser-media-images@0.10.0
## 0.0.144
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
- jazz-browser-media-images@0.9.23
## 0.0.143
### Patch Changes
- jazz-browser-media-images@0.9.22
- jazz-react@0.9.22
## 0.0.142
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser-media-images@0.9.21
- jazz-react@0.9.21
## 0.0.141
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser-media-images@0.9.20
- jazz-react@0.9.20
## 0.0.140
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
- jazz-browser-media-images@0.9.19
## 0.0.139
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
- jazz-browser-media-images@0.9.18
## 0.0.138
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser-media-images@0.9.17
- jazz-react@0.9.17
## 0.0.137
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser-media-images@0.9.16
- jazz-react@0.9.16
## 0.0.136
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-browser-media-images@0.9.15
- jazz-react@0.9.15
## 0.0.135
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-browser-media-images@0.9.14
- jazz-react@0.9.14
## 0.0.134
### Patch Changes
- jazz-react@0.9.13
- jazz-tools@0.9.13
- jazz-browser-media-images@0.9.13
## 0.0.133
### Patch Changes
- jazz-react@0.9.12
- jazz-tools@0.9.12
- jazz-browser-media-images@0.9.12
## 0.0.132
### Patch Changes
- jazz-react@0.9.11
- jazz-tools@0.9.11
- jazz-browser-media-images@0.9.11
## 0.0.131
### Patch Changes

View File

@@ -13,6 +13,10 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npm create jazz-app@latest --example chat --project-name chat
```
or
```bash
npx create-jazz-app@latest --example chat --project-name chat
```

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.146",
"version": "0.0.131",
"type": "module",
"scripts": {
"dev": "vite",
@@ -23,15 +23,15 @@
"react-dom": "^18.3.1"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@playwright/test": "^1.46.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -1 +0,0 @@
export const apiKey = "chat-example-jazz@garden.co";

View File

@@ -1,11 +1,11 @@
import { apiKey } from "@/apiKey.ts";
import { getRandomUsername, inIframe, onChatLoad } from "@/util.ts";
import { inIframe, onChatLoad } from "@/util.ts";
import { useIframeHashRouter } from "hash-slash";
import { JazzProvider, useAccount } from "jazz-react";
import { useAccount } from "jazz-react";
import { Group, ID } from "jazz-tools";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { ChatScreen } from "./chatScreen.tsx";
import { JazzAndAuth } from "./jazz.tsx";
import { Chat } from "./schema.ts";
import { ThemeProvider } from "./themeProvider.tsx";
import { AppContainer, TopBar } from "./ui.tsx";
@@ -28,16 +28,7 @@ export function App() {
return (
<AppContainer>
<TopBar>
<input
type="text"
value={me?.profile?.name ?? ""}
className="bg-transparent"
onChange={(e) => {
if (!me?.profile) return;
me.profile.name = e.target.value;
}}
placeholder="Set username"
/>
<p>{me?.profile?.name}</p>
{!inIframe && <button onClick={logOut}>Log out</button>}
</TopBar>
{router.route({
@@ -48,20 +39,12 @@ export function App() {
);
}
const url = new URL(window.location.href);
const defaultProfileName = url.searchParams.get("user") ?? getRandomUsername();
createRoot(document.getElementById("root")!).render(
<ThemeProvider>
<StrictMode>
<JazzProvider
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
defaultProfileName={defaultProfileName}
>
<JazzAndAuth>
<App />
</JazzProvider>
</JazzAndAuth>
</StrictMode>
</ThemeProvider>,
);

View File

@@ -0,0 +1,19 @@
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react";
export function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, state] = useDemoAuth();
return (
<>
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=chat-example-jazz@garden.co"
>
{children}
</JazzProvider>
{state.state !== "signedIn" && (
<DemoAuthBasicUI appName="Jazz Chat" state={state} />
)}
</>
);
}

View File

@@ -6,7 +6,7 @@ import { useId, useRef } from "react";
export function AppContainer(props: { children: React.ReactNode }) {
return (
<div className="flex flex-col justify-between w-screen h-screen bg-stone-50 dark:bg-stone-925 dark:text-white">
<div className="flex flex-col justify-between w-screen h-screen bg-stone-50 dark:bg-black dark:text-white">
{props.children}
</div>
);
@@ -14,7 +14,7 @@ export function AppContainer(props: { children: React.ReactNode }) {
export function TopBar(props: { children: React.ReactNode }) {
return (
<div className="p-3 bg-white w-full flex justify-between gap-2 border-b dark:bg-transparent dark:border-stone-900">
<div className="p-3 bg-white w-full flex justify-between gap-2 border-b dark:bg-transparent dark:border-stone-800">
{props.children}
</div>
);
@@ -33,7 +33,7 @@ export function ChatBody(props: { children: React.ReactNode }) {
export function EmptyChatMessage() {
return (
<div className="h-full text-base text-stone-500 flex items-center justify-center px-3 md:text-2xl">
<div className="h-full text-base text-stone-500 flex items-center justify-center px-3 text-lg md:text-2xl">
Start a conversation below.
</div>
);
@@ -61,7 +61,7 @@ export function BubbleBody(props: {
"line-clamp-10 text-ellipsis whitespace-pre-wrap",
"rounded-2xl overflow-hidden max-w-[calc(100%-5rem)] shadow-sm p-1",
props.fromMe
? "bg-white dark:bg-stone-900 dark:text-white"
? "bg-white dark:bg-stone-700 dark:text-white"
: "bg-blue text-white",
)}
>
@@ -97,7 +97,7 @@ export function BubbleInfo(props: { by: string | undefined; madeAt: Date }) {
export function InputBar(props: { children: React.ReactNode }) {
return (
<div className="p-3 bg-white border-t shadow-2xl mt-auto flex gap-1 dark:bg-transparent dark:border-stone-900">
<div className="p-3 bg-white border-t shadow-2xl mt-auto flex gap-1 dark:bg-transparent dark:border-stone-800">
{props.children}
</div>
);
@@ -147,7 +147,7 @@ export function TextInput(props: { onSubmit: (text: string) => void }) {
</label>
<input
id={inputId}
className="rounded-full py-1 px-3 border block w-full placeholder:text-stone-500 dark:bg-stone-925 dark:text-white dark:border-stone-900"
className="rounded-full py-1 px-3 border block w-full placeholder:text-stone-500 dark:bg-black dark:text-white dark:border-stone-700"
placeholder="Type a message and press Enter"
maxLength={2048}
onKeyDown={({ key, currentTarget: input }) => {

View File

@@ -15,20 +15,3 @@ export function onChatLoad(chat: Chat) {
}
export const inIframe = window.self !== window.top;
const animals = [
"elephant",
"penguin",
"giraffe",
"octopus",
"kangaroo",
"dolphin",
"cheetah",
"koala",
"platypus",
"pangolin",
];
export function getRandomUsername() {
return `Anonymous ${animals[Math.floor(Math.random() * animals.length)]}`;
}

View File

@@ -1,35 +1,48 @@
import { test } from "@playwright/test";
import { ChatPage } from "./pages/ChatPage";
import { LoginPage } from "./pages/LoginPage";
test("chat between two users", async ({ page: marioPage, browser }) => {
const context = await browser.newContext();
const luigiPage = await context.newPage();
test("chat between two users", async ({ page }) => {
const loginPage = new LoginPage(page);
await marioPage.goto("/");
const mario = "S. Mario";
const luigi = "Luigi";
const marioChat = new ChatPage(marioPage);
const luigiChat = new ChatPage(luigiPage);
await loginPage.goto();
await loginPage.fillUsername(mario);
await loginPage.signup();
await marioChat.setUsername("Mario");
const chatPage = new ChatPage(page);
const message1ByMario = "Hello Luigi, are you ready to save the princess?";
await marioChat.sendMessage(message1ByMario);
await marioChat.expectMessageRow(message1ByMario);
await chatPage.sendMessage(message1ByMario);
await chatPage.expectMessageRow(message1ByMario);
const roomURL = marioPage.url();
await luigiPage.goto(roomURL);
const roomURL = page.url();
await luigiChat.setUsername("Luigi");
await chatPage.logout();
await luigiChat.expectMessageRow(message1ByMario);
await loginPage.expectLoaded();
await loginPage.fillUsername(luigi);
await loginPage.signup();
await page.goto(roomURL);
await chatPage.expectMessageRow(message1ByMario);
const message2ByLuigi =
"No, I'm not ready yet. I'm still trying to find the key to the castle.";
await luigiChat.sendMessage(message2ByLuigi);
await luigiChat.expectMessageRow(message2ByLuigi);
await chatPage.sendMessage(message2ByLuigi);
await chatPage.expectMessageRow(message2ByLuigi);
await marioChat.expectMessageRow(message1ByMario);
await luigiChat.expectMessageRow(message2ByLuigi);
await chatPage.logout();
await loginPage.loginAs(mario);
await page.goto(roomURL);
await chatPage.expectMessageRow(message1ByMario);
await chatPage.expectMessageRow(message2ByLuigi);
});

View File

@@ -4,7 +4,7 @@ export class ChatPage {
readonly page: Page;
readonly messageInput: Locator;
readonly logoutButton: Locator;
readonly usernameInput: Locator;
constructor(page: Page) {
this.page = page;
this.messageInput = page.getByRole("textbox", {
@@ -13,11 +13,6 @@ export class ChatPage {
this.logoutButton = page.getByRole("button", {
name: "Log out",
});
this.usernameInput = page.getByPlaceholder("Set username");
}
async setUsername(username: string) {
await this.usernameInput.fill(username);
}
async sendMessage(message: string) {

View File

@@ -0,0 +1,40 @@
import { Locator, Page, expect } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly usernameInput: Locator;
readonly signupButton: Locator;
constructor(page: Page) {
this.page = page;
this.usernameInput = page.getByRole("textbox");
this.signupButton = page.getByRole("button", {
name: "Sign up",
});
}
async goto() {
this.page.goto("/");
}
async fillUsername(value: string) {
await this.usernameInput.clear();
await this.usernameInput.fill(value);
}
async loginAs(value: string) {
await this.page
.getByRole("button", {
name: value,
})
.click();
}
async signup() {
await this.signupButton.click();
}
async expectLoaded() {
await expect(this.signupButton).toBeVisible();
}
}

View File

@@ -1,136 +1,5 @@
# minimal-auth-clerk
## 0.0.45
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react@0.10.1
- jazz-react-auth-clerk@0.10.1
## 0.0.44
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react-auth-clerk@0.10.0
- jazz-react@0.10.0
- jazz-tools@0.10.0
## 0.0.43
### Patch Changes
- jazz-react@0.9.23
- jazz-react-auth-clerk@0.9.23
- jazz-tools@0.9.23
## 0.0.42
### Patch Changes
- jazz-react@0.9.22
- jazz-react-auth-clerk@0.9.22
## 0.0.41
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react@0.9.21
- jazz-react-auth-clerk@0.9.21
## 0.0.40
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react@0.9.20
- jazz-react-auth-clerk@0.9.20
## 0.0.39
### Patch Changes
- jazz-react@0.9.19
- jazz-react-auth-clerk@0.9.19
- jazz-tools@0.9.19
## 0.0.38
### Patch Changes
- jazz-react@0.9.18
- jazz-react-auth-clerk@0.9.18
- jazz-tools@0.9.18
## 0.0.37
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react@0.9.17
- jazz-react-auth-clerk@0.9.17
## 0.0.36
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-react-auth-clerk@0.9.16
- jazz-tools@0.9.16
- jazz-react@0.9.16
## 0.0.35
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-react@0.9.15
- jazz-react-auth-clerk@0.9.15
## 0.0.34
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-react@0.9.14
- jazz-react-auth-clerk@0.9.14
## 0.0.33
### Patch Changes
- jazz-react@0.9.13
- jazz-react-auth-clerk@0.9.13
- jazz-tools@0.9.13
## 0.0.32
### Patch Changes
- jazz-react@0.9.12
- jazz-react-auth-clerk@0.9.12
- jazz-tools@0.9.12
## 0.0.31
### Patch Changes
- jazz-react@0.9.11
- jazz-react-auth-clerk@0.9.11
- jazz-tools@0.9.11
## 0.0.30
### Patch Changes

View File

@@ -15,7 +15,11 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest --example clerk --project-name clerk
npm create jazz-app@latest --start clerk --project-name clerk
```
or
```bash
npx create-jazz-app@latest --start clerk --project-name clerk
```
Go to the new project directory.

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.45",
"version": "0.0.30",
"type": "module",
"scripts": {
"dev": "vite",
@@ -13,7 +13,7 @@
"dependencies": {
"@clerk/clerk-react": "^5.4.1",
"jazz-react": "workspace:*",
"jazz-react-auth-clerk": "workspace:0.10.1",
"jazz-react-auth-clerk": "workspace:0.9.10",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
@@ -25,6 +25,6 @@
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -1,25 +1,13 @@
import { SignInButton } from "@clerk/clerk-react";
import { useAccount, useIsAuthenticated } from "jazz-react";
import { useAccount } from "jazz-react";
function App() {
const { me, logOut } = useAccount();
const isAuthenticated = useIsAuthenticated();
if (isAuthenticated) {
return (
<div className="container">
<h1>You're logged in</h1>
<p>Welcome back, {me?.profile?.name}</p>
<button onClick={() => logOut()}>Logout</button>
</div>
);
}
return (
<div className="container">
<h1>You're not logged in</h1>
<SignInButton />
<h1>You're logged in</h1>
<p>Welcome back, {me?.profile?.name}</p>
<button onClick={() => logOut()}>Logout</button>
</div>
);
}

View File

@@ -1 +0,0 @@
export const apiKey = "minimal-auth-clerk-example@garden.co";

View File

@@ -62,7 +62,7 @@ button {
}
.container {
max-width: 400px;
max-width: 200px;
margin: 0 auto;
padding: 0 1rem;
display: flex;

View File

@@ -1,10 +1,10 @@
import { ClerkProvider, useClerk } from "@clerk/clerk-react";
import { ClerkProvider, SignInButton, useClerk } from "@clerk/clerk-react";
import { useJazzClerkAuth } from "jazz-react-auth-clerk";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { JazzProviderWithClerk } from "jazz-react-auth-clerk";
import { apiKey } from "./apiKey";
import { JazzProvider } from "jazz-react";
// Import your publishable key
const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
@@ -13,28 +13,35 @@ if (!PUBLISHABLE_KEY) {
throw new Error("Add your Clerk publishable key to the .env.local file");
}
function JazzProvider({ children }: { children: React.ReactNode }) {
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
return (
<JazzProviderWithClerk
clerk={clerk}
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
when: "signedUp", // This makes the app work in local mode when the user is not authenticated
}}
>
{children}
</JazzProviderWithClerk>
<main className="container">
{state?.errors?.map((error) => (
<div key={error}>{error}</div>
))}
{clerk.user && auth ? (
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=minimal-auth-clerk-example@garden.co"
>
{children}
</JazzProvider>
) : (
<SignInButton />
)}
</main>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/">
<JazzProvider>
<JazzAndAuth>
<App />
</JazzProvider>
</JazzAndAuth>
</ClerkProvider>
</StrictMode>,
);

View File

@@ -1,121 +1,5 @@
# file-share-svelte
## 0.0.30
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-svelte@0.10.1
## 0.0.29
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-tools@0.10.0
- jazz-svelte@0.10.0
## 0.0.28
### Patch Changes
- jazz-svelte@0.9.23
- jazz-tools@0.9.23
## 0.0.27
### Patch Changes
- jazz-svelte@0.9.22
## 0.0.26
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-svelte@0.9.21
## 0.0.25
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-svelte@0.9.20
## 0.0.24
### Patch Changes
- jazz-svelte@0.9.19
- jazz-tools@0.9.19
## 0.0.23
### Patch Changes
- jazz-svelte@0.9.18
- jazz-tools@0.9.18
## 0.0.22
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-svelte@0.9.17
## 0.0.21
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-svelte@0.9.16
## 0.0.20
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-svelte@0.9.15
## 0.0.19
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-svelte@0.9.14
## 0.0.18
### Patch Changes
- jazz-svelte@0.9.13
- jazz-tools@0.9.13
## 0.0.17
### Patch Changes
- jazz-svelte@0.9.12
- jazz-tools@0.9.12
## 0.0.16
### Patch Changes
- jazz-svelte@0.9.11
- jazz-tools@0.9.11
## 0.0.15
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.30",
"version": "0.0.15",
"private": true,
"type": "module",
"scripts": {
@@ -18,8 +18,8 @@
},
"devDependencies": {
"@sveltejs/adapter-vercel": "^5.5.0",
"@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^4.0.1",
"@types/is-ci": "^3.0.4",
"autoprefixer": "^10.4.20",
"eslint": "^9.7.0",
@@ -32,10 +32,10 @@
"prettier-plugin-tailwindcss": "^0.6.5",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"typescript-eslint": "^8.0.0",
"vite": "^6.0.11"
"vite": "^5.4.10"
},
"dependencies": {
"@tailwindcss/typography": "^0.5.15",

View File

@@ -1 +0,0 @@
export const apiKey = "file-share-svelte@garden.co"

View File

@@ -17,6 +17,6 @@ export function formatFileSize(bytes: number): string {
* @param createdAt The creation date
* @returns A unique file ID string
*/
export function generateTempFileId(fileName: string | undefined, createdAt: Date | undefined): string {
return `file-${fileName ?? 'unknown'}-${createdAt?.getTime() ?? 0}`;
export function generateTempFileId(fileName: string, createdAt: Date): string {
return `file-${fileName}-${createdAt.getTime()}`;
}

View File

@@ -12,9 +12,11 @@
import { Toaster } from 'svelte-sonner';
import '../app.css';
import { FileShareAccount } from '$lib/schema';
import {apiKey} from '../apiKey';
let { children } = $props();
const auth = usePasskeyAuth({
appName: 'File Share'
});
</script>
<svelte:head>
@@ -23,16 +25,21 @@
<Toaster richColors />
<JazzProvider
AccountSchema={FileShareAccount}
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
when: "signedUp",
}}
>
<PasskeyAuthBasicUI appName="File Share">
{#if auth.state.state === 'ready'}
<div class="fixed inset-0 flex items-center justify-center bg-gray-50/80">
<div class="rounded-lg bg-white p-8 shadow-lg">
<PasskeyAuthBasicUI state={auth.state} />
</div>
</div>
{/if}
{#if auth.current}
<JazzProvider
AccountSchema={FileShareAccount}
auth={auth.current}
peer="wss://cloud.jazz.tools/?key=file-share-svelte@garden.co"
>
<div class="min-h-screen bg-gray-100">
{@render children()}
</div>
</PasskeyAuthBasicUI>
</JazzProvider>
</JazzProvider>
{/if}

View File

@@ -28,7 +28,7 @@
const input = event.target as HTMLInputElement;
const files = input.files;
if (!files || !files.length || !me.root?.sharedFiles || !me.root.publicGroup) return;
if (!files || !files.length || !me?.root?.sharedFiles || !me.root.publicGroup) return;
const file = files[0];
const fileName = file.name;
@@ -129,14 +129,12 @@
{#if sharedFiles.current}
{#if !(sharedFiles.current.length === 0 && uploadingFiles.size === 0)}
{#each [...sharedFiles.current, ...uploadingFiles.values()] as file (generateTempFileId(file?.name, file?.createdAt))}
{#if file}
<FileItem
{file}
loading={uploadingFiles.has(generateTempFileId(file?.name, file?.createdAt))}
onShare={shareFile}
onDelete={deleteFile}
/>
{/if}
<FileItem
{file}
loading={uploadingFiles.has(generateTempFileId(file?.name, file?.createdAt))}
onShare={shareFile}
onDelete={deleteFile}
/>
{/each}
{:else}
<p class="text-center text-gray-500">No files yet</p>

View File

@@ -1,136 +1,5 @@
# form
## 0.0.41
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser-media-images@0.10.1
- jazz-react@0.10.1
## 0.0.40
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
- jazz-browser-media-images@0.10.0
## 0.0.39
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
- jazz-browser-media-images@0.9.23
## 0.0.38
### Patch Changes
- jazz-browser-media-images@0.9.22
- jazz-react@0.9.22
## 0.0.37
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser-media-images@0.9.21
- jazz-react@0.9.21
## 0.0.36
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser-media-images@0.9.20
- jazz-react@0.9.20
## 0.0.35
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
- jazz-browser-media-images@0.9.19
## 0.0.34
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
- jazz-browser-media-images@0.9.18
## 0.0.33
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser-media-images@0.9.17
- jazz-react@0.9.17
## 0.0.32
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser-media-images@0.9.16
- jazz-react@0.9.16
## 0.0.31
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-browser-media-images@0.9.15
- jazz-react@0.9.15
## 0.0.30
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-browser-media-images@0.9.14
- jazz-react@0.9.14
## 0.0.29
### Patch Changes
- jazz-react@0.9.13
- jazz-tools@0.9.13
- jazz-browser-media-images@0.9.13
## 0.0.28
### Patch Changes
- jazz-react@0.9.12
- jazz-tools@0.9.12
- jazz-browser-media-images@0.9.12
## 0.0.27
### Patch Changes
- jazz-react@0.9.11
- jazz-tools@0.9.11
- jazz-browser-media-images@0.9.11
## 0.0.26
### Patch Changes

View File

@@ -28,7 +28,11 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest --example form --project-name form
npm create jazz-app@latest --start form --project-name form
```
or
```bash
npx create-jazz-app@latest --start form --project-name form
```
Go to the new project directory.

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.0.41",
"version": "0.0.26",
"type": "module",
"scripts": {
"dev": "vite",
@@ -20,7 +20,7 @@
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.50.1",
"@playwright/test": "^1.46.1",
"@tailwindcss/forms": "^0.5.9",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
@@ -29,8 +29,8 @@
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -1 +0,0 @@
export const apiKey = "form-example@garden.co";

View File

@@ -1,11 +1,30 @@
import { JazzProvider } from "jazz-react";
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { apiKey } from "./apiKey";
import { JazzAccount } from "./schema.ts";
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, authState] = useDemoAuth();
return (
<>
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=form-example@garden.co"
AccountSchema={JazzAccount}
>
{children}
</JazzProvider>
{authState.state !== "signedIn" && (
<DemoAuthBasicUI appName="Form" state={authState} />
)}
</>
);
}
declare module "jazz-react" {
interface Register {
Account: JazzAccount;
@@ -14,13 +33,8 @@ declare module "jazz-react" {
createRoot(document.getElementById("root")!).render(
<StrictMode>
<JazzProvider
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
AccountSchema={JazzAccount}
>
<JazzAndAuth>
<App />
</JazzProvider>
</JazzAndAuth>
</StrictMode>,
);

View File

@@ -1,7 +1,13 @@
import { expect, test } from "@playwright/test";
import { LoginPage } from "./pages/LoginPage";
test("create and edit an order", async ({ page }) => {
await page.goto("/");
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.fillUsername("Alice");
await loginPage.signup();
// start an order
await page.getByRole("link", { name: "Add new order" }).click();
await page.getByLabel("Base tea").selectOption("Oolong");

View File

@@ -0,0 +1,40 @@
import { Locator, Page, expect } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly usernameInput: Locator;
readonly signupButton: Locator;
constructor(page: Page) {
this.page = page;
this.usernameInput = page.getByRole("textbox");
this.signupButton = page.getByRole("button", {
name: "Sign up",
});
}
async goto() {
this.page.goto("/");
}
async fillUsername(value: string) {
await this.usernameInput.clear();
await this.usernameInput.fill(value);
}
async loginAs(value: string) {
await this.page
.getByRole("button", {
name: value,
})
.click();
}
async signup() {
await this.signupButton.click();
}
async expectLoaded() {
await expect(this.signupButton).toBeVisible();
}
}

View File

@@ -1,136 +1,5 @@
# image-upload
## 0.0.43
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser-media-images@0.10.1
- jazz-react@0.10.1
## 0.0.42
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
- jazz-browser-media-images@0.10.0
## 0.0.41
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
- jazz-browser-media-images@0.9.23
## 0.0.40
### Patch Changes
- jazz-browser-media-images@0.9.22
- jazz-react@0.9.22
## 0.0.39
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser-media-images@0.9.21
- jazz-react@0.9.21
## 0.0.38
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser-media-images@0.9.20
- jazz-react@0.9.20
## 0.0.37
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
- jazz-browser-media-images@0.9.19
## 0.0.36
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
- jazz-browser-media-images@0.9.18
## 0.0.35
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser-media-images@0.9.17
- jazz-react@0.9.17
## 0.0.34
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser-media-images@0.9.16
- jazz-react@0.9.16
## 0.0.33
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-browser-media-images@0.9.15
- jazz-react@0.9.15
## 0.0.32
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-browser-media-images@0.9.14
- jazz-react@0.9.14
## 0.0.31
### Patch Changes
- jazz-react@0.9.13
- jazz-tools@0.9.13
- jazz-browser-media-images@0.9.13
## 0.0.30
### Patch Changes
- jazz-react@0.9.12
- jazz-tools@0.9.12
- jazz-browser-media-images@0.9.12
## 0.0.29
### Patch Changes
- jazz-react@0.9.11
- jazz-tools@0.9.11
- jazz-browser-media-images@0.9.11
## 0.0.28
### Patch Changes

View File

@@ -15,6 +15,10 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npm create jazz-app@latest --example image-upload --project-name image-upload
```
or
```bash
npx create-jazz-app@latest --example image-upload --project-name image-upload
```

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.43",
"version": "0.0.28",
"type": "module",
"scripts": {
"dev": "vite",
@@ -24,6 +24,6 @@
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -1 +0,0 @@
export const apiKey = "image-upload-example@garden.co";

View File

@@ -1,11 +1,30 @@
import { JazzProvider } from "jazz-react";
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { apiKey } from "./apiKey.ts";
import { JazzAccount } from "./schema.ts";
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, authState] = useDemoAuth();
return (
<>
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=image-upload-example@garden.co"
AccountSchema={JazzAccount}
>
{children}
</JazzProvider>
{authState.state !== "signedIn" && (
<DemoAuthBasicUI appName="Image upload" state={authState} />
)}
</>
);
}
declare module "jazz-react" {
interface Register {
Account: JazzAccount;
@@ -14,13 +33,8 @@ declare module "jazz-react" {
createRoot(document.getElementById("root")!).render(
<StrictMode>
<JazzProvider
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
AccountSchema={JazzAccount}
>
<JazzAndAuth>
<App />
</JazzProvider>
</JazzAndAuth>
</StrictMode>,
);

View File

@@ -1,81 +1,5 @@
# jazz-example-inspector
## 0.0.104
### Patch Changes
- Updated dependencies [5a63cba]
- cojson@0.10.1
- cojson-transport-ws@0.10.1
## 0.0.103
### Patch Changes
- Updated dependencies [b426342]
- Updated dependencies [498954f]
- Updated dependencies [8217981]
- Updated dependencies [ac3d9fa]
- Updated dependencies [610543c]
- cojson@0.10.0
- cojson-transport-ws@0.10.0
## 0.0.102
### Patch Changes
- Updated dependencies [70c9a5d]
- cojson@0.9.23
- cojson-transport-ws@0.9.23
## 0.0.101
### Patch Changes
- Updated dependencies [14b6149]
- cojson-transport-ws@0.9.22
## 0.0.100
### Patch Changes
- Updated dependencies [6ad0a9f]
- cojson@0.9.19
- cojson-transport-ws@0.9.19
## 0.0.99
### Patch Changes
- Updated dependencies [8898b10]
- cojson@0.9.18
- cojson-transport-ws@0.9.18
## 0.0.98
### Patch Changes
- Updated dependencies [8d29e50]
- cojson-transport-ws@0.9.13
- cojson@0.9.13
## 0.0.97
### Patch Changes
- Updated dependencies [15d4b2a]
- cojson-transport-ws@0.9.12
- cojson@0.9.12
## 0.0.96
### Patch Changes
- Updated dependencies [efbf3d8]
- Updated dependencies [5863bad]
- cojson@0.9.11
- cojson-transport-ws@0.9.11
## 0.0.95
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector-app",
"private": true,
"version": "0.0.104",
"version": "0.0.95",
"type": "module",
"scripts": {
"dev": "vite",
@@ -12,12 +12,12 @@
},
"dependencies": {
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"cojson": "workspace:0.10.1",
"cojson-transport-ws": "workspace:0.10.1",
"cojson": "workspace:0.9.10",
"cojson-transport-ws": "workspace:0.9.10",
"hash-slash": "workspace:0.2.1",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
@@ -37,8 +37,8 @@
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -1 +0,0 @@
export const apiKey = "";

View File

@@ -5,9 +5,13 @@ import {
RawCoStream,
RawCoValue,
} from "cojson";
import { base64URLtoBytes } from "cojson";
import { BinaryStreamItem, BinaryStreamStart, CoStreamItem } from "cojson";
import { JsonObject, JsonValue } from "cojson";
import { base64URLtoBytes } from "cojson/src/base64url.ts";
import {
BinaryStreamItem,
BinaryStreamStart,
CoStreamItem,
} from "cojson/src/coValues/coStream.ts";
import { JsonObject, JsonValue } from "cojson/src/jsonValue.ts";
import { ArrowDownToLine } from "lucide-react";
import { useEffect, useState } from "react";
import { PageInfo } from "./types";

View File

@@ -1,6 +1,6 @@
import clsx from "clsx";
import { CoID, LocalNode, RawCoValue } from "cojson";
import { JsonObject } from "cojson";
import { JsonObject } from "cojson/src/jsonValue.ts";
import { ResolveIcon } from "./type-icon";
import { PageInfo, isCoId } from "./types";
import { CoMapPreview, ValueRenderer } from "./value-renderer";

View File

@@ -6,9 +6,9 @@ import {
RawAccount,
RawAccountID,
RawCoValue,
WasmCrypto,
} from "cojson";
import { createWebSocketPeer } from "cojson-transport-ws";
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
import { Trash2 } from "lucide-react";
import React, { useState, useEffect } from "react";
import { Breadcrumbs } from "./breadcrumbs";

View File

@@ -1,5 +1,5 @@
import { CoID, LocalNode, RawCoValue } from "cojson";
import { JsonObject } from "cojson";
import { JsonObject } from "cojson/src/jsonValue.ts";
import { useMemo, useState } from "react";
import { LinkIcon } from "../link-icon";
import { PageInfo } from "./types";

View File

@@ -1,142 +1,5 @@
# jazz-example-musicplayer
## 0.0.67
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-inspector@0.10.1
- jazz-react@0.10.1
## 0.0.66
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-inspector@0.10.0
- jazz-react@0.10.0
- jazz-tools@0.10.0
## 0.0.65
### Patch Changes
- jazz-inspector@0.9.23
- jazz-react@0.9.23
- jazz-tools@0.9.23
## 0.0.64
### Patch Changes
- jazz-react@0.9.22
## 0.0.63
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-inspector@0.9.22
- jazz-react@0.9.21
## 0.0.62
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-inspector@0.9.21
- jazz-react@0.9.20
## 0.0.61
### Patch Changes
- jazz-inspector@0.9.20
- jazz-react@0.9.19
- jazz-tools@0.9.19
## 0.0.60
### Patch Changes
- Updated dependencies [2faf22f]
- jazz-inspector@0.9.19
## 0.0.59
### Patch Changes
- jazz-inspector@0.9.18
- jazz-react@0.9.18
- jazz-tools@0.9.18
## 0.0.58
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-inspector@0.9.17
- jazz-react@0.9.17
## 0.0.57
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-inspector@0.9.16
- jazz-react@0.9.16
## 0.0.56
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-inspector@0.9.15
- jazz-react@0.9.15
## 0.0.55
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-inspector@0.9.14
- jazz-react@0.9.14
## 0.0.54
### Patch Changes
- jazz-inspector@0.9.13
- jazz-react@0.9.13
- jazz-tools@0.9.13
## 0.0.53
### Patch Changes
- jazz-inspector@0.9.12
- jazz-react@0.9.12
- jazz-tools@0.9.12
## 0.0.52
### Patch Changes
- jazz-inspector@0.9.11
- jazz-react@0.9.11
- jazz-tools@0.9.11
## 0.0.51
### Patch Changes

View File

@@ -13,6 +13,10 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npm create jazz-app@latest --example music-player --project-name music-player
```
or
```bash
npx create-jazz-app@latest --example music-player --project-name music-player
```

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.67",
"version": "0.0.51",
"type": "module",
"scripts": {
"dev": "vite",
@@ -21,9 +21,9 @@
"@radix-ui/react-tooltip": "^1.1.6",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-react": "workspace:0.9.10",
"jazz-tools": "workspace:0.9.10",
"jazz-inspector": "workspace:*",
"jazz-react": "workspace:0.10.1",
"jazz-tools": "workspace:0.10.1",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -33,14 +33,14 @@
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@playwright/test": "^1.46.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -36,8 +36,6 @@ export class MusicTrack extends CoMap {
*/
file = co.ref(FileStream);
waveform = co.ref(MusicTrackWaveform);
isExampleTrack = co.optional.boolean;
}
export class MusicTrackWaveform extends CoMap {
@@ -87,21 +85,29 @@ export class MusicaAccount extends Account {
* The account migration is run on account creation and on every log-in.
* You can use it to set up the account root and any other initial CoValues you need.
*/
migrate() {
if (this.root === undefined) {
const tracks = ListOfTracks.create([]);
const rootPlaylist = Playlist.create({
tracks,
title: "",
});
migrate(this: MusicaAccount) {
if (!this._refs.root) {
const ownership = { owner: this };
this.root = MusicaAccountRoot.create({
rootPlaylist,
playlists: ListOfPlaylists.create([]),
activeTrack: null,
activePlaylist: rootPlaylist,
exampleDataLoaded: false,
});
const tracks = ListOfTracks.create([], ownership);
const rootPlaylist = Playlist.create(
{
tracks,
title: "",
},
ownership,
);
this.root = MusicaAccountRoot.create(
{
rootPlaylist,
playlists: ListOfPlaylists.create([], ownership),
activeTrack: null,
activePlaylist: rootPlaylist,
exampleDataLoaded: false,
},
ownership,
);
}
}
}

View File

@@ -11,9 +11,7 @@ import { PlayerControls } from "./components/PlayerControls";
import "./index.css";
import { MusicaAccount } from "@/1_schema";
import { apiKey } from "@/apiKey.ts";
import { JazzProvider } from "jazz-react";
import { onAnonymousAccountDiscarded } from "./4_actions";
import { JazzProvider, useIsAnonymousUser } from "jazz-react";
import { useUploadExampleData } from "./lib/useUploadExampleData";
/**
@@ -56,10 +54,27 @@ function Main() {
);
}
const peer =
(new URL(window.location.href).searchParams.get(
"peer",
) as `ws://${string}`) ?? `wss://cloud.jazz.tools/?key=${apiKey}`;
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const peer =
(new URL(window.location.href).searchParams.get(
"peer",
) as `ws://${string}`) ??
"wss://cloud.jazz.tools/?key=music-player-example-jazz@garden.co";
const isAnonymous = useIsAnonymousUser();
return (
<JazzProvider
storage="indexedDB"
peer={peer}
localOnly={isAnonymous}
AccountSchema={MusicaAccount}
>
{children}
<JazzInspector />
</JazzProvider>
);
}
declare module "jazz-react" {
interface Register {
@@ -69,18 +84,8 @@ declare module "jazz-react" {
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<JazzProvider
sync={{
peer,
when: "signedUp", // This makes the app work in local mode when the user is anonymous
}}
storage="indexedDB"
AccountSchema={MusicaAccount}
defaultProfileName="Anonymous unicorn"
onAnonymousAccountDiscarded={onAnonymousAccountDiscarded}
>
<JazzAndAuth>
<Main />
<JazzInspector />
</JazzProvider>
</JazzAndAuth>
</React.StrictMode>,
);

View File

@@ -3,7 +3,7 @@ import {
createInviteLink,
useAccount,
useCoState,
useIsAuthenticated,
useIsAnonymousUser,
} from "jazz-react";
import { ID } from "jazz-tools";
import { useNavigate, useParams } from "react-router";
@@ -71,7 +71,7 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
});
};
const isAuthenticated = useIsAuthenticated();
const isAnonymousUser = useIsAnonymousUser();
return (
<div className="flex flex-col h-screen text-gray-800 bg-blue-50">
@@ -93,7 +93,7 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
<Button onClick={handleCreatePlaylist}>New playlist</Button>
</>
)}
{!isRootPlaylist && isAuthenticated && (
{!isRootPlaylist && !isAnonymousUser && (
<Button onClick={handlePlaylistShareClick}>
Share playlist
</Button>

View File

@@ -22,18 +22,18 @@ import {
* pattern that best fits your app.
*/
export async function uploadMusicTracks(
files: Iterable<File>,
isExampleTrack: boolean = false,
) {
const { root } = await MusicaAccount.getMe().ensureLoaded({
export async function uploadMusicTracks(files: Iterable<File>) {
const me = await MusicaAccount.getMe().ensureLoaded({
root: {
rootPlaylist: {
tracks: [],
},
playlists: [],
},
});
if (!me) return;
for (const file of files) {
// The ownership object defines the user that owns the created coValues
// We are creating a group for each CoValue in order to be able to share them via Playlist
@@ -52,24 +52,25 @@ export async function uploadMusicTracks(
duration: data.duration,
waveform: MusicTrackWaveform.create({ data: data.waveform }, group),
title: file.name,
isExampleTrack,
},
group,
);
// The newly created musicTrack can be associated to the
// user track list using a simple push call
root.rootPlaylist.tracks.push(musicTrack);
me.root.rootPlaylist.tracks.push(musicTrack);
}
}
export async function createNewPlaylist() {
const { root } = await MusicaAccount.getMe().ensureLoaded({
const me = await MusicaAccount.getMe().ensureLoaded({
root: {
playlists: [],
},
});
if (!me) throw new Error("Current playlist not resolved");
// Since playlists are meant to be shared we associate them
// to a group which will contain the keys required to get
// access to the "owned" values
@@ -85,7 +86,7 @@ export async function createNewPlaylist() {
// Again, we associate the new playlist to the
// user by pushing it into the playlists CoList
root.playlists.push(playlist);
me.root.playlists.push(playlist);
return playlist;
}
@@ -151,49 +152,24 @@ export async function updateMusicTrackTitle(track: MusicTrack, title: string) {
}
export async function updateActivePlaylist(playlist?: Playlist) {
const { root } = await MusicaAccount.getMe().ensureLoaded({
const me = await MusicaAccount.getMe().ensureLoaded({
root: {
activePlaylist: {},
rootPlaylist: {},
},
});
root.activePlaylist = playlist ?? root.rootPlaylist;
if (!me) return;
me.root.activePlaylist = playlist ?? me.root.rootPlaylist;
}
export async function updateActiveTrack(track: MusicTrack) {
const { root } = await MusicaAccount.getMe().ensureLoaded({
const me = await MusicaAccount.getMe().ensureLoaded({
root: {},
});
root.activeTrack = track;
}
export async function onAnonymousAccountDiscarded(
anonymousAccount: MusicaAccount,
) {
const { root: anonymousAccountRoot } = await anonymousAccount.ensureLoaded({
root: {
rootPlaylist: {
tracks: [{}],
},
},
});
const me = await MusicaAccount.getMe().ensureLoaded({
root: {
rootPlaylist: {
tracks: [],
},
},
});
for (const track of anonymousAccountRoot.rootPlaylist.tracks) {
if (track.isExampleTrack) continue;
const trackGroup = track._owner.castAs(Group);
trackGroup.addMember(me, "admin");
me.root.rootPlaylist.tracks.push(track);
}
if (!me) return;
me.root.activeTrack = track;
}

View File

@@ -19,6 +19,8 @@ export function InvitePage() {
},
});
if (!me) return;
if (
playlist &&
!me.root.playlists.some((item) => playlist.id === item?.id)

View File

@@ -1 +0,0 @@
export const apiKey = "music-player-example-jazz@garden.co";

View File

@@ -1,7 +1,7 @@
"use client";
import { Button } from "@/components/ui/button";
import { useAccount, useIsAuthenticated } from "jazz-react";
import { useAccount, useIsAnonymousUser } from "jazz-react";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { AuthModal } from "./AuthModal";
@@ -11,14 +11,14 @@ export function AuthButton() {
const { logOut } = useAccount();
const navigate = useNavigate();
const isAuthenticated = useIsAuthenticated();
const isOnboarding = useIsAnonymousUser();
function handleSignOut() {
logOut();
navigate("/");
}
if (isAuthenticated) {
if (!isOnboarding) {
return (
<Button variant="outline" onClick={handleSignOut}>
Sign out

View File

@@ -9,6 +9,7 @@ import {
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useAccount, usePasskeyAuth } from "jazz-react";
import { Loader2 } from "lucide-react";
import { useState } from "react";
interface AuthModalProps {
@@ -19,44 +20,31 @@ interface AuthModalProps {
export function AuthModal({ open, onOpenChange }: AuthModalProps) {
const [username, setUsername] = useState("");
const [isSignUp, setIsSignUp] = useState(true);
const [error, setError] = useState<string | null>(null);
const { me } = useAccount({
root: {
rootPlaylist: {
tracks: [{}],
},
const { me } = useAccount();
const [, authState] = usePasskeyAuth({
appName: "Jazz Music Player",
onAnonymousUserUpgrade: ({ username, isSignUp }) => {
if (isSignUp) {
me.profile!.name = username;
}
onOpenChange(false);
},
});
const auth = usePasskeyAuth({
appName: "Jazz Music Player",
});
const handleViewChange = () => {
setIsSignUp(!isSignUp);
setError(null);
};
const handleSubmit = async (e: React.FormEvent) => {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
try {
if (authState.state === "ready") {
if (isSignUp) {
await auth.signUp(username);
authState.signUp(username);
} else {
await auth.logIn();
authState.logIn();
}
onOpenChange(false);
} catch (error) {
setError(error instanceof Error ? error.message : "Unknown error");
}
};
const shouldShowTransferRootPlaylist =
!isSignUp &&
me?.root.rootPlaylist.tracks.some((track) => !track.isExampleTrack);
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[425px]">
@@ -64,11 +52,13 @@ export function AuthModal({ open, onOpenChange }: AuthModalProps) {
<DialogTitle className="text-2xl font-bold">
{isSignUp ? "Create account" : "Welcome back"}
</DialogTitle>
<DialogDescription>
{isSignUp
? "Sign up to enable network sync and share your playlists with others"
: "Changes done before logging in will be lost"}
</DialogDescription>
{authState.state === "ready" && (
<DialogDescription>
{isSignUp
? "Sign up to enable network sync and share your playlists with others"
: "Changes done before logging in will be lost"}
</DialogDescription>
)}
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
{isSignUp && (
@@ -83,26 +73,32 @@ export function AuthModal({ open, onOpenChange }: AuthModalProps) {
/>
</div>
)}
{error && <div className="text-sm text-red-500">{error}</div>}
{shouldShowTransferRootPlaylist && (
{authState.errors.length > 0 && (
<div className="text-sm text-red-500">
You have tracks in your root playlist that are not example tracks.
If you log in with a passkey, your playlists will be transferred
to your logged account.
{authState.errors.map((error, i) => (
<p key={i}>{error}</p>
))}
</div>
)}
<div className="space-y-4">
<Button
type="submit"
className="w-full bg-blue-600 hover:bg-blue-700"
disabled={authState.state === "loading"}
>
{isSignUp ? "Sign up with passkey" : "Login with passkey"}
{authState.state === "loading" ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : isSignUp ? (
"Sign up with passkey"
) : (
"Login with passkey"
)}
</Button>
<div className="text-center text-sm">
{isSignUp ? "Already have an account?" : "Don't have an account?"}{" "}
<button
type="button"
onClick={handleViewChange}
onClick={() => setIsSignUp(!isSignUp)}
className="text-blue-600 hover:underline"
>
{isSignUp ? "Login" : "Sign up"}

View File

@@ -5,13 +5,13 @@ import {
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { useIsAuthenticated } from "jazz-react";
import { useIsAnonymousUser } from "jazz-react";
import { Info } from "lucide-react";
export function LocalOnlyTag() {
const isAuthenticated = useIsAuthenticated();
const isAnonymousUser = useIsAnonymousUser();
if (isAuthenticated) {
if (!isAnonymousUser) {
return null;
}

View File

@@ -9,6 +9,8 @@ export async function getNextTrack() {
},
});
if (!me) return;
const tracks = me.root.activePlaylist.tracks;
const activeTrack = me.root._refs.activeTrack;
@@ -28,6 +30,8 @@ export async function getPrevTrack() {
},
});
if (!me) return;
const tracks = me.root.activePlaylist.tracks;
const activeTrack = me.root._refs.activeTrack;

View File

@@ -1,14 +1,11 @@
import { MusicaAccount } from "@/1_schema";
import { useAccount } from "jazz-react";
import { useEffect } from "react";
import { uploadMusicTracks } from "../4_actions";
export function useUploadExampleData() {
const { me } = useAccount();
useEffect(() => {
uploadOnboardingData();
}, [me.id]);
}, []);
}
async function uploadOnboardingData() {
@@ -16,6 +13,8 @@ async function uploadOnboardingData() {
root: {},
});
if (!me) throw new Error("Me not resolved");
if (me.root.exampleDataLoaded) return;
me.root.exampleDataLoaded = true;
@@ -23,7 +22,7 @@ async function uploadOnboardingData() {
try {
const trackFile = await (await fetch("/example.mp3")).blob();
await uploadMusicTracks([new File([trackFile], "Example song")], true);
await uploadMusicTracks([new File([trackFile], "Example song")]);
} catch (error) {
me.root.exampleDataLoaded = false;
throw error;

View File

@@ -66,10 +66,7 @@ test("create a new playlist and share", async ({
await sleep(4000); // Wait for the sync to complete
const luigiContext = await browser.newContext();
await mockAuthenticator(luigiContext);
const luigiPage = await luigiContext.newPage();
const luigiPage = await (await browser.newContext()).newPage();
await luigiPage.goto("/");
const luigiHome = new HomePage(luigiPage);

View File

@@ -101,9 +101,6 @@ export class HomePage {
await this.page
.getByRole("button", { name: "Sign up with passkey" })
.click();
await expect(
this.page.getByRole("button", { name: "Sign out" }),
).toBeVisible();
}
async logout() {

View File

@@ -1,136 +1,5 @@
# jazz-example-onboarding
## 0.0.47
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser-media-images@0.10.1
- jazz-react@0.10.1
## 0.0.46
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
- jazz-browser-media-images@0.10.0
## 0.0.45
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
- jazz-browser-media-images@0.9.23
## 0.0.44
### Patch Changes
- jazz-browser-media-images@0.9.22
- jazz-react@0.9.22
## 0.0.43
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser-media-images@0.9.21
- jazz-react@0.9.21
## 0.0.42
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser-media-images@0.9.20
- jazz-react@0.9.20
## 0.0.41
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
- jazz-browser-media-images@0.9.19
## 0.0.40
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
- jazz-browser-media-images@0.9.18
## 0.0.39
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser-media-images@0.9.17
- jazz-react@0.9.17
## 0.0.38
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser-media-images@0.9.16
- jazz-react@0.9.16
## 0.0.37
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-browser-media-images@0.9.15
- jazz-react@0.9.15
## 0.0.36
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-browser-media-images@0.9.14
- jazz-react@0.9.14
## 0.0.35
### Patch Changes
- jazz-react@0.9.13
- jazz-tools@0.9.13
- jazz-browser-media-images@0.9.13
## 0.0.34
### Patch Changes
- jazz-react@0.9.12
- jazz-tools@0.9.12
- jazz-browser-media-images@0.9.12
## 0.0.33
### Patch Changes
- jazz-react@0.9.11
- jazz-tools@0.9.11
- jazz-browser-media-images@0.9.11
## 0.0.32
### Patch Changes

View File

@@ -11,6 +11,10 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npm create jazz-app@latest --example onboarding --project-name onboarding
```
or
```bash
npx create-jazz-app@latest --example onboarding --project-name onboarding
```

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-onboarding",
"private": true,
"version": "0.0.47",
"version": "0.0.32",
"type": "module",
"scripts": {
"dev": "vite",
@@ -21,7 +21,7 @@
"react-dom": "^18.3.1"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@playwright/test": "^1.46.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
@@ -29,8 +29,8 @@
"is-ci": "^3.0.1",
"jazz-run": "workspace:*",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -1 +0,0 @@
export const apiKey = "onboarding-example-jazz@garden.co";

View File

@@ -1,15 +1,29 @@
import App from "@/App.tsx";
import "@/index.css";
import { HRAccount } from "@/schema.ts";
import { JazzProvider } from "jazz-react";
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react";
import React from "react";
import ReactDOM from "react-dom/client";
import { apiKey } from "./apiKey";
const peer =
(new URL(window.location.href).searchParams.get(
"peer",
) as `ws://${string}`) ?? `wss://cloud.jazz.tools/?key=${apiKey}`;
) as `ws://${string}`) ??
"wss://cloud.jazz.tools/?key=onboarding-example-jazz@garden.co";
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, authState] = useDemoAuth();
return (
<>
<JazzProvider AccountSchema={HRAccount} auth={auth} peer={peer}>
{children}
</JazzProvider>
{authState.state !== "signedIn" && (
<DemoAuthBasicUI appName="Jazz Onboarding" state={authState} />
)}
</>
);
}
declare module "jazz-react" {
interface Register {
@@ -19,13 +33,8 @@ declare module "jazz-react" {
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<JazzProvider
AccountSchema={HRAccount}
sync={{
peer,
}}
>
<JazzAndAuth>
<App />
</JazzProvider>
</JazzAndAuth>
</React.StrictMode>,
);

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