Compare commits

..

2 Commits

Author SHA1 Message Date
Guido D'Orsi
11f1a9d5ba docs: add docs about worker storage 2025-01-30 13:05:53 +01:00
Guido D'Orsi
91265d62dd feat: add storage peer option to worker 2025-01-30 13:03:32 +01:00
914 changed files with 17705 additions and 61916 deletions

View File

@@ -0,0 +1,5 @@
---
"jazz-nodejs": patch
---
Add storage peer option

View File

@@ -9,15 +9,12 @@
"cojson-storage", "cojson-storage",
"cojson-storage-indexeddb", "cojson-storage-indexeddb",
"cojson-storage-sqlite", "cojson-storage-sqlite",
"cojson-storage-rn-sqlite",
"cojson-transport-ws", "cojson-transport-ws",
"jazz-browser", "jazz-browser",
"jazz-auth-clerk", "jazz-browser-auth-clerk",
"jazz-browser-media-images", "jazz-browser-media-images",
"jazz-inspector",
"jazz-nodejs", "jazz-nodejs",
"jazz-react", "jazz-react",
"jazz-react-core",
"jazz-react-auth-clerk", "jazz-react-auth-clerk",
"jazz-react-native", "jazz-react-native",
"jazz-react-native-auth-clerk", "jazz-react-native-auth-clerk",

View File

@@ -1,5 +0,0 @@
---
"multiauth": patch
---
Use the new Resolve API

View File

@@ -1,39 +0,0 @@
name: Setup Android Emulator
inputs:
api-level:
description: 'API level to use for the emulator'
required: true
default: '29'
runs:
using: "composite"
steps:
- name: Enable KVM
shell: bash
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Gradle cache
uses: gradle/actions/setup-gradle@v4
- name: AVD cache
uses: useblacksmith/cache@v5
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ inputs.api-level }}
- name: Create AVD and Generate Snapshot for Caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ inputs.api-level }}
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
disable-animations: false
script: echo "Generated AVD snapshot for caching."

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: jobs:
build-examples: build-examples:
runs-on: blacksmith-4vcpu-ubuntu-2204 runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
example: [ example: [
@@ -19,16 +19,40 @@ jobs:
"pets", "pets",
"reactions", "reactions",
"todo", "todo",
"onboarding",
] ]
steps: steps:
- name: Checkout - uses: actions/checkout@v3
uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Setup Source Code - name: Enable corepack
uses: ./.github/actions/source-code/ 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 - name: Pnpm Build
run: | run: |

View File

@@ -2,22 +2,48 @@ name: Build Starters
on: on:
push: push:
branches: ["main"] branches: [ "main" ]
jobs: jobs:
build-starters: build-starters:
runs-on: blacksmith-4vcpu-ubuntu-2204 runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
starter: ["react-passkey-auth"] starter: [
"react-demo-auth-tailwind",
]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Setup Source Code - name: Enable corepack
uses: ./.github/actions/source-code/ 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 - name: Pnpm Build
run: | run: |

View File

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

View File

@@ -1,85 +0,0 @@
name: End-to-End Tests for React Native
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- ".github/actions/android-emulator/**"
- ".github/actions/source-code/**"
- ".github/workflows/e2e-rn-test.yml"
- "examples/chat-rn/**"
- "examples/chat-rn-clerk/**"
- "packages/**"
jobs:
e2e-tests:
runs-on: blacksmith-4vcpu-ubuntu-2204
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: Setup JDK
uses: actions/setup-java@v4
with:
distribution: corretto
java-version: 22
cache: gradle
- name: Pnpm Build
run: pnpm turbo build --filter="./packages/*"
- name: chat-rn App Pre Build
working-directory: ./examples/chat-rn
run: |
pnpm build
pnpm expo prebuild --clean
- name: Install Maestro
run: |
curl -fsSL "https://get.maestro.mobile.dev" | bash
- name: Setup Android Emulator
id: android-emulator
uses: ./.github/actions/android-emulator/
with:
api-level: 29
- name: Test App
uses: reactivecircus/android-emulator-runner@v2
id: e2e_test
continue-on-error: true
with:
api-level: 29
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
disable-animations: true
working-directory: ./examples/chat-rn/
script: ./test/e2e/run.sh
- name: Copy Maestro Output
if: steps.e2e_test.outcome != 'success'
run: |
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: jobs:
test: test:
runs-on: blacksmith-4vcpu-ubuntu-2204 runs-on: ubuntu-latest
timeout-minutes: 5 timeout-minutes: 5
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Setup Source Code - name: Enable corepack
uses: ./.github/actions/source-code/ 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 - name: Build jazz-run
run: pnpm exec turbo build && chmod +x dist/index.js; run: pnpm exec turbo build && chmod +x dist/index.js;
@@ -26,3 +48,4 @@ jobs:
- name: Run create account - name: Run create account
run: ./dist/index.js account create --name "Jazz Run CI test" run: ./dist/index.js account create --name "Jazz Run CI test"
working-directory: ./packages/jazz-run working-directory: ./packages/jazz-run

View File

@@ -9,19 +9,41 @@ on:
jobs: jobs:
test: test:
timeout-minutes: 60 timeout-minutes: 60
runs-on: blacksmith-4vcpu-ubuntu-2204 runs-on: ubuntu-latest
continue-on-error: true continue-on-error: true
strategy: strategy:
matrix: matrix:
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "starters/react-passkey-auth"] project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "examples/onboarding", "starters/react-demo-auth-tailwind"]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Setup Source Code - name: Enable corepack
uses: ./.github/actions/source-code/ 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 - name: Pnpm Build
run: pnpm turbo build run: pnpm turbo build

View File

@@ -1,102 +0,0 @@
name: Pre-Publish tagged Pull Requests
on:
pull_request:
types: [opened, synchronize, reopened, labeled]
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,16 +17,35 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs: jobs:
release: release:
name: Release name: Release
runs-on: blacksmith-4vcpu-ubuntu-2204 runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Setup Source Code - name: Enable corepack
uses: ./.github/actions/source-code/ run: corepack enable
- name: Build packages - name: Install Node.js
run: pnpm exec turbo run build --filter='./packages/*' 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 - name: Create Release Pull Request or Publish to npm
id: changesets id: changesets

View File

@@ -9,20 +9,39 @@ on:
jobs: jobs:
unit-tests: unit-tests:
runs-on: blacksmith-4vcpu-ubuntu-2204 runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Source Code - name: Enable corepack
uses: ./.github/actions/source-code/ 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 - name: Pnpm Build
run: pnpm turbo build --filter="./packages/*" run: pnpm turbo build --filter="./packages/*"
- name: Install Playwright Browsers
run: pnpm exec playwright install
- name: Unit Tests - name: Unit Tests
run: pnpm test:ci run: pnpm test:ci

6
.gitignore vendored
View File

@@ -7,15 +7,11 @@ docsTmp
coverage coverage
.direnv .direnv
# Typescript
**/*.tsbuildinfo
# Next.js # Next.js
**/.next **/.next
# Vite output # Vite output
**/dist **/dist
__screenshots__
# Playwright # Playwright
test-results test-results
@@ -23,5 +19,3 @@ test-results
.husky .husky
.vscode/settings.json .vscode/settings.json
.svelte-kit

8
.idea/.gitignore generated vendored
View File

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

View File

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

8
.idea/jazz.iml generated
View File

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

8
.idea/modules.xml generated
View File

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

19
.idea/php.xml generated
View File

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

6
.idea/prettier.xml generated
View File

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

6
.idea/vcs.xml generated
View File

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

View File

@@ -36,7 +36,7 @@ We welcome all ideas! If you have suggestions, feel free to open an issue marked
### 5. Local Setup ### 5. Local Setup
You'll need Node.js 22.x installed (we're working on support for 23.x), and pnpm 9.x installed. If you're using nix, run `nix develop` to get a shell with the correct versions of everything installed. You'll need Node.js 20.x or 22.x installed (we're working on support for 23.x), and pnpm 9.x installed. If you're using nix, run `nix develop` to get a shell with the correct versions of everything installed.
1. **Clone the repository**: 1. **Clone the repository**:
```bash ```bash
@@ -48,25 +48,7 @@ You'll need Node.js 22.x installed (we're working on support for 23.x), and pnpm
pnpm install pnpm install
``` ```
3. **Install homepage dependencies**: 3. **Run tests** to verify everything is working:
```bash
cd homepage && pnpm install
```
4. **Go back to the project root**:
```bash
cd ..
```
4. **Build the packages**:
```bash
pnpm build
```
5. **Run tests** to verify everything is working:
```bash ```bash
pnpm test pnpm test
``` ```

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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

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) - Community & support: [Discord](https://discord.gg/utDMjHYg42)
- Updates: [X](https://x.com/jazz_tools) & [Email](https://garden.co/news) - Updates: [X](https://x.com/jazz_tools) & [Email](https://garden.co/news)
Copyright 2025 &mdash; Garden Computing, Inc. Copyright 2024 &mdash; Garden Computing, Inc.

View File

@@ -12,9 +12,7 @@
"**/ios/**", "**/ios/**",
"**/android/**", "**/android/**",
"packages/jazz-svelte/**", "packages/jazz-svelte/**",
"examples/*svelte*/**", "examples/*svelte*/**"
"homepage/homepage/**",
"**/package.json"
] ]
}, },
"formatter": { "formatter": {
@@ -44,6 +42,15 @@
} }
}, },
"overrides": [ "overrides": [
{
"include": ["**/package.json"],
"linter": {
"enabled": false
},
"formatter": {
"enabled": false
}
},
{ {
"include": ["packages/**/src/**"], "include": ["packages/**/src/**"],
"linter": { "linter": {
@@ -54,24 +61,21 @@
} }
}, },
{ {
"include": ["packages/cojson-storage*/**", "cojson-transport-ws/**"], "include": ["packages/**/src/tests/**", "packages/**/src/test/**"],
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
},
{
"include": ["packages/**/src/tests/**"],
"linter": { "linter": {
"rules": { "rules": {
"correctness": { "correctness": {
"useImportExtensions": "off" "useImportExtensions": "off"
}
}
}
}, },
"style": { {
"noNonNullAssertion": "off" "include": ["packages/cojson-storage-indexeddb/**"],
}, "linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": { "suspicious": {
"noExplicitAny": "info" "noExplicitAny": "info"
} }

View File

@@ -1,284 +1,5 @@
# chat-rn-clerk # chat-rn-clerk
## 1.0.91
### Patch Changes
- jazz-react-native@0.12.1
- jazz-react-native-auth-clerk@0.12.1
- jazz-tools@0.12.1
- jazz-react-native-media-images@0.12.1
## 1.0.90
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react-native@0.12.0
- jazz-react-native-auth-clerk@0.12.0
- jazz-react-native-media-images@0.12.0
## 1.0.89
### Patch Changes
- jazz-react-native@0.11.8
- jazz-react-native-auth-clerk@0.11.8
- jazz-tools@0.11.8
- jazz-react-native-media-images@0.11.8
## 1.0.88
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react-native@0.11.7
- jazz-react-native-auth-clerk@0.11.7
- jazz-react-native-media-images@0.11.7
## 1.0.87
### Patch Changes
- 1bfa9bb: Removed when="singedUp" from examples apps' Jazz providers. This is a really niche use-case option and can lead to broken-feeling experiences when anonymous users try to load something.
- Updated dependencies [e7c85b7]
- jazz-react-native@0.11.6
- jazz-tools@0.11.6
- jazz-react-native-auth-clerk@0.11.6
- jazz-react-native-media-images@0.11.6
## 1.0.86
### Patch Changes
- jazz-react-native@0.11.5
- jazz-react-native-auth-clerk@0.11.5
- jazz-tools@0.11.5
- jazz-react-native-media-images@0.11.5
## 1.0.85
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react-native@0.11.4
- jazz-react-native-auth-clerk@0.11.4
- jazz-react-native-media-images@0.11.4
## 1.0.84
### Patch Changes
- jazz-react-native@0.11.3
- jazz-react-native-auth-clerk@0.11.3
- jazz-tools@0.11.3
- jazz-react-native-media-images@0.11.3
## 1.0.83
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react-native@0.11.2
- jazz-react-native-auth-clerk@0.11.2
- jazz-react-native-media-images@0.11.2
## 1.0.82
### Patch Changes
- jazz-react-native@0.11.1
- jazz-react-native-auth-clerk@0.11.1
## 1.0.81
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-react-native-media-images@0.11.0
- jazz-react-native-auth-clerk@0.11.0
- jazz-react-native@0.11.0
## 1.0.80
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react-native@0.10.15
- jazz-react-native-auth-clerk@0.10.15
- jazz-react-native-media-images@0.10.15
## 1.0.79
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react-native@0.10.14
- jazz-react-native-auth-clerk@0.10.14
- jazz-react-native-media-images@0.10.14
## 1.0.78
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react-native@0.10.13
- jazz-react-native-auth-clerk@0.10.13
- jazz-react-native-media-images@0.10.13
## 1.0.77
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react-native@0.10.12
- jazz-react-native-auth-clerk@0.10.12
- jazz-react-native-media-images@0.10.12
## 1.0.76
### Patch Changes
- Updated dependencies [5a54e4a]
- jazz-react-native@0.10.11
- jazz-react-native-auth-clerk@0.10.11
## 1.0.75
### Patch Changes
- Updated dependencies [3405d8f]
- jazz-react-native@0.10.10
- jazz-react-native-auth-clerk@0.10.10
## 1.0.74
### Patch Changes
- jazz-react-native-auth-clerk@0.10.9
## 1.0.73
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react-native@0.10.8
- jazz-react-native-auth-clerk@0.10.8
- jazz-react-native-media-images@0.10.8
## 1.0.72
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react-native@0.10.7
- jazz-tools@0.10.7
- jazz-react-native-auth-clerk@0.10.7
- jazz-react-native-media-images@0.10.7
## 1.0.71
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-react-native@0.10.6
- jazz-react-native-auth-clerk@0.10.6
- jazz-react-native-media-images@0.10.6
## 1.0.70
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react-native@0.10.5
- jazz-react-native-auth-clerk@0.10.5
- jazz-react-native-media-images@0.10.5
## 1.0.69
### Patch Changes
- jazz-react-native@0.10.4
- jazz-react-native-auth-clerk@0.10.4
- jazz-tools@0.10.4
- jazz-react-native-media-images@0.10.4
## 1.0.68
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react-native@0.10.3
- jazz-react-native-auth-clerk@0.10.3
- jazz-react-native-media-images@0.10.3
## 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
### 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 ## 1.0.63
### Patch Changes ### Patch Changes

View File

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

View File

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

View File

@@ -1,6 +1,5 @@
import "../global.css"; import "../global.css";
import { ClerkLoaded, ClerkProvider } from "@clerk/clerk-expo"; import { ClerkLoaded, ClerkProvider } from "@clerk/clerk-expo";
import { secureStore } from "@clerk/clerk-expo/secure-store";
import { useFonts } from "expo-font"; import { useFonts } from "expo-font";
import { Slot } from "expo-router"; import { Slot } from "expo-router";
import * as SplashScreen from "expo-splash-screen"; import * as SplashScreen from "expo-splash-screen";
@@ -34,11 +33,7 @@ export default function RootLayout() {
} }
return ( return (
<ClerkProvider <ClerkProvider tokenCache={tokenCache} publishableKey={publishableKey}>
tokenCache={tokenCache}
publishableKey={publishableKey}
__experimental_resourceCache={secureStore}
>
<ClerkLoaded> <ClerkLoaded>
<JazzAndAuth> <JazzAndAuth>
<Slot /> <Slot />

View File

@@ -28,7 +28,7 @@ export default function Conversation() {
const { me } = useAccount(); const { me } = useAccount();
const [chat, setChat] = useState<Chat>(); const [chat, setChat] = useState<Chat>();
const [message, setMessage] = useState(""); const [message, setMessage] = useState("");
const loadedChat = useCoState(Chat, chat?.id, { resolve: { $each: true } }); const loadedChat = useCoState(Chat, chat?.id, [{}]);
const navigation = useNavigation(); const navigation = useNavigation();
const [isUploading, setIsUploading] = useState(false); const [isUploading, setIsUploading] = useState(false);
@@ -71,7 +71,7 @@ export default function Conversation() {
const loadChat = async (chatId: ID<Chat>) => { const loadChat = async (chatId: ID<Chat>) => {
try { try {
const chat = await Chat.load(chatId, me); const chat = await Chat.load(chatId, me, []);
setChat(chat); setChat(chat);
} catch (error) { } catch (error) {
console.log("Error loading chat", error); console.log("Error loading chat", error);

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
{ {
"name": "chat-rn-clerk", "name": "chat-rn-clerk",
"main": "index.js", "main": "index.js",
"version": "1.0.91", "version": "1.0.63",
"scripts": { "scripts": {
"build": "expo export -p ios", "build": "expo export -p ios",
"start": "expo start", "start": "expo start",
@@ -9,22 +9,23 @@
"format-and-lint:fix": "biome check . --write", "format-and-lint:fix": "biome check . --write",
"android": "expo run:android", "android": "expo run:android",
"ios": "expo run:ios", "ios": "expo run:ios",
"web": "expo start --web" "web": "expo start --web",
"test": "jest --watchAll"
}, },
"jest": { "jest": {
"preset": "jest-expo" "preset": "jest-expo"
}, },
"dependencies": { "dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2", "@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0",
"@bam.tech/react-native-image-resizer": "^3.0.11", "@bam.tech/react-native-image-resizer": "^3.0.11",
"@craftzdog/react-native-buffer": "6.0.5",
"@clerk/clerk-expo": "^2.2.21", "@clerk/clerk-expo": "^2.2.21",
"@expo/vector-icons": "^14.0.2", "@expo/vector-icons": "^14.0.2",
"@op-engineering/op-sqlite": "^11.2.12", "@op-engineering/op-sqlite": "^11.2.12",
"@react-native-community/netinfo": "^11.4.1", "@react-native-community/netinfo": "^11.4.1",
"@react-navigation/native": "^7.0.13", "@react-navigation/native": "^7.0.13",
"@react-navigation/native-stack": "^7.1.14", "@react-navigation/native-stack": "^7.1.14",
"base-64": "^1.0.0",
"buffer": "^6.0.3",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"expo": "^52.0.0", "expo": "^52.0.0",
"expo-build-properties": "~0.13.1", "expo-build-properties": "~0.13.1",
@@ -50,14 +51,18 @@
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-native": "~0.76.3", "react-native": "~0.76.3",
"react-native-fetch-api": "^3.0.0",
"react-native-gesture-handler": "~2.20.2", "react-native-gesture-handler": "~2.20.2",
"react-native-get-random-values": "^1.11.0", "react-native-get-random-values": "^1.11.0",
"react-native-polyfill-globals": "^3.1.0",
"react-native-quick-base64": "^2.1.2",
"react-native-reanimated": "~3.16.3", "react-native-reanimated": "~3.16.3",
"react-native-safe-area-context": "4.12.0", "react-native-safe-area-context": "4.12.0",
"react-native-screens": "4.1.0", "react-native-screens": "4.1.0",
"react-native-url-polyfill": "^2.0.0", "react-native-url-polyfill": "^2.0.0",
"react-native-web": "~0.19.13", "react-native-web": "~0.19.13",
"readable-stream": "4.7.0" "text-encoding": "^0.7.0",
"web-streams-polyfill": "^3.2.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",
@@ -67,7 +72,7 @@
"jest": "^29.2.1", "jest": "^29.2.1",
"jest-expo": "~52.0.2", "jest-expo": "~52.0.2",
"react-test-renderer": "18.2.0", "react-test-renderer": "18.2.0",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.15",
"typescript": "~5.6.2" "typescript": "~5.6.2"
}, },
"private": true "private": true

View File

@@ -1,17 +1,8 @@
/* eslint-disable import/order */ import "react-native-polyfill-globals/auto";
// @ts-expect-error - @types/react-native doesn't cover this file
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { Buffer } from "@craftzdog/react-native-buffer";
polyfillGlobal("Buffer", () => Buffer);
// @ts-expect-error - @types/readable-stream doesn't have ReadableStream type
import { ReadableStream } from "readable-stream";
polyfillGlobal("ReadableStream", () => ReadableStream);
import "@azure/core-asynciterator-polyfill"; import "@azure/core-asynciterator-polyfill";
import { Buffer } from "buffer";
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
import "@bacons/text-decoder/install"; polyfillGlobal("Buffer", () => Buffer);
polyfillGlobal("ReadableStream", () => ReadableStream);
import "react-native-get-random-values";

View File

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

View File

@@ -1,20 +1,49 @@
import { useClerk } from "@clerk/clerk-expo"; import { useClerk, useUser } from "@clerk/clerk-expo";
import { JazzProviderWithClerk } from "jazz-react-native-auth-clerk"; import { JazzProvider, setupKvStore } from "jazz-react-native";
import React, { PropsWithChildren } from "react"; import { useJazzClerkAuth } from "jazz-react-native-auth-clerk";
import { apiKey } from "./apiKey"; import React, { createContext, PropsWithChildren, useContext } 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) { export function JazzAndAuth({ children }: PropsWithChildren) {
const { isSignedIn, isLoaded: isClerkLoaded } = useUser();
const clerk = useClerk(); const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk, kvStore);
const isAuthenticated = Boolean(isSignedIn && isClerkLoaded && auth);
return ( return (
<JazzProviderWithClerk <AuthContext.Provider
clerk={clerk} value={{ isAuthenticated, isLoading: !isClerkLoaded || !auth }}
>
{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" storage="sqlite"
sync={{ peer="wss://cloud.jazz.tools/?key=chat-rn-clerk-example-jazz@garden.co"
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
> >
{children} {children}
</JazzProviderWithClerk> </JazzProvider>
) : (
children
)}
</AuthContext.Provider>
); );
} }

View File

@@ -1,226 +1,5 @@
# chat-rn # chat-rn
## 1.0.87
### Patch Changes
- jazz-react-native@0.12.1
- jazz-tools@0.12.1
## 1.0.86
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react-native@0.12.0
## 1.0.85
### Patch Changes
- jazz-react-native@0.11.8
- jazz-tools@0.11.8
## 1.0.84
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react-native@0.11.7
## 1.0.83
### Patch Changes
- Updated dependencies [e7c85b7]
- jazz-react-native@0.11.6
- jazz-tools@0.11.6
## 1.0.82
### Patch Changes
- jazz-react-native@0.11.5
- jazz-tools@0.11.5
## 1.0.81
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react-native@0.11.4
## 1.0.80
### Patch Changes
- jazz-react-native@0.11.3
- jazz-tools@0.11.3
## 1.0.79
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react-native@0.11.2
## 1.0.78
### Patch Changes
- jazz-react-native@0.11.1
## 1.0.77
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-react-native@0.11.0
## 1.0.76
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react-native@0.10.15
## 1.0.75
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react-native@0.10.14
## 1.0.74
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react-native@0.10.13
## 1.0.73
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react-native@0.10.12
## 1.0.72
### Patch Changes
- Updated dependencies [5a54e4a]
- jazz-react-native@0.10.11
## 1.0.71
### Patch Changes
- Updated dependencies [3405d8f]
- jazz-react-native@0.10.10
## 1.0.70
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react-native@0.10.8
## 1.0.69
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react-native@0.10.7
- jazz-tools@0.10.7
## 1.0.68
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-react-native@0.10.6
## 1.0.67
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react-native@0.10.5
## 1.0.66
### Patch Changes
- jazz-react-native@0.10.4
- jazz-tools@0.10.4
## 1.0.65
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react-native@0.10.3
## 1.0.64
### Patch Changes
- jazz-react-native@0.10.2
- jazz-tools@0.10.2
## 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 ## 1.0.60
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,6 +1,6 @@
{ {
"name": "chat-rn", "name": "chat-rn",
"version": "1.0.87", "version": "1.0.60",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"build": "expo export -p ios", "build": "expo export -p ios",
@@ -13,17 +13,17 @@
}, },
"dependencies": { "dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2", "@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0",
"@craftzdog/react-native-buffer": "6.0.5",
"@op-engineering/op-sqlite": "^11.2.12", "@op-engineering/op-sqlite": "^11.2.12",
"@react-native-community/netinfo": "^11.4.1", "@react-native-community/netinfo": "^11.4.1",
"@react-navigation/native": "^7.0.13", "@react-navigation/native": "^7.0.13",
"@react-navigation/native-stack": "^7.1.14", "@react-navigation/native-stack": "^7.1.14",
"base-64": "^1.0.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"expo": "^52.0.0", "expo": "^52.0.0",
"expo-build-properties": "~0.13.1", "expo-build-properties": "~0.13.1",
"expo-clipboard": "~7.0.0", "expo-clipboard": "~7.0.0",
"expo-constants": "~17.0.3", "expo-constants": "~17.0.3",
"expo-crypto": "~14.0.1",
"expo-dev-client": "~5.0.5", "expo-dev-client": "~5.0.5",
"expo-linking": "~7.0.3", "expo-linking": "~7.0.3",
"expo-secure-store": "~14.0.0", "expo-secure-store": "~14.0.0",
@@ -34,16 +34,19 @@
"nativewind": "^4.1.21", "nativewind": "^4.1.21",
"react": "^18.3.1", "react": "^18.3.1",
"react-native": "~0.76.3", "react-native": "~0.76.3",
"react-native-fetch-api": "^3.0.0",
"react-native-get-random-values": "^1.11.0", "react-native-get-random-values": "^1.11.0",
"react-native-polyfill-globals": "^3.1.0",
"react-native-safe-area-context": "4.12.0", "react-native-safe-area-context": "4.12.0",
"react-native-screens": "4.1.0", "react-native-screens": "4.1.0",
"react-native-url-polyfill": "^2.0.0", "react-native-url-polyfill": "^2.0.0",
"readable-stream": "4.7.0" "text-encoding": "^0.7.0",
"web-streams-polyfill": "^3.2.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.15",
"typescript": "~5.6.2" "typescript": "~5.6.2"
}, },
"private": true "private": true

View File

@@ -1,17 +1,6 @@
/* eslint-disable import/order */ import "react-native-polyfill-globals/auto";
// @ts-expect-error - @types/react-native doesn't cover this file
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { Buffer } from "@craftzdog/react-native-buffer";
polyfillGlobal("Buffer", () => Buffer);
// @ts-expect-error - @types/readable-stream doesn't have ReadableStream type
import { ReadableStream } from "readable-stream";
polyfillGlobal("ReadableStream", () => ReadableStream);
import "@azure/core-asynciterator-polyfill"; import "@azure/core-asynciterator-polyfill";
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
import "@bacons/text-decoder/install"; polyfillGlobal("ReadableStream", () => ReadableStream);
import "react-native-get-random-values";

View File

@@ -9,8 +9,7 @@ import * as Linking from "expo-linking";
import React, { StrictMode, useEffect, useState } from "react"; import React, { StrictMode, useEffect, useState } from "react";
import HandleInviteScreen from "./invite"; import HandleInviteScreen from "./invite";
import { JazzProvider } from "jazz-react-native"; import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react-native";
import { apiKey } from "./apiKey";
import ChatScreen from "./chat"; import ChatScreen from "./chat";
const Stack = createNativeStackNavigator(); const Stack = createNativeStackNavigator();
@@ -29,6 +28,7 @@ const linking = {
}; };
function App() { function App() {
const [auth, state] = useDemoAuth();
const [initialRoute, setInitialRoute] = useState< const [initialRoute, setInitialRoute] = useState<
"ChatScreen" | "HandleInviteScreen" "ChatScreen" | "HandleInviteScreen"
>("ChatScreen"); >("ChatScreen");
@@ -43,13 +43,16 @@ function App() {
}); });
}, []); }, []);
if (!auth) {
return null;
}
return ( return (
<StrictMode> <StrictMode>
<JazzProvider <JazzProvider
auth={auth}
storage="sqlite" storage="sqlite"
sync={{ peer="wss://cloud.jazz.tools/?key=chat-rn-example-jazz@garden.co"
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
> >
<NavigationContainer linking={linking} ref={navigationRef}> <NavigationContainer linking={linking} ref={navigationRef}>
<Stack.Navigator initialRouteName={initialRoute}> <Stack.Navigator initialRouteName={initialRoute}>
@@ -66,6 +69,9 @@ function App() {
</Stack.Navigator> </Stack.Navigator>
</NavigationContainer> </NavigationContainer>
</JazzProvider> </JazzProvider>
{state.state !== "signedIn" ? (
<DemoAuthBasicUI appName="Jazz Chat" state={state} />
) : null}
</StrictMode> </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 clsx from "clsx";
import * as Clipboard from "expo-clipboard"; 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 { useEffect, useState } from "react";
import React, { import React, {
Button, Button,
@@ -20,18 +20,12 @@ import { Chat, Message } from "./schema";
export default function ChatScreen({ navigation }: { navigation: any }) { export default function ChatScreen({ navigation }: { navigation: any }) {
const { me, logOut } = useAccount(); const { me, logOut } = useAccount();
const [chatId, setChatId] = useState<ID<Chat>>(); const [chatId, setChatId] = useState<ID<Chat>>();
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } }); const loadedChat = useCoState(Chat, chatId, [{}]);
const [message, setMessage] = useState(""); const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});
function handleLogOut() {
setChatId(undefined);
logOut();
}
useEffect(() => { useEffect(() => {
navigation.setOptions({ navigation.setOptions({
headerRight: () => <Button onPress={handleLogOut} title="Logout" />, headerRight: () => <Button onPress={logOut} title="Logout" />,
headerLeft: () => headerLeft: () =>
loadedChat ? ( loadedChat ? (
<Button <Button
@@ -137,19 +131,6 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
<View className="flex flex-col h-full"> <View className="flex flex-col h-full">
{!loadedChat ? ( {!loadedChat ? (
<View className="flex flex-col h-full items-center justify-center"> <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 <TouchableOpacity
onPress={createChat} onPress={createChat}
className="bg-blue-500 p-4 rounded-md" className="bg-blue-500 p-4 rounded-md"
@@ -191,12 +172,10 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
placeholder="Type a message..." placeholder="Type a message..."
textAlignVertical="center" textAlignVertical="center"
onSubmitEditing={sendMessage} onSubmitEditing={sendMessage}
testID="message-input"
/> />
<TouchableOpacity <TouchableOpacity
onPress={sendMessage} onPress={sendMessage}
className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center" className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center"
testID="send-button"
> >
<Text></Text> <Text></Text>
</TouchableOpacity> </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,50 +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
- tapOn:
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"
# This doesn't work on CI, maybe because Android has a different alert dialog
# - tapOn: "Join chat"
# - inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
# - pressKey: "enter"
# - assertVisible: "boorad"
# - assertVisible: "bro, low key, it do be like that tho"

View File

@@ -1,20 +0,0 @@
#!/bin/bash
# This script is necessary, because unlike ios, the android emulator action
# accepts a script, runs it as your tests, then terminates.
set -e
# build and install the app
echo "Building and installing Android app."
echo "If it fails, its output will be in artifact: android-install.log..."
cd ./android/
./gradlew installRelease >> ~/output/android-install.log 2>&1
cd ..
# run the e2e tests
export PATH="$PATH":"$HOME/.maestro/bin"
export MAESTRO_DRIVER_STARTUP_TIMEOUT=300000 # setting to 5 mins 👀
export MAESTRO_CLI_NO_ANALYTICS=1
export MAESTRO_CLI_ANALYSIS_NOTIFICATION_DISABLED=true
maestro test test/e2e/flow.yml

View File

@@ -1,242 +1,5 @@
# chat-vue # chat-vue
## 0.0.72
### Patch Changes
- jazz-browser@0.12.1
- jazz-tools@0.12.1
- jazz-vue@0.12.1
## 0.0.71
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [4c01459]
- jazz-tools@0.12.0
- jazz-vue@0.12.0
- jazz-browser@0.12.0
## 0.0.70
### Patch Changes
- jazz-browser@0.11.8
- jazz-tools@0.11.8
- jazz-vue@0.11.8
## 0.0.69
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-browser@0.11.7
- jazz-vue@0.11.7
## 0.0.68
### Patch Changes
- Updated dependencies [e7c85b7]
- jazz-tools@0.11.6
- jazz-vue@0.11.6
- jazz-browser@0.11.6
## 0.0.67
### Patch Changes
- jazz-browser@0.11.5
- jazz-tools@0.11.5
- jazz-vue@0.11.5
## 0.0.66
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-browser@0.11.4
- jazz-vue@0.11.4
## 0.0.65
### Patch Changes
- jazz-browser@0.11.3
- jazz-tools@0.11.3
- jazz-vue@0.11.3
## 0.0.64
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-browser@0.11.2
- jazz-vue@0.11.2
## 0.0.63
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [18428ea]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-browser@0.11.0
- jazz-vue@0.11.0
## 0.0.62
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-browser@0.10.15
- jazz-vue@0.10.15
## 0.0.61
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-browser@0.10.14
- jazz-vue@0.10.14
## 0.0.60
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser@0.10.13
- jazz-vue@0.10.13
## 0.0.59
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-vue@0.10.12
- jazz-browser@0.10.12
## 0.0.58
### Patch Changes
- Updated dependencies [834203f]
- jazz-browser@0.10.9
- jazz-vue@0.10.9
## 0.0.57
### Patch Changes
- Updated dependencies [1e87fc7]
- Updated dependencies [2fb6428]
- jazz-browser@0.10.8
- jazz-tools@0.10.8
- jazz-vue@0.10.8
## 0.0.56
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [bf76d79]
- Updated dependencies [0eed228]
- jazz-browser@0.10.7
- jazz-tools@0.10.7
- jazz-vue@0.10.7
## 0.0.55
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-browser@0.10.6
- jazz-vue@0.10.6
## 0.0.54
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-browser@0.10.5
- jazz-vue@0.10.5
## 0.0.53
### Patch Changes
- jazz-browser@0.10.4
- jazz-tools@0.10.4
- jazz-vue@0.10.4
## 0.0.52
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-browser@0.10.3
- jazz-vue@0.10.3
## 0.0.51
### Patch Changes
- jazz-browser@0.10.2
- jazz-tools@0.10.2
- jazz-vue@0.10.2
## 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 ## 0.0.47
### Patch Changes ### Patch Changes

View File

@@ -11,12 +11,12 @@ You can either
Create a new Jazz project, and use this example as a template. Create a new Jazz project, and use this example as a template.
```bash ```bash
npx create-jazz-app@latest chat-vue-app --example chat-vue npx create-jazz-app@latest --example chat-vue --project-name chat-vue
``` ```
Go to the new project directory. Go to the new project directory.
```bash ```bash
cd chat-vue-app cd chat-vue
``` ```
Run the dev server. Run the dev server.

View File

@@ -1,6 +1,6 @@
{ {
"name": "chat-vue", "name": "chat-vue",
"version": "0.0.72", "version": "0.0.47",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
@@ -30,9 +30,9 @@
"eslint-plugin-vue": "^9.28.0", "eslint-plugin-vue": "^9.28.0",
"npm-run-all2": "^6.2.3", "npm-run-all2": "^6.2.3",
"postcss": "^8.4.27", "postcss": "^8.4.27",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.15",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"vite": "^6.0.11", "vite": "^5.4.10",
"vite-plugin-vue-devtools": "^7.4.6", "vite-plugin-vue-devtools": "^7.4.6",
"vue-tsc": "^2.1.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 { createApp, defineComponent, h } from "vue";
import App from "./App.vue"; import App from "./App.vue";
import "./index.css"; import "./index.css";
import { apiKey } from "@/apiKey";
import router from "./router"; import router from "./router";
const RootComponent = defineComponent({ const RootComponent = defineComponent({
name: "RootComponent", name: "RootComponent",
setup() { setup() {
return () => const { authMethod, state } = useDemoAuth();
return () => [
h( h(
JazzProvider, JazzProvider,
{ {
sync: { auth: authMethod.value,
peer: `wss://cloud.jazz.tools/?key=${apiKey}`, 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

@@ -49,7 +49,7 @@ export default defineComponent({
}, },
}, },
setup(props) { setup(props) {
const chat = useCoState(Chat, props.chatId, { resolve: { $each: true } }); const chat = useCoState(Chat, props.chatId, [{}]);
const showNLastMessages = ref(30); const showNLastMessages = ref(30);
const displayedMessages = computed(() => { const displayedMessages = computed(() => {

View File

@@ -1,254 +1,5 @@
# jazz-example-chat # jazz-example-chat
## 0.0.169
### Patch Changes
- jazz-inspector@0.12.1
- jazz-react@0.12.1
- jazz-tools@0.12.1
## 0.0.168
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [9a56bb3]
- jazz-tools@0.12.0
- jazz-inspector@0.12.0
- jazz-react@0.12.0
## 0.0.167
### Patch Changes
- Updated dependencies [71b9390]
- jazz-inspector@0.11.8
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.166
### Patch Changes
- Updated dependencies [2c3761c]
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-inspector@0.11.7
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.165
### Patch Changes
- Updated dependencies [e7c85b7]
- Updated dependencies [09f0a98]
- Updated dependencies [11da4d1]
- Updated dependencies [8ed144e]
- jazz-react@0.11.6
- jazz-tools@0.11.6
- jazz-inspector@0.11.6
- jazz-browser-media-images@0.11.6
## 0.0.164
### Patch Changes
- jazz-react@0.11.5
- jazz-tools@0.11.5
- jazz-browser-media-images@0.11.5
## 0.0.163
### Patch Changes
- 2074e45: In the chat app example, show a "Message not readable" placeholder, if messages from a chat list are not readable by the user.
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-browser-media-images@0.11.4
- jazz-react@0.11.4
## 0.0.162
### Patch Changes
- jazz-react@0.11.3
- jazz-tools@0.11.3
- jazz-browser-media-images@0.11.3
## 0.0.161
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react@0.11.2
- jazz-browser-media-images@0.11.2
## 0.0.160
### Patch Changes
- jazz-react@0.11.1
## 0.0.159
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-browser-media-images@0.11.0
- jazz-react@0.11.0
## 0.0.158
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-browser-media-images@0.10.15
- jazz-react@0.10.15
## 0.0.157
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
- jazz-browser-media-images@0.10.14
## 0.0.156
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.155
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.154
### Patch Changes
- jazz-browser-media-images@0.10.9
- jazz-react@0.10.9
## 0.0.153
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
- jazz-browser-media-images@0.10.8
## 0.0.152
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react@0.10.7
- jazz-tools@0.10.7
- jazz-browser-media-images@0.10.7
## 0.0.151
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- hash-slash@0.2.2
- jazz-react@0.10.6
- jazz-tools@0.10.6
- jazz-browser-media-images@0.10.6
## 0.0.150
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-browser-media-images@0.10.5
- jazz-react@0.10.5
## 0.0.149
### Patch Changes
- jazz-react@0.10.4
- jazz-tools@0.10.4
- jazz-browser-media-images@0.10.4
## 0.0.148
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-browser-media-images@0.10.3
- jazz-react@0.10.3
## 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
### 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 ## 0.0.143
### Patch Changes ### Patch Changes

View File

@@ -13,12 +13,12 @@ You can either
Create a new Jazz project, and use this example as a template. Create a new Jazz project, and use this example as a template.
```bash ```bash
npx create-jazz-app@latest chat-app --example chat npx create-jazz-app@latest --example chat --project-name chat
``` ```
Go to the new project directory. Go to the new project directory.
```bash ```bash
cd chat-app cd chat
``` ```
Run the dev server. Run the dev server.

View File

@@ -1,7 +1,7 @@
{ {
"name": "jazz-example-chat", "name": "jazz-example-chat",
"private": true, "private": true,
"version": "0.0.169", "version": "0.0.143",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -9,13 +9,13 @@
"format-and-lint": "biome check .", "format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write", "format-and-lint:fix": "biome check . --write",
"preview": "vite preview", "preview": "vite preview",
"test:e2e": "playwright test", "test": "playwright test",
"test:e2e:ui": "playwright test --ui" "test:ui": "playwright test --ui"
}, },
"dependencies": { "dependencies": {
"clsx": "^2.0.0", "clsx": "^2.0.0",
"hash-slash": "workspace:*", "hash-slash": "workspace:*",
"jazz-inspector": "workspace:*", "jazz-browser-media-images": "workspace:*",
"jazz-react": "workspace:*", "jazz-react": "workspace:*",
"jazz-tools": "workspace:*", "jazz-tools": "workspace:*",
"lucide-react": "^0.274.0", "lucide-react": "^0.274.0",
@@ -23,15 +23,15 @@
"react-dom": "^18.3.1" "react-dom": "^18.3.1"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.50.1", "@playwright/test": "^1.46.1",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1", "@types/react-dom": "^18.3.1",
"@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",
"postcss": "^8.4.27", "postcss": "^8.4.27",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.15",
"typescript": "~5.6.2", "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,12 +1,11 @@
import { apiKey } from "@/apiKey.ts"; import { inIframe, onChatLoad } from "@/util.ts";
import { getRandomUsername, inIframe, onChatLoad } from "@/util.ts";
import { useIframeHashRouter } from "hash-slash"; import { useIframeHashRouter } from "hash-slash";
import { JazzInspector } from "jazz-inspector"; import { useAccount } from "jazz-react";
import { JazzProvider, useAccount } from "jazz-react";
import { Group, ID } from "jazz-tools"; import { Group, ID } from "jazz-tools";
import { StrictMode } from "react"; import { StrictMode } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import { ChatScreen } from "./chatScreen.tsx"; import { ChatScreen } from "./chatScreen.tsx";
import { JazzAndAuth } from "./jazz.tsx";
import { Chat } from "./schema.ts"; import { Chat } from "./schema.ts";
import { ThemeProvider } from "./themeProvider.tsx"; import { ThemeProvider } from "./themeProvider.tsx";
import { AppContainer, TopBar } from "./ui.tsx"; import { AppContainer, TopBar } from "./ui.tsx";
@@ -29,16 +28,7 @@ export function App() {
return ( return (
<AppContainer> <AppContainer>
<TopBar> <TopBar>
<input <p>{me?.profile?.name}</p>
type="text"
value={me?.profile?.name ?? ""}
className="bg-transparent"
onChange={(e) => {
if (!me?.profile) return;
me.profile.name = e.target.value;
}}
placeholder="Set username"
/>
{!inIframe && <button onClick={logOut}>Log out</button>} {!inIframe && <button onClick={logOut}>Log out</button>}
</TopBar> </TopBar>
{router.route({ {router.route({
@@ -49,21 +39,12 @@ export function App() {
); );
} }
const url = new URL(window.location.href);
const defaultProfileName = url.searchParams.get("user") ?? getRandomUsername();
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<ThemeProvider> <ThemeProvider>
<StrictMode> <StrictMode>
<JazzProvider <JazzAndAuth>
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
defaultProfileName={defaultProfileName}
>
<App /> <App />
<JazzInspector /> </JazzAndAuth>
</JazzProvider>
</StrictMode> </StrictMode>
</ThemeProvider>, </ThemeProvider>,
); );

View File

@@ -1,5 +1,6 @@
import { createImage, useAccount, useCoState } from "jazz-react"; import { createImage } from "jazz-browser-media-images";
import { Account, ID } from "jazz-tools"; import { useCoState } from "jazz-react";
import { ID } from "jazz-tools";
import { useState } from "react"; import { useState } from "react";
import { Chat, Message } from "./schema.ts"; import { Chat, Message } from "./schema.ts";
import { import {
@@ -16,8 +17,7 @@ import {
} from "./ui.tsx"; } from "./ui.tsx";
export function ChatScreen(props: { chatID: ID<Chat> }) { export function ChatScreen(props: { chatID: ID<Chat> }) {
const chat = useCoState(Chat, props.chatID, { resolve: { $each: true } }); const chat = useCoState(Chat, props.chatID, [{}]);
const account = useAccount();
const [showNLastMessages, setShowNLastMessages] = useState(30); const [showNLastMessages, setShowNLastMessages] = useState(30);
if (!chat) if (!chat)
@@ -47,7 +47,7 @@ export function ChatScreen(props: { chatID: ID<Chat> }) {
chat chat
.slice(-showNLastMessages) .slice(-showNLastMessages)
.reverse() // this plus flex-col-reverse on ChatBody gives us scroll-to-bottom behavior .reverse() // this plus flex-col-reverse on ChatBody gives us scroll-to-bottom behavior
.map((msg) => <ChatBubble me={account.me} msg={msg} key={msg.id} />) .map((msg) => <ChatBubble msg={msg} key={msg.id} />)
) : ( ) : (
<EmptyChatMessage /> <EmptyChatMessage />
)} )}
@@ -74,20 +74,7 @@ export function ChatScreen(props: { chatID: ID<Chat> }) {
); );
} }
function ChatBubble(props: { me: Account; msg: Message }) { function ChatBubble(props: { msg: Message }) {
if (!props.me.canRead(props.msg)) {
return (
<BubbleContainer fromMe={false}>
<BubbleBody fromMe={false}>
<BubbleText
text="Message not readable"
className="text-gray-500 italic"
/>
</BubbleBody>
</BubbleContainer>
);
}
const lastEdit = props.msg._edits.text; const lastEdit = props.msg._edits.text;
const fromMe = lastEdit.by?.isMe; const fromMe = lastEdit.by?.isMe;
const { text, image } = props.msg; const { text, image } = props.msg;

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 }) { export function AppContainer(props: { children: React.ReactNode }) {
return ( 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} {props.children}
</div> </div>
); );
@@ -14,7 +14,7 @@ export function AppContainer(props: { children: React.ReactNode }) {
export function TopBar(props: { children: React.ReactNode }) { export function TopBar(props: { children: React.ReactNode }) {
return ( 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} {props.children}
</div> </div>
); );
@@ -33,7 +33,7 @@ export function ChatBody(props: { children: React.ReactNode }) {
export function EmptyChatMessage() { export function EmptyChatMessage() {
return ( 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. Start a conversation below.
</div> </div>
); );
@@ -61,7 +61,7 @@ export function BubbleBody(props: {
"line-clamp-10 text-ellipsis whitespace-pre-wrap", "line-clamp-10 text-ellipsis whitespace-pre-wrap",
"rounded-2xl overflow-hidden max-w-[calc(100%-5rem)] shadow-sm p-1", "rounded-2xl overflow-hidden max-w-[calc(100%-5rem)] shadow-sm p-1",
props.fromMe props.fromMe
? "bg-white dark:bg-stone-900 dark:text-white" ? "bg-white dark:bg-stone-700 dark:text-white"
: "bg-blue text-white", : "bg-blue text-white",
)} )}
> >
@@ -70,12 +70,8 @@ export function BubbleBody(props: {
); );
} }
export function BubbleText(props: { text: string; className?: string }) { export function BubbleText(props: { text: string }) {
return ( return <p className="px-2 leading-relaxed">{props.text}</p>;
<p className={clsx("px-2 leading-relaxed", props.className)}>
{props.text}
</p>
);
} }
export function BubbleImage(props: { image: ImageDefinition }) { export function BubbleImage(props: { image: ImageDefinition }) {
@@ -101,7 +97,7 @@ export function BubbleInfo(props: { by: string | undefined; madeAt: Date }) {
export function InputBar(props: { children: React.ReactNode }) { export function InputBar(props: { children: React.ReactNode }) {
return ( 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} {props.children}
</div> </div>
); );
@@ -151,7 +147,7 @@ export function TextInput(props: { onSubmit: (text: string) => void }) {
</label> </label>
<input <input
id={inputId} 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" placeholder="Type a message and press Enter"
maxLength={2048} maxLength={2048}
onKeyDown={({ key, currentTarget: input }) => { onKeyDown={({ key, currentTarget: input }) => {

View File

@@ -15,20 +15,3 @@ export function onChatLoad(chat: Chat) {
} }
export const inIframe = window.self !== window.top; 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 { test } from "@playwright/test";
import { ChatPage } from "./pages/ChatPage"; import { ChatPage } from "./pages/ChatPage";
import { LoginPage } from "./pages/LoginPage";
test("chat between two users", async ({ page: marioPage, browser }) => { test("chat between two users", async ({ page }) => {
const context = await browser.newContext(); const loginPage = new LoginPage(page);
const luigiPage = await context.newPage();
await marioPage.goto("/"); const mario = "S. Mario";
const luigi = "Luigi";
const marioChat = new ChatPage(marioPage); await loginPage.goto();
const luigiChat = new ChatPage(luigiPage); 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?"; const message1ByMario = "Hello Luigi, are you ready to save the princess?";
await marioChat.sendMessage(message1ByMario); await chatPage.sendMessage(message1ByMario);
await marioChat.expectMessageRow(message1ByMario); await chatPage.expectMessageRow(message1ByMario);
const roomURL = marioPage.url(); const roomURL = page.url();
await luigiPage.goto(roomURL);
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 = const message2ByLuigi =
"No, I'm not ready yet. I'm still trying to find the key to the castle."; "No, I'm not ready yet. I'm still trying to find the key to the castle.";
await luigiChat.sendMessage(message2ByLuigi); await chatPage.sendMessage(message2ByLuigi);
await luigiChat.expectMessageRow(message2ByLuigi); await chatPage.expectMessageRow(message2ByLuigi);
await marioChat.expectMessageRow(message1ByMario); await chatPage.logout();
await luigiChat.expectMessageRow(message2ByLuigi); 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 page: Page;
readonly messageInput: Locator; readonly messageInput: Locator;
readonly logoutButton: Locator; readonly logoutButton: Locator;
readonly usernameInput: Locator;
constructor(page: Page) { constructor(page: Page) {
this.page = page; this.page = page;
this.messageInput = page.getByRole("textbox", { this.messageInput = page.getByRole("textbox", {
@@ -13,11 +13,6 @@ export class ChatPage {
this.logoutButton = page.getByRole("button", { this.logoutButton = page.getByRole("button", {
name: "Log out", name: "Log out",
}); });
this.usernameInput = page.getByPlaceholder("Set username");
}
async setUsername(username: string) {
await this.usernameInput.fill(username);
} }
async sendMessage(message: string) { 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,247 +1,5 @@
# minimal-auth-clerk # minimal-auth-clerk
## 0.0.68
### Patch Changes
- jazz-react@0.12.1
- jazz-react-auth-clerk@0.12.1
- jazz-tools@0.12.1
## 0.0.67
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
- jazz-react-auth-clerk@0.12.0
## 0.0.66
### Patch Changes
- jazz-react@0.11.8
- jazz-react-auth-clerk@0.11.8
- jazz-tools@0.11.8
## 0.0.65
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
- jazz-react-auth-clerk@0.11.7
## 0.0.64
### Patch Changes
- 1bfa9bb: Removed when="singedUp" from examples apps' Jazz providers. This is a really niche use-case option and can lead to broken-feeling experiences when anonymous users try to load something.
- Updated dependencies [e7c85b7]
- jazz-react@0.11.6
- jazz-tools@0.11.6
- jazz-react-auth-clerk@0.11.6
## 0.0.63
### Patch Changes
- jazz-react@0.11.5
- jazz-react-auth-clerk@0.11.5
- jazz-tools@0.11.5
## 0.0.62
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react@0.11.4
- jazz-react-auth-clerk@0.11.4
## 0.0.61
### Patch Changes
- jazz-react@0.11.3
- jazz-react-auth-clerk@0.11.3
- jazz-tools@0.11.3
## 0.0.60
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react@0.11.2
- jazz-react-auth-clerk@0.11.2
## 0.0.59
### Patch Changes
- jazz-react@0.11.1
- jazz-react-auth-clerk@0.11.1
## 0.0.58
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-react-auth-clerk@0.11.0
- jazz-react@0.11.0
## 0.0.57
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react@0.10.15
- jazz-react-auth-clerk@0.10.15
## 0.0.56
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
- jazz-react-auth-clerk@0.10.14
## 0.0.55
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
- jazz-react-auth-clerk@0.10.13
## 0.0.54
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-react-auth-clerk@0.10.12
## 0.0.53
### Patch Changes
- jazz-react@0.10.9
- jazz-react-auth-clerk@0.10.9
## 0.0.52
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
- jazz-react-auth-clerk@0.10.8
## 0.0.51
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react-auth-clerk@0.10.7
- jazz-react@0.10.7
- jazz-tools@0.10.7
## 0.0.50
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- jazz-react-auth-clerk@0.10.6
- jazz-react@0.10.6
- jazz-tools@0.10.6
## 0.0.49
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react@0.10.5
- jazz-react-auth-clerk@0.10.5
## 0.0.48
### Patch Changes
- jazz-react@0.10.4
- jazz-react-auth-clerk@0.10.4
- jazz-tools@0.10.4
## 0.0.47
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react@0.10.3
- jazz-react-auth-clerk@0.10.3
## 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
### 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 ## 0.0.42
### Patch Changes ### Patch Changes

View File

@@ -15,12 +15,12 @@ You can either
Create a new Jazz project, and use this example as a template. Create a new Jazz project, and use this example as a template.
```bash ```bash
npx create-jazz-app@latest clerk-app --example clerk npx create-jazz-app@latest --example clerk --project-name clerk
``` ```
Go to the new project directory. Go to the new project directory.
```bash ```bash
cd clerk-app cd clerk
``` ```
Run the dev server. Run the dev server.

View File

@@ -1,7 +1,7 @@
{ {
"name": "clerk", "name": "clerk",
"private": true, "private": true,
"version": "0.0.68", "version": "0.0.42",
"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.12.1", "jazz-react-auth-clerk": "workspace:0.9.22",
"jazz-tools": "workspace:*", "jazz-tools": "workspace:*",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1" "react-dom": "^18.3.1"
@@ -25,6 +25,6 @@
"@vitejs/plugin-react": "^4.3.3", "@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0", "globals": "^15.11.0",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"vite": "^6.0.11" "vite": "^5.4.10"
} }
} }

View File

@@ -1,12 +1,8 @@
import { SignInButton } from "@clerk/clerk-react"; import { useAccount } from "jazz-react";
import { useAccount, useIsAuthenticated } from "jazz-react";
function App() { function App() {
const { me, logOut } = useAccount(); const { me, logOut } = useAccount();
const isAuthenticated = useIsAuthenticated();
if (isAuthenticated) {
return ( return (
<div className="container"> <div className="container">
<h1>You're logged in</h1> <h1>You're logged in</h1>
@@ -14,14 +10,6 @@ function App() {
<button onClick={() => logOut()}>Logout</button> <button onClick={() => logOut()}>Logout</button>
</div> </div>
); );
}
return (
<div className="container">
<h1>You're not logged in</h1>
<SignInButton />
</div>
);
} }
export default App; export default App;

View File

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

View File

@@ -62,7 +62,7 @@ button {
} }
.container { .container {
max-width: 400px; max-width: 200px;
margin: 0 auto; margin: 0 auto;
padding: 0 1rem; padding: 0 1rem;
display: flex; 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 { StrictMode } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import App from "./App.tsx"; import App from "./App.tsx";
import "./index.css"; import "./index.css";
import { JazzProviderWithClerk } from "jazz-react-auth-clerk"; import { JazzProvider } from "jazz-react";
import { apiKey } from "./apiKey";
// Import your publishable key // Import your publishable key
const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY; const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
@@ -13,27 +13,35 @@ if (!PUBLISHABLE_KEY) {
throw new Error("Add your Clerk publishable key to the .env.local file"); 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 clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
return ( return (
<JazzProviderWithClerk <main className="container">
clerk={clerk} {state?.errors?.map((error) => (
sync={{ <div key={error}>{error}</div>
peer: `wss://cloud.jazz.tools/?key=${apiKey}`, ))}
}} {clerk.user && auth ? (
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=minimal-auth-clerk-example@garden.co"
> >
{children} {children}
</JazzProviderWithClerk> </JazzProvider>
) : (
<SignInButton />
)}
</main>
); );
} }
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<StrictMode> <StrictMode>
<ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/"> <ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/">
<JazzProvider> <JazzAndAuth>
<App /> <App />
</JazzProvider> </JazzAndAuth>
</ClerkProvider> </ClerkProvider>
</StrictMode>, </StrictMode>,
); );

View File

@@ -1,213 +1,5 @@
# file-share-svelte # file-share-svelte
## 0.0.52
### Patch Changes
- jazz-svelte@0.12.1
- jazz-tools@0.12.1
## 0.0.51
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-svelte@0.12.0
## 0.0.50
### Patch Changes
- jazz-svelte@0.11.8
- jazz-tools@0.11.8
## 0.0.49
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-svelte@0.11.7
## 0.0.48
### Patch Changes
- 1bfa9bb: Removed when="singedUp" from examples apps' Jazz providers. This is a really niche use-case option and can lead to broken-feeling experiences when anonymous users try to load something.
- Updated dependencies [e7c85b7]
- jazz-tools@0.11.6
- jazz-svelte@0.11.6
## 0.0.47
### Patch Changes
- jazz-svelte@0.11.5
- jazz-tools@0.11.5
## 0.0.46
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-svelte@0.11.4
## 0.0.45
### Patch Changes
- jazz-svelte@0.11.3
- jazz-tools@0.11.3
## 0.0.44
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-svelte@0.11.2
## 0.0.43
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-svelte@0.11.0
## 0.0.42
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-svelte@0.10.15
## 0.0.41
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-svelte@0.10.14
## 0.0.40
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-svelte@0.10.13
## 0.0.39
### Patch Changes
- Updated dependencies [4612e05]
- jazz-svelte@0.10.12
- jazz-tools@0.10.12
## 0.0.38
### Patch Changes
- jazz-svelte@0.10.9
## 0.0.37
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-svelte@0.10.8
## 0.0.36
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-svelte@0.10.7
- jazz-tools@0.10.7
## 0.0.35
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-svelte@0.10.6
## 0.0.34
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-svelte@0.10.5
## 0.0.33
### Patch Changes
- jazz-svelte@0.10.4
- jazz-tools@0.10.4
## 0.0.32
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-svelte@0.10.3
## 0.0.31
### Patch Changes
- jazz-svelte@0.10.2
- jazz-tools@0.10.2
## 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 ## 0.0.27
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "file-share-svelte", "name": "file-share-svelte",
"version": "0.0.52", "version": "0.0.27",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
@@ -13,13 +13,13 @@
"lint": "prettier --check . && eslint .", "lint": "prettier --check . && eslint .",
"format-and-lint": "pnpm run format && pnpm run lint", "format-and-lint": "pnpm run format && pnpm run lint",
"format-and-lint:fix": "pnpm run format --write && pnpm run lint --fix", "format-and-lint:fix": "pnpm run format --write && pnpm run lint --fix",
"test:e2e": "playwright test", "test": "playwright test",
"test:e2e:ui": "playwright test --ui" "test:ui": "playwright test --ui"
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-vercel": "^5.5.0", "@sveltejs/adapter-vercel": "^5.5.0",
"@sveltejs/kit": "^2.16.0", "@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0", "@sveltejs/vite-plugin-svelte": "^4.0.1",
"@types/is-ci": "^3.0.4", "@types/is-ci": "^3.0.4",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"eslint": "^9.7.0", "eslint": "^9.7.0",
@@ -32,10 +32,10 @@
"prettier-plugin-tailwindcss": "^0.6.5", "prettier-plugin-tailwindcss": "^0.6.5",
"svelte": "^5.0.0", "svelte": "^5.0.0",
"svelte-check": "^4.0.0", "svelte-check": "^4.0.0",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.15",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"typescript-eslint": "^8.0.0", "typescript-eslint": "^8.0.0",
"vite": "^6.0.11" "vite": "^5.4.10"
}, },
"dependencies": { "dependencies": {
"@tailwindcss/typography": "^0.5.15", "@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 * @param createdAt The creation date
* @returns A unique file ID string * @returns A unique file ID string
*/ */
export function generateTempFileId(fileName: string | undefined, createdAt: Date | undefined): string { export function generateTempFileId(fileName: string, createdAt: Date): string {
return `file-${fileName ?? 'unknown'}-${createdAt?.getTime() ?? 0}`; return `file-${fileName}-${createdAt.getTime()}`;
} }

View File

@@ -12,9 +12,11 @@
import { Toaster } from 'svelte-sonner'; import { Toaster } from 'svelte-sonner';
import '../app.css'; import '../app.css';
import { FileShareAccount } from '$lib/schema'; import { FileShareAccount } from '$lib/schema';
import {apiKey} from '../apiKey';
let { children } = $props(); let { children } = $props();
const auth = usePasskeyAuth({
appName: 'File Share'
});
</script> </script>
<svelte:head> <svelte:head>
@@ -23,15 +25,21 @@
<Toaster richColors /> <Toaster richColors />
<JazzProvider {#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} AccountSchema={FileShareAccount}
sync={{ auth={auth.current}
peer: `wss://cloud.jazz.tools/?key=${apiKey}`, peer="wss://cloud.jazz.tools/?key=file-share-svelte@garden.co"
}} >
>
<PasskeyAuthBasicUI appName="File Share">
<div class="min-h-screen bg-gray-100"> <div class="min-h-screen bg-gray-100">
{@render children()} {@render children()}
</div> </div>
</PasskeyAuthBasicUI> </JazzProvider>
</JazzProvider> {/if}

View File

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

View File

@@ -1,28 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
/test-results/
/playwright-report/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
playwright-report

View File

@@ -1,327 +0,0 @@
# jazz-tailwind-demo-auth-starter
## 0.0.8
### Patch Changes
- jazz-react@0.12.1
- jazz-tools@0.12.1
## 0.0.7
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.6
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.5
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.4
### Patch Changes
- Updated dependencies [e7c85b7]
- jazz-react@0.11.6
- jazz-tools@0.11.6
## 0.0.3
### Patch Changes
- jazz-react@0.11.5
- jazz-tools@0.11.5
## 0.0.2
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react@0.11.4
## 0.0.52
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react@0.10.15
## 0.0.51
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
## 0.0.50
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
## 0.0.49
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
## 0.0.48
### Patch Changes
- jazz-react@0.10.9
## 0.0.47
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
## 0.0.46
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react@0.10.7
- jazz-tools@0.10.7
## 0.0.45
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- jazz-react@0.10.6
- jazz-tools@0.10.6
## 0.0.44
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react@0.10.5
## 0.0.43
### Patch Changes
- jazz-react@0.10.4
- jazz-tools@0.10.4
## 0.0.42
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react@0.10.3
## 0.0.41
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.40
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react@0.10.1
## 0.0.39
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
## 0.0.38
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
## 0.0.37
### Patch Changes
- jazz-react@0.9.22
## 0.0.36
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react@0.9.21
## 0.0.35
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react@0.9.20
## 0.0.34
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
## 0.0.33
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
## 0.0.32
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react@0.9.17
## 0.0.31
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-react@0.9.16
## 0.0.30
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-react@0.9.15
## 0.0.29
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-react@0.9.14
## 0.0.28
### Patch Changes
- jazz-react@0.9.13
- jazz-tools@0.9.13
## 0.0.27
### Patch Changes
- jazz-react@0.9.12
- jazz-tools@0.9.12
## 0.0.26
### Patch Changes
- jazz-react@0.9.11
- jazz-tools@0.9.11
## 0.0.25
### Patch Changes
- Updated dependencies [5e83864]
- jazz-react@0.9.10
- jazz-tools@0.9.10
## 0.0.24
### Patch Changes
- Updated dependencies [8eb9247]
- jazz-tools@0.9.9
- jazz-react@0.9.9
## 0.0.23
### Patch Changes
- Updated dependencies [d1d773b]
- jazz-tools@0.9.8
- jazz-react@0.9.8
## 0.0.22
### Patch Changes
- jazz-react@0.9.4
## 0.0.21
### Patch Changes
- Updated dependencies [1b71969]
- jazz-react@0.9.1
- jazz-tools@0.9.1
## 0.0.20
### Patch Changes
- Updated dependencies [956a4d1]
- Updated dependencies [8eda792]
- jazz-react@0.9.0
- jazz-tools@0.9.0
## 0.0.19
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react@0.8.51

View File

@@ -1,32 +0,0 @@
{
"name": "filestream",
"private": true,
"version": "0.0.8",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write"
},
"dependencies": {
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2",
"vite": "^6.0.11"
}
}

View File

@@ -1,37 +0,0 @@
import { FileWidget } from "./FileWidget.js";
import { Logo } from "./Logo.tsx";
function App() {
return (
<>
<main className="container mt-16 flex flex-col gap-8">
<Logo />
<FileWidget />
<p className="text-center">
Edit the form above,{" "}
<button
type="button"
onClick={() => window.location.reload()}
className="font-semibold underline"
>
refresh
</button>{" "}
this page, and see your changes persist.
</p>
<p className="text-center my-16">
Go to{" "}
<a
className="font-semibold underline"
href="https://jazz.tools/docs/react/guide"
>
jazz.tools/docs/react/guide
</a>{" "}
for a full tutorial.
</p>
</main>
</>
);
}
export default App;

View File

@@ -1,269 +0,0 @@
"use client";
import { useAccount } from "jazz-react";
import { FileStream } from "jazz-tools";
import { useRef, useState } from "react";
export function FileWidget() {
const inputRef = useRef<HTMLInputElement>(null);
const dragAndDropElementRef = useRef<HTMLDivElement>(null);
const [isUploading, setIsUploading] = useState(false);
const [progress, setProgress] = useState(0);
const [error, setError] = useState<string | null>(null);
const { me } = useAccount();
async function handleUpload(event: React.FormEvent) {
event.preventDefault();
setError(null);
if (!me?.profile) {
setError("User profile not found");
return;
}
setProgress(0);
const file = inputRef.current?.files?.[0];
if (!file) {
setError("Please select a file");
return;
}
try {
setIsUploading(true);
me.profile.file = await FileStream.createFromBlob(file, {
onProgress: (p) => setProgress(Math.round(p * 100)),
});
} catch (error) {
setError(
error instanceof Error ? error.message : "Failed to upload file",
);
console.error("Error uploading file:", error);
} finally {
setIsUploading(false);
}
}
function handleDelete() {
if (!me?.profile) return;
delete me.profile?.file;
}
async function handleDownload() {
if (!me?.profile) return;
const file = me.profile.file;
if (!file) return;
try {
const blob = file.toBlob();
const url = URL.createObjectURL(blob || new Blob());
const a = document.createElement("a");
a.href = url;
a.download = file.id || "download";
a.click();
URL.revokeObjectURL(url);
} catch (error) {
console.error("Error downloading file:", error);
}
}
function formatFileSize(bytes?: number): string {
if (!bytes) return "0 Bytes";
const k = 1024;
const sizes = ["Bytes", "KB", "MB", "GB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
}
const onDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
dragAndDropElementRef?.current?.classList.replace(
"border-stone-400",
"border-blue-700",
);
};
const onDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
dragAndDropElementRef?.current?.classList.replace(
"border-stone-400",
"border-blue-700",
);
};
const onDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
dragAndDropElementRef?.current?.classList.replace(
"border-blue-700",
"border-stone-400",
);
};
const onDrop = async (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
dragAndDropElementRef?.current?.classList.replace(
"border-blue-700",
"border-stone-400",
);
if (!me?.profile) {
setError("User profile not found");
return;
}
const droppedFiles = e.dataTransfer.files;
if (!droppedFiles || droppedFiles.length === 0) {
return;
}
const file = droppedFiles[0];
setProgress(0);
try {
setIsUploading(true);
me.profile.file = await FileStream.createFromBlob(file, {
onProgress: (p) => setProgress(Math.round(p * 100)),
});
} catch (error) {
setError(
error instanceof Error ? error.message : "Failed to upload file",
);
console.error("Error uploading file:", error);
} finally {
setIsUploading(false);
}
};
if (me?.profile?.file == null) {
return (
<div className="flex flex-col gap-4">
<div
className="flex flex-col border-2 border-dashed border-stone-400 h-48 items-center justify-center bg-stone-100 m-5 rounded-md"
ref={dragAndDropElementRef}
onDragEnter={onDragEnter}
onDragOver={onDragOver}
onDragLeave={onDragLeave}
onDrop={onDrop}
>
<p>Drag & drop your file here</p>
</div>
<form onSubmit={handleUpload} className="flex gap-2">
<input
className="bg-stone-100 py-1.5 px-2 text-sm rounded-md w-4/5"
ref={inputRef}
type="file"
accept="file"
onChange={() => setError(null)}
disabled={isUploading}
/>
<button
type="submit"
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md disabled:opacity-50"
disabled={isUploading}
>
{isUploading ? `Uploading...` : "Upload file"}
</button>
</form>
{error && (
<div className="text-red-800 text-sm pl-4" role="alert">
{error}
</div>
)}
{isUploading && (
<div className="flex gap-2 items-center">
<div className="py-1.5 px-3 text-sm">Progress: {progress}%</div>
<div className="h-2 bg-stone-200 rounded-full flex-1">
<div
className="h-full bg-blue-500 rounded-full transition-all duration-300"
style={{ width: `${progress}%` }}
/>
</div>
</div>
)}
</div>
);
}
const fileData = me?.profile?.file?.getChunks();
const mimeType = fileData?.mimeType || "unknown";
return (
<div className="gap-2">
<div className="p-4">
<div className="space-y-2">
<div className="flex justify-between">
<span className="font-bold">File name</span>
<span>{fileData?.fileName}</span>
</div>
<div className="flex justify-between">
<span className="font-bold">Type</span>
<span>{mimeType}</span>
</div>
<div className="flex justify-between">
<span className="font-bold">Size</span>
<span>{formatFileSize(fileData?.totalSizeBytes)}</span>
</div>
</div>
</div>
<div className="flex gap-2 justify-end">
<button
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md"
onClick={handleDelete}
>
Delete file
</button>
<button
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md"
onClick={handleDownload}
>
Download file
</button>
</div>
<div className="w-full justify-center pt-8">
{fileData?.mimeType?.startsWith("image/") && (
<div className="flex justify-center">
<img
src={URL.createObjectURL(
me?.profile?.file?.toBlob() || new Blob(),
)}
alt="File preview"
className="max-w-xs mb-4"
/>
</div>
)}
{fileData?.mimeType?.startsWith("audio/") && (
<div className="flex justify-center">
<audio
src={URL.createObjectURL(
me?.profile?.file?.toBlob() || new Blob(),
)}
controls
className="w-full mb-4"
/>
</div>
)}
{fileData?.mimeType?.startsWith("video/") && (
<div className="flex justify-center">
<video
src={URL.createObjectURL(
me?.profile?.file?.toBlob() || new Blob(),
)}
controls
className="w-full mb-4"
/>
</div>
)}
</div>
</div>
);
}

View File

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

View File

@@ -1,29 +0,0 @@
import { JazzProvider } from "jazz-react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import { apiKey } from "./apiKey.ts";
import "./index.css";
import { JazzAccount } from "./schema.ts";
// We use this to identify the app in the passkey auth
export const APPLICATION_NAME = "Jazz File Stream Example";
declare module "jazz-react" {
export interface Register {
Account: JazzAccount;
}
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<JazzProvider
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
AccountSchema={JazzAccount}
>
<App />
</JazzProvider>
</StrictMode>,
);

View File

@@ -1,14 +0,0 @@
import { Account, FileStream, Profile, co } from "jazz-tools";
export class JazzProfile extends Profile {
file = co.ref(FileStream, { optional: true });
}
export class JazzAccount extends Account {
profile = co.ref(JazzProfile);
/** 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(this: JazzAccount) {}
}

View File

@@ -1,9 +0,0 @@
import { expect, test } from "@playwright/test";
test("home page loads", async ({ page }) => {
await page.goto("/");
await expect(page.getByText("Welcome!")).toBeVisible();
await page.getByLabel("Name").fill("Bob");
await expect(page.getByText("Welcome, Bob!")).toBeVisible();
});

View File

@@ -1,247 +1,5 @@
# form # form
## 0.1.10
### Patch Changes
- jazz-react@0.12.1
- jazz-tools@0.12.1
## 0.1.9
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.1.8
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.1.7
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.1.6
### Patch Changes
- Updated dependencies [e7c85b7]
- Updated dependencies [8ed144e]
- jazz-react@0.11.6
- jazz-tools@0.11.6
- jazz-browser-media-images@0.11.6
## 0.1.5
### Patch Changes
- jazz-react@0.11.5
- jazz-tools@0.11.5
- jazz-browser-media-images@0.11.5
## 0.1.4
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-browser-media-images@0.11.4
- jazz-react@0.11.4
## 0.1.3
### Patch Changes
- jazz-react@0.11.3
- jazz-tools@0.11.3
- jazz-browser-media-images@0.11.3
## 0.1.2
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react@0.11.2
- jazz-browser-media-images@0.11.2
## 0.1.1
### Patch Changes
- jazz-react@0.11.1
## 0.1.0
### Minor Changes
- 18428ea: PasskeyAuth: Sets `profile.name` only if a non-empty username is passed to `signUp`
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-browser-media-images@0.11.0
- jazz-react@0.11.0
## 0.0.53
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-browser-media-images@0.10.15
- jazz-react@0.10.15
## 0.0.52
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
- jazz-browser-media-images@0.10.14
## 0.0.51
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.50
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.49
### Patch Changes
- jazz-browser-media-images@0.10.9
- jazz-react@0.10.9
## 0.0.48
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
- jazz-browser-media-images@0.10.8
## 0.0.47
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react@0.10.7
- jazz-tools@0.10.7
- jazz-browser-media-images@0.10.7
## 0.0.46
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- hash-slash@0.2.2
- jazz-react@0.10.6
- jazz-tools@0.10.6
- jazz-browser-media-images@0.10.6
## 0.0.45
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-browser-media-images@0.10.5
- jazz-react@0.10.5
## 0.0.44
### Patch Changes
- jazz-react@0.10.4
- jazz-tools@0.10.4
- jazz-browser-media-images@0.10.4
## 0.0.43
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-browser-media-images@0.10.3
- jazz-react@0.10.3
## 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
### 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 ## 0.0.38
### Patch Changes ### Patch Changes

View File

@@ -28,12 +28,12 @@ You can either
Create a new Jazz project, and use this example as a template. Create a new Jazz project, and use this example as a template.
```bash ```bash
npx create-jazz-app@latest form-app --example form npx create-jazz-app@latest --example form --project-name form
``` ```
Go to the new project directory. Go to the new project directory.
```bash ```bash
cd form-app cd form
``` ```
Run the dev server. Run the dev server.

View File

@@ -1,7 +1,7 @@
{ {
"name": "form", "name": "form",
"private": true, "private": true,
"version": "0.1.10", "version": "0.0.38",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -12,6 +12,7 @@
}, },
"dependencies": { "dependencies": {
"hash-slash": "workspace:*", "hash-slash": "workspace:*",
"jazz-browser-media-images": "workspace:*",
"jazz-react": "workspace:*", "jazz-react": "workspace:*",
"jazz-tools": "workspace:*", "jazz-tools": "workspace:*",
"react": "^18.3.1", "react": "^18.3.1",
@@ -19,7 +20,7 @@
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.9.4", "@biomejs/biome": "1.9.4",
"@playwright/test": "^1.50.1", "@playwright/test": "^1.46.1",
"@tailwindcss/forms": "^0.5.9", "@tailwindcss/forms": "^0.5.9",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1", "@types/react-dom": "^18.3.1",
@@ -28,8 +29,8 @@
"globals": "^15.11.0", "globals": "^15.11.0",
"is-ci": "^3.0.1", "is-ci": "^3.0.1",
"postcss": "^8.4.27", "postcss": "^8.4.27",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.15",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"vite": "^6.0.11" "vite": "^5.4.10"
} }
} }

View File

@@ -1,4 +1,5 @@
import { useIframeHashRouter } from "hash-slash"; import { useIframeHashRouter } from "hash-slash";
import { useAccount } from "jazz-react";
import { ID } from "jazz-tools"; import { ID } from "jazz-tools";
import { CreateOrder } from "./CreateOrder.tsx"; import { CreateOrder } from "./CreateOrder.tsx";
import { EditOrder } from "./EditOrder.tsx"; import { EditOrder } from "./EditOrder.tsx";
@@ -6,10 +7,25 @@ import { Orders } from "./Orders.tsx";
import { BubbleTeaOrder } from "./schema.ts"; import { BubbleTeaOrder } from "./schema.ts";
function App() { function App() {
const { me, logOut } = useAccount();
const router = useIframeHashRouter(); const router = useIframeHashRouter();
return ( return (
<> <>
<header>
<nav className="container py-2 border-b flex items-center justify-between">
<span>
You're logged in as <strong>{me?.profile?.name}</strong>
</span>
<button
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md dark:bg-stone-900 dark:text-white"
onClick={() => logOut()}
>
Log out
</button>
</nav>
</header>
<main className="container py-8 space-y-8"> <main className="container py-8 space-y-8">
{router.route({ {router.route({
"/": () => <Orders />, "/": () => <Orders />,

View File

@@ -12,9 +12,7 @@ import {
} from "./schema.ts"; } from "./schema.ts";
export function CreateOrder() { export function CreateOrder() {
const { me } = useAccount({ const { me } = useAccount({ root: { draft: {}, orders: [] } });
resolve: { root: { draft: true, orders: true } },
});
const router = useIframeHashRouter(); const router = useIframeHashRouter();
const [errors, setErrors] = useState<string[]>([]); const [errors, setErrors] = useState<string[]>([]);
@@ -62,7 +60,7 @@ function CreateOrderForm({
onSave: (draft: DraftBubbleTeaOrder) => void; onSave: (draft: DraftBubbleTeaOrder) => void;
}) { }) {
const draft = useCoState(DraftBubbleTeaOrder, id, { const draft = useCoState(DraftBubbleTeaOrder, id, {
resolve: { addOns: true }, addOns: [],
}); });
if (!draft) return; if (!draft) return;

View File

@@ -2,7 +2,7 @@ import { useAccount } from "jazz-react";
export function DraftIndicator() { export function DraftIndicator() {
const { me } = useAccount({ const { me } = useAccount({
resolve: { root: { draft: true } }, root: { draft: {} },
}); });
if (me?.root.draft?.hasChanges) { if (me?.root.draft?.hasChanges) {

View File

@@ -6,7 +6,7 @@ import { OrderThumbnail } from "./OrderThumbnail.tsx";
import { BubbleTeaOrder } from "./schema.ts"; import { BubbleTeaOrder } from "./schema.ts";
export function EditOrder(props: { id: ID<BubbleTeaOrder> }) { export function EditOrder(props: { id: ID<BubbleTeaOrder> }) {
const order = useCoState(BubbleTeaOrder, props.id); const order = useCoState(BubbleTeaOrder, props.id, []);
if (!order) return; if (!order) return;

View File

@@ -4,7 +4,7 @@ import { OrderThumbnail } from "./OrderThumbnail.tsx";
export function Orders() { export function Orders() {
const { me } = useAccount({ const { me } = useAccount({
resolve: { root: { orders: true } }, root: { orders: [] },
}); });
return ( return (

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 { StrictMode } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import App from "./App.tsx"; import App from "./App.tsx";
import "./index.css"; import "./index.css";
import { apiKey } from "./apiKey";
import { JazzAccount } from "./schema.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=form-example@garden.co"
AccountSchema={JazzAccount}
>
{children}
</JazzProvider>
{authState.state !== "signedIn" && (
<DemoAuthBasicUI appName="Form" state={authState} />
)}
</>
);
}
declare module "jazz-react" { declare module "jazz-react" {
interface Register { interface Register {
Account: JazzAccount; Account: JazzAccount;
@@ -14,13 +33,8 @@ declare module "jazz-react" {
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<StrictMode> <StrictMode>
<JazzProvider <JazzAndAuth>
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
AccountSchema={JazzAccount}
>
<App /> <App />
</JazzProvider> </JazzAndAuth>
</StrictMode>, </StrictMode>,
); );

View File

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

File diff suppressed because one or more lines are too long

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