Compare commits
3 Commits
cojson-sto
...
feat/1206-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69ea14c513 | ||
|
|
05d6f36f30 | ||
|
|
02541d3f48 |
@@ -2,22 +2,42 @@
|
||||
"$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"linked": [],
|
||||
"fixed": [
|
||||
"fixed": [],
|
||||
"linked": [
|
||||
[
|
||||
"cojson",
|
||||
"cojson-storage",
|
||||
"cojson-storage-indexeddb",
|
||||
"cojson-storage-sqlite",
|
||||
"cojson-transport-ws",
|
||||
"jazz-browser",
|
||||
"jazz-auth-clerk",
|
||||
"jazz-auth-betterauth",
|
||||
"jazz-betterauth-client-plugin",
|
||||
"jazz-betterauth-server-plugin",
|
||||
"jazz-react-auth-betterauth",
|
||||
"jazz-browser-media-images",
|
||||
"jazz-expo",
|
||||
"jazz-inspector",
|
||||
"jazz-inspector-element",
|
||||
"jazz-nodejs",
|
||||
"jazz-react",
|
||||
"jazz-react-core",
|
||||
"jazz-react-auth-clerk",
|
||||
"jazz-react-native-core",
|
||||
"jazz-react-native",
|
||||
"jazz-react-native-media-images",
|
||||
"jazz-run",
|
||||
"jazz-tools"
|
||||
"jazz-svelte",
|
||||
"jazz-tools",
|
||||
"jazz-vue"
|
||||
]
|
||||
],
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "minor"
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": [],
|
||||
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
|
||||
"onlyUpdatePeerDependentsWhenOutOfRange": true
|
||||
}
|
||||
}
|
||||
|
||||
23
.github/pull_request_template.md
vendored
@@ -1,23 +0,0 @@
|
||||
# Description
|
||||
<!-- Please include a summary of the change and which issue is fixed -->
|
||||
<!-- Please also include relevant motivation and context -->
|
||||
<!-- Include any links to documentation like RFC’s if necessary -->
|
||||
<!-- Add a link to to relevant preview environments or anything that would simplify visual review process -->
|
||||
<!-- Supplemental screenshots and video are encouraged, but the primary description should be in text -->
|
||||
|
||||
## Manual testing instructions
|
||||
|
||||
<!-- Add any actions required to manually test the changes -->
|
||||
|
||||
## Tests
|
||||
|
||||
- [ ] Tests have been added and/or updated
|
||||
- [ ] Tests have not been updated, because: <!-- Insert reason for not updating tests here -->
|
||||
- [ ] I need help with writing tests
|
||||
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I've updated the part of the docs that are affected the PR changes
|
||||
- [ ] I've generated a changeset, if a version bump is required
|
||||
- [ ] I've updated the jsDoc comments to the public APIs I've modified, or added them when missing
|
||||
37
.github/workflows/build-examples.yaml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Build Examples
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build-examples:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
strategy:
|
||||
matrix:
|
||||
example: [
|
||||
"chat",
|
||||
"clerk",
|
||||
"passkey",
|
||||
"inspector",
|
||||
"music-player",
|
||||
"password-manager",
|
||||
"pets",
|
||||
"reactions",
|
||||
"todo",
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup Source Code
|
||||
uses: ./.github/actions/source-code/
|
||||
|
||||
- name: Pnpm Build
|
||||
run: |
|
||||
pnpm install
|
||||
pnpm turbo build;
|
||||
working-directory: ./examples/${{ matrix.example }}
|
||||
26
.github/workflows/build-starters.yaml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Build Starters
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build-starters:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
strategy:
|
||||
matrix:
|
||||
starter: ["react-passkey-auth"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup Source Code
|
||||
uses: ./.github/actions/source-code/
|
||||
|
||||
- name: Pnpm Build
|
||||
run: |
|
||||
pnpm install
|
||||
pnpm turbo build;
|
||||
working-directory: ./starters/${{ matrix.starter }}
|
||||
13
.github/workflows/code-quality.yml
vendored
@@ -1,28 +1,19 @@
|
||||
name: Code quality
|
||||
|
||||
concurrency:
|
||||
# For pushes, this lets concurrent runs happen, so each push gets a result.
|
||||
# But for other events (e.g. PRs), we can cancel the previous runs.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
pull_request:
|
||||
|
||||
|
||||
jobs:
|
||||
quality:
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404-arm
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Biome
|
||||
uses: biomejs/setup-biome@v2
|
||||
with:
|
||||
version: 1.9.4
|
||||
version: latest
|
||||
- name: Run Biome
|
||||
run: biome ci .
|
||||
|
||||
|
||||
10
.github/workflows/e2e-rn-test.yml
vendored
@@ -1,11 +1,5 @@
|
||||
name: End-to-End Tests for React Native
|
||||
|
||||
concurrency:
|
||||
# For pushes, this lets concurrent runs happen, so each push gets a result.
|
||||
# But for other events (e.g. PRs), we can cancel the previous runs.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
@@ -44,6 +38,7 @@ jobs:
|
||||
- name: chat-rn-expo App Pre Build
|
||||
working-directory: ./examples/chat-rn-expo
|
||||
run: |
|
||||
pnpm build
|
||||
pnpm expo prebuild --clean
|
||||
|
||||
- name: Install Maestro
|
||||
@@ -66,8 +61,7 @@ jobs:
|
||||
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-expo/
|
||||
# killall due to this issue: https://github.com/ReactiveCircus/android-emulator-runner/issues/385
|
||||
script: ./test/e2e/run.sh && ( killall -INT crashpad_handler || true )
|
||||
script: ./test/e2e/run.sh
|
||||
|
||||
- name: Copy Maestro Output
|
||||
if: steps.e2e_test.outcome != 'success'
|
||||
|
||||
8
.github/workflows/jazz-run.yml
vendored
@@ -1,11 +1,5 @@
|
||||
name: Jazz Run Tests
|
||||
|
||||
concurrency:
|
||||
# For pushes, this lets concurrent runs happen, so each push gets a result.
|
||||
# But for other events (e.g. PRs), we can cancel the previous runs.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
@@ -14,7 +8,7 @@ on:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
|
||||
148
.github/workflows/playwright.yml
vendored
@@ -1,11 +1,5 @@
|
||||
name: Playwright Tests
|
||||
|
||||
concurrency:
|
||||
# For pushes, this lets concurrent runs happen, so each push gets a result.
|
||||
# But for other events (e.g. PRs), we can cancel the previous runs.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
@@ -15,11 +9,11 @@ on:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
shard: ["1/2", "2/2"]
|
||||
project: ["tests/e2e", "examples/chat", "examples/clerk", "examples/betterauth", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/organization", "examples/pets", "starters/react-passkey-auth"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -29,129 +23,21 @@ jobs:
|
||||
- name: Setup Source Code
|
||||
uses: ./.github/actions/source-code/
|
||||
|
||||
- name: Pnpm Build
|
||||
run: pnpm turbo build
|
||||
working-directory: ./${{ matrix.project }}
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: pnpm exec playwright install
|
||||
working-directory: ./${{ matrix.project }}
|
||||
|
||||
- name: Run Playwright tests for shard ${{ matrix.shard }}
|
||||
run: |
|
||||
# Parse shard information (e.g., "1/2" -> shard_num=1, total_shards=2)
|
||||
IFS='/' read -r shard_num total_shards <<< "${{ matrix.shard }}"
|
||||
shard_index=$((shard_num - 1)) # Convert to 0-based index
|
||||
|
||||
# Debug: Print parsed values
|
||||
echo "Parsed shard_num: $shard_num"
|
||||
echo "Parsed total_shards: $total_shards"
|
||||
echo "Calculated shard_index: $shard_index"
|
||||
|
||||
# Define all projects to test
|
||||
all_projects=(
|
||||
"tests/e2e"
|
||||
"examples/chat"
|
||||
"examples/chat-svelte"
|
||||
"examples/clerk"
|
||||
"examples/betterauth"
|
||||
"examples/file-share-svelte"
|
||||
"examples/form"
|
||||
"examples/inspector"
|
||||
"examples/music-player"
|
||||
"examples/organization"
|
||||
"starters/react-passkey-auth"
|
||||
"starters/svelte-passkey-auth"
|
||||
"tests/jazz-svelte"
|
||||
)
|
||||
|
||||
# Calculate which projects this shard should run
|
||||
shard_projects=()
|
||||
for i in "${!all_projects[@]}"; do
|
||||
if [ $((i % total_shards)) -eq $shard_index ]; then
|
||||
shard_projects+=("${all_projects[i]}")
|
||||
fi
|
||||
done
|
||||
|
||||
# Track project results
|
||||
overall_exit_code=0
|
||||
failed_projects=()
|
||||
passed_projects=()
|
||||
|
||||
echo "=== Running tests for shard ${{ matrix.shard }} ==="
|
||||
echo "Projects in this shard:"
|
||||
printf '%s\n' "${shard_projects[@]}"
|
||||
echo
|
||||
|
||||
# Run tests for each project
|
||||
for project in "${shard_projects[@]}"; do
|
||||
echo "=== Testing project: $project ==="
|
||||
|
||||
# Check if project directory exists
|
||||
if [ ! -d "$project" ]; then
|
||||
echo "❌ FAILED: Project directory $project does not exist"
|
||||
failed_projects+=("$project (directory not found)")
|
||||
overall_exit_code=1
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if project has package.json
|
||||
if [ ! -f "$project/package.json" ]; then
|
||||
echo "❌ FAILED: No package.json found in $project"
|
||||
failed_projects+=("$project (no package.json)")
|
||||
overall_exit_code=1
|
||||
continue
|
||||
fi
|
||||
|
||||
# Build the project
|
||||
echo "🔨 Building $project..."
|
||||
cd "$project"
|
||||
|
||||
if [ -f .env.test ]; then
|
||||
cp .env.test .env
|
||||
fi
|
||||
|
||||
if ! pnpm turbo build; then
|
||||
echo "❌ BUILD FAILED: $project"
|
||||
failed_projects+=("$project (build failed)")
|
||||
overall_exit_code=1
|
||||
cd - > /dev/null
|
||||
continue
|
||||
fi
|
||||
|
||||
# Run Playwright tests
|
||||
echo "🧪 Running Playwright tests for $project..."
|
||||
if ! pnpm exec playwright test; then
|
||||
echo "❌ TESTS FAILED: $project"
|
||||
failed_projects+=("$project (tests failed)")
|
||||
overall_exit_code=1
|
||||
else
|
||||
echo "✅ TESTS PASSED: $project"
|
||||
passed_projects+=("$project")
|
||||
fi
|
||||
|
||||
cd - > /dev/null
|
||||
echo "=== Finished testing $project ==="
|
||||
echo
|
||||
done
|
||||
|
||||
# Print summary report
|
||||
echo "=========================================="
|
||||
echo "📊 TEST SUMMARY FOR SHARD ${{ matrix.shard }}"
|
||||
echo "=========================================="
|
||||
|
||||
if [ ${#passed_projects[@]} -gt 0 ]; then
|
||||
echo "✅ PASSED (${#passed_projects[@]}):"
|
||||
printf ' - %s\n' "${passed_projects[@]}"
|
||||
echo
|
||||
fi
|
||||
|
||||
if [ ${#failed_projects[@]} -gt 0 ]; then
|
||||
echo "❌ FAILED (${#failed_projects[@]}):"
|
||||
printf ' - %s\n' "${failed_projects[@]}"
|
||||
echo
|
||||
fi
|
||||
|
||||
|
||||
echo "Total projects in shard: ${#shard_projects[@]}"
|
||||
echo "Passed: ${#passed_projects[@]}"
|
||||
echo "Failed: ${#failed_projects[@]}"
|
||||
echo "=========================================="
|
||||
|
||||
# Exit with overall status
|
||||
exit $overall_exit_code
|
||||
- name: Run Playwright tests
|
||||
run: pnpm exec playwright test
|
||||
working-directory: ./${{ matrix.project }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: ${{ hashFiles(format('{0}/package.json', matrix.project)) }}-playwright-report
|
||||
path: ./${{ matrix.project }}/playwright-report/
|
||||
retention-days: 30
|
||||
|
||||
7
.github/workflows/pre-release.yml
vendored
@@ -1,11 +1,4 @@
|
||||
name: Pre-Publish tagged Pull Requests
|
||||
|
||||
concurrency:
|
||||
# For pushes, this lets concurrent runs happen, so each push gets a result.
|
||||
# But for other events (e.g. PRs), we can cancel the previous runs.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
2
.github/workflows/release.yml
vendored
@@ -17,7 +17,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
8
.github/workflows/unit-test.yml
vendored
@@ -1,11 +1,5 @@
|
||||
name: Unit Tests
|
||||
|
||||
concurrency:
|
||||
# For pushes, this lets concurrent runs happen, so each push gets a result.
|
||||
# But for other events (e.g. PRs), we can cancel the previous runs.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
@@ -15,7 +9,7 @@ on:
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
3
.gitignore
vendored
@@ -20,9 +20,6 @@ __screenshots__
|
||||
# Playwright
|
||||
test-results
|
||||
|
||||
# Java
|
||||
.java-version
|
||||
|
||||
.husky
|
||||
|
||||
.vscode/*
|
||||
|
||||
@@ -63,7 +63,7 @@ You'll need Node.js 22.x installed (we're working on support for 23.x), and pnpm
|
||||
4. **Build the packages**:
|
||||
|
||||
```bash
|
||||
pnpm build:packages
|
||||
pnpm build
|
||||
```
|
||||
|
||||
5. **Run tests** to verify everything is working:
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
"jazz-tools.json",
|
||||
"**/ios/**",
|
||||
"**/android/**",
|
||||
"tests/jazz-svelte/src/**",
|
||||
"packages/jazz-svelte/**",
|
||||
"examples/*svelte*/**",
|
||||
"starters/*svelte*/**",
|
||||
"examples/jazz-paper-scissors/src/routeTree.gen.ts",
|
||||
"homepage/homepage/**",
|
||||
"**/package.json"
|
||||
@@ -56,7 +55,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": ["packages/cojson/src/storage/*/**", "cojson-transport-ws/**"],
|
||||
"include": ["packages/cojson-storage*/**", "cojson-transport-ws/**"],
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
@@ -65,7 +64,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": ["**/tests/**"],
|
||||
"include": ["packages/**/src/tests/**"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"correctness": {
|
||||
|
||||
6
examples/betterauth/.gitignore
vendored
@@ -36,10 +36,8 @@ yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
.env*
|
||||
!.env
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
@@ -1,221 +1,5 @@
|
||||
# betterauth
|
||||
|
||||
## 0.1.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [048ac1d]
|
||||
- jazz-tools@0.14.22
|
||||
- jazz-betterauth-server-plugin@0.14.22
|
||||
- jazz-inspector@0.14.22
|
||||
- jazz-react@0.14.22
|
||||
- jazz-react-auth-betterauth@0.14.22
|
||||
- jazz-betterauth-client-plugin@0.14.22
|
||||
|
||||
## 0.1.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e7e505e]
|
||||
- Updated dependencies [13b57aa]
|
||||
- Updated dependencies [5662faa]
|
||||
- Updated dependencies [2116a59]
|
||||
- jazz-tools@0.14.21
|
||||
- jazz-betterauth-server-plugin@0.14.21
|
||||
- jazz-inspector@0.14.21
|
||||
- jazz-react@0.14.21
|
||||
- jazz-react-auth-betterauth@0.14.21
|
||||
- jazz-betterauth-client-plugin@0.14.21
|
||||
|
||||
## 0.1.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6f72419]
|
||||
- Updated dependencies [04b20c2]
|
||||
- jazz-tools@0.14.20
|
||||
- jazz-betterauth-server-plugin@0.14.20
|
||||
- jazz-inspector@0.14.20
|
||||
- jazz-react@0.14.20
|
||||
- jazz-react-auth-betterauth@0.14.20
|
||||
- jazz-betterauth-client-plugin@0.14.20
|
||||
|
||||
## 0.1.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-betterauth-client-plugin@0.14.19
|
||||
- jazz-betterauth-server-plugin@0.14.19
|
||||
- jazz-react-auth-betterauth@0.14.19
|
||||
- jazz-inspector@0.14.19
|
||||
- jazz-react@0.14.19
|
||||
- jazz-tools@0.14.19
|
||||
|
||||
## 0.1.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4b950bc]
|
||||
- Updated dependencies [d6d9c0a]
|
||||
- Updated dependencies [c559054]
|
||||
- jazz-tools@0.14.18
|
||||
- jazz-betterauth-server-plugin@0.14.18
|
||||
- jazz-inspector@0.14.18
|
||||
- jazz-react@0.14.18
|
||||
- jazz-react-auth-betterauth@0.14.18
|
||||
- jazz-betterauth-client-plugin@0.14.18
|
||||
|
||||
## 0.1.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e512df4]
|
||||
- jazz-betterauth-server-plugin@0.14.17
|
||||
- jazz-tools@0.14.17
|
||||
- jazz-betterauth-client-plugin@0.14.17
|
||||
- jazz-inspector@0.14.17
|
||||
- jazz-react@0.14.17
|
||||
- jazz-react-auth-betterauth@0.14.17
|
||||
|
||||
## 0.1.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-betterauth-server-plugin@0.14.16
|
||||
- jazz-inspector@0.14.16
|
||||
- jazz-react@0.14.16
|
||||
- jazz-react-auth-betterauth@0.14.16
|
||||
- jazz-tools@0.14.16
|
||||
- jazz-betterauth-client-plugin@0.14.16
|
||||
|
||||
## 0.1.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [f9590f9]
|
||||
- jazz-react@0.14.15
|
||||
- jazz-betterauth-server-plugin@0.14.15
|
||||
- jazz-inspector@0.14.15
|
||||
- jazz-react-auth-betterauth@0.14.15
|
||||
- jazz-tools@0.14.15
|
||||
- jazz-betterauth-client-plugin@0.14.15
|
||||
|
||||
## 0.1.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e32a1f7]
|
||||
- jazz-tools@0.14.14
|
||||
- jazz-betterauth-server-plugin@0.14.14
|
||||
- jazz-inspector@0.14.14
|
||||
- jazz-react@0.14.14
|
||||
- jazz-react-auth-betterauth@0.14.14
|
||||
- jazz-betterauth-client-plugin@0.14.14
|
||||
|
||||
## 0.1.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-inspector@0.14.13
|
||||
- jazz-react@0.14.13
|
||||
- jazz-react-auth-betterauth@0.14.13
|
||||
|
||||
## 0.1.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-inspector@0.14.12
|
||||
- jazz-react@0.14.12
|
||||
- jazz-react-auth-betterauth@0.14.12
|
||||
|
||||
## 0.1.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [dc746a2]
|
||||
- Updated dependencies [f869d9a]
|
||||
- Updated dependencies [3fe6832]
|
||||
- jazz-react-auth-betterauth@0.14.10
|
||||
- jazz-inspector@0.14.10
|
||||
- jazz-react@0.14.10
|
||||
- jazz-tools@0.14.10
|
||||
- jazz-betterauth-server-plugin@0.14.10
|
||||
- jazz-betterauth-client-plugin@0.14.10
|
||||
|
||||
## 0.1.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [22c2600]
|
||||
- jazz-tools@0.14.9
|
||||
- jazz-betterauth-server-plugin@0.14.9
|
||||
- jazz-inspector@0.14.9
|
||||
- jazz-react@0.14.9
|
||||
- jazz-react-auth-betterauth@0.14.9
|
||||
- jazz-betterauth-client-plugin@0.14.9
|
||||
|
||||
## 0.1.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [637ae13]
|
||||
- jazz-tools@0.14.8
|
||||
- jazz-betterauth-server-plugin@0.14.8
|
||||
- jazz-inspector@0.14.8
|
||||
- jazz-react@0.14.8
|
||||
- jazz-react-auth-betterauth@0.14.8
|
||||
- jazz-betterauth-client-plugin@0.14.8
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [365b0ea]
|
||||
- jazz-tools@0.14.7
|
||||
- jazz-betterauth-server-plugin@0.14.7
|
||||
- jazz-inspector@0.14.7
|
||||
- jazz-react@0.14.7
|
||||
- jazz-react-auth-betterauth@0.14.7
|
||||
- jazz-betterauth-client-plugin@0.14.7
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9d6d9fe]
|
||||
- Updated dependencies [9d6d9fe]
|
||||
- jazz-tools@0.14.6
|
||||
- jazz-betterauth-server-plugin@0.14.6
|
||||
- jazz-inspector@0.14.6
|
||||
- jazz-react@0.14.6
|
||||
- jazz-react-auth-betterauth@0.14.6
|
||||
- jazz-betterauth-client-plugin@0.14.6
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [91cbb2f]
|
||||
- Updated dependencies [20b3d88]
|
||||
- jazz-tools@0.14.5
|
||||
- jazz-betterauth-server-plugin@0.14.5
|
||||
- jazz-inspector@0.14.5
|
||||
- jazz-react@0.14.5
|
||||
- jazz-react-auth-betterauth@0.14.5
|
||||
- jazz-betterauth-client-plugin@0.14.5
|
||||
|
||||
## 0.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [011af55]
|
||||
- jazz-tools@0.14.4
|
||||
- jazz-betterauth-server-plugin@0.14.4
|
||||
- jazz-inspector@0.14.4
|
||||
- jazz-react@0.14.4
|
||||
- jazz-react-auth-betterauth@0.14.4
|
||||
- jazz-betterauth-client-plugin@0.14.4
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -5,12 +5,10 @@ This example demonstrates how to integrate [Better Auth](https://www.better-auth
|
||||
## Getting started
|
||||
|
||||
To run this example, you may either:
|
||||
|
||||
- Clone the Jazz monorepo and run this example from within.
|
||||
- Create a new Jazz project using this example as a template, and run that new project.
|
||||
* Clone the Jazz monorepo and run this example from within.
|
||||
* Create a new Jazz project using this example as a template, and run that new project.
|
||||
|
||||
### Setting environment variables
|
||||
|
||||
- `NEXT_PUBLIC_AUTH_BASE_URL`: A URL to a Better Auth server. If undefined, the example will self-host a Better Auth server.
|
||||
- `BETTER_AUTH_SECRET`: The encryption secret used by the self-hosted Better Auth server (required only if `NEXT_PUBLIC_AUTH_BASE_URL` is undefined)
|
||||
- `GITHUB_CLIENT_ID`: The client ID for the GitHub OAuth provider used by the self-hosted Better Auth server (required only if `NEXT_PUBLIC_AUTH_BASE_URL` is undefined)
|
||||
@@ -19,64 +17,38 @@ To run this example, you may either:
|
||||
### Using this example as a template
|
||||
|
||||
1. Create a new Jazz project, and use this example as a template.
|
||||
|
||||
```sh
|
||||
npx create-jazz-app@latest betterauth-app --example betterauth
|
||||
```
|
||||
|
||||
2. Navigate to the new project and install dependencies.
|
||||
|
||||
2. Navigate to the new project and start the development server.
|
||||
```sh
|
||||
cd betterauth-app
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Create a .env file (don't forget to set your [BETTER_AUTH_SECRET](https://www.better-auth.com/docs/installation#set-environment-variables)!)
|
||||
|
||||
```sh
|
||||
mv .env.example .env
|
||||
```
|
||||
|
||||
4. Start the development server
|
||||
|
||||
```sh
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
https://www.better-auth.com/docs/installation#set-environment-variables
|
||||
|
||||
### Using the monorepo
|
||||
|
||||
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
|
||||
|
||||
Clone the jazz repository.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/garden-co/jazz.git
|
||||
```
|
||||
|
||||
Install and build dependencies.
|
||||
|
||||
```bash
|
||||
pnpm i && npx turbo build
|
||||
```
|
||||
|
||||
Go to the example directory.
|
||||
|
||||
```bash
|
||||
cd jazz/examples/betterauth/
|
||||
```
|
||||
|
||||
Create a .env file (don't forget to set your [BETTER_AUTH_SECRET](https://www.better-auth.com/docs/installation#set-environment-variables)!)
|
||||
|
||||
```sh
|
||||
mv .env.example .env
|
||||
```
|
||||
|
||||
Start the dev server.
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "betterauth",
|
||||
"version": "0.1.7",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -21,9 +22,11 @@
|
||||
"better-sqlite3": "^11.9.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"jazz-react-auth-betterauth": "workspace:*",
|
||||
"jazz-betterauth-client-plugin": "workspace:*",
|
||||
"jazz-betterauth-server-plugin": "workspace:*",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-react-auth-betterauth": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"lucide-react": "^0.510.0",
|
||||
"next": "15.3.2",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAccount } from "jazz-react";
|
||||
import { Account } from "jazz-tools";
|
||||
import { useAccount } from "jazz-tools/react";
|
||||
import {
|
||||
AppWindowMacIcon,
|
||||
FileTextIcon,
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import { JazzProvider } from "jazz-react";
|
||||
import { AuthProvider } from "jazz-react-auth-betterauth";
|
||||
import { JazzReactProvider } from "jazz-tools/react";
|
||||
import { type ReactNode, lazy } from "react";
|
||||
|
||||
const JazzDevTools =
|
||||
process.env.NODE_ENV === "production"
|
||||
? () => null
|
||||
: lazy(() =>
|
||||
import("jazz-tools/inspector").then((res) => ({
|
||||
import("jazz-inspector").then((res) => ({
|
||||
default: res.JazzInspector,
|
||||
})),
|
||||
);
|
||||
|
||||
export function JazzAndAuth({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<JazzReactProvider
|
||||
<JazzProvider
|
||||
sync={{
|
||||
peer: "wss://cloud.jazz.tools/?key=betterauth-example@garden.co",
|
||||
}}
|
||||
@@ -28,6 +28,6 @@ export function JazzAndAuth({ children }: { children: ReactNode }) {
|
||||
{children}
|
||||
</AuthProvider>
|
||||
<JazzDevTools />
|
||||
</JazzReactProvider>
|
||||
</JazzProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-react";
|
||||
import { useAuth } from "jazz-react-auth-betterauth";
|
||||
import { Account } from "jazz-tools";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-tools/react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useCallback } from "react";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-react";
|
||||
import { useAuth } from "jazz-react-auth-betterauth";
|
||||
import { useAccount, useIsAuthenticated } from "jazz-tools/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
|
||||
17
examples/chat-rn-expo-clerk/.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
node_modules/
|
||||
.expo/
|
||||
dist/
|
||||
npm-debug.*
|
||||
*.jks
|
||||
*.p8
|
||||
*.p12
|
||||
*.key
|
||||
*.mobileprovision
|
||||
*.orig.*
|
||||
web-build/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
ios
|
||||
android
|
||||
1158
examples/chat-rn-expo-clerk/CHANGELOG.md
Normal file
24
examples/chat-rn-expo-clerk/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# 🎷 Jazz + Expo + `expo-router` + Clerk Auth
|
||||
|
||||
## 🚀 How to Run
|
||||
|
||||
### 1. Inside the Workspace Root
|
||||
|
||||
First, install dependencies and build the project:
|
||||
|
||||
```bash
|
||||
pnpm i
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
### 2. Inside the `examples/chat-rn-expo-clerk` Directory
|
||||
|
||||
Next, navigate to the specific example project and run the following commands:
|
||||
|
||||
```bash
|
||||
pnpm expo prebuild
|
||||
pnpx pod-install
|
||||
pnpm expo run:ios
|
||||
```
|
||||
|
||||
This will set up and launch the app on iOS. For Android, you can replace the last command with `pnpm expo run:android`.
|
||||
45
examples/chat-rn-expo-clerk/app.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "jazz-chat-rn-expo-clerk",
|
||||
"scheme": "jazz-chat-rn-expo-clerk",
|
||||
"slug": "jazz-chat-rn-expo-clerk",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/images/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"splash": {
|
||||
"image": "./assets/images/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.jazz.chatrnclerk"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/images/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"package": "com.jazz.chatrnclerk"
|
||||
},
|
||||
"newArchEnabled": true,
|
||||
"plugins": [
|
||||
"expo-secure-store",
|
||||
"expo-font",
|
||||
"expo-router",
|
||||
"expo-sqlite",
|
||||
[
|
||||
"expo-image-picker",
|
||||
{
|
||||
"photosPermission": "The app accesses your photos to let you share them with your friends."
|
||||
}
|
||||
]
|
||||
],
|
||||
"extra": {
|
||||
"eas": {
|
||||
"projectId": "ca3d46e5-a10a-47ec-9d77-3b841e1c62d4"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
examples/chat-rn-expo-clerk/app/(app)/_layout.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Redirect, Stack } from "expo-router";
|
||||
import { useIsAuthenticated } from "jazz-expo";
|
||||
import React from "react";
|
||||
|
||||
export default function HomeLayout() {
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
|
||||
if (isAuthenticated) {
|
||||
return <Redirect href={"/chat"} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack screenOptions={{ headerShown: false, headerBackVisible: true }} />
|
||||
);
|
||||
}
|
||||
33
examples/chat-rn-expo-clerk/app/(app)/index.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { SignedOut } from "@clerk/clerk-expo";
|
||||
import { Link } from "expo-router";
|
||||
import React from "react";
|
||||
import { Text, View } from "react-native";
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<View className="flex-1 justify-center items-center bg-gray-100 p-6">
|
||||
<SignedOut>
|
||||
<View className="bg-white p-6 rounded-lg shadow-lg w-11/12 max-w-md">
|
||||
<Text className="text-2xl font-bold text-center text-gray-900 mb-4">
|
||||
Jazz 🤝 Clerk 🤝 Expo
|
||||
</Text>
|
||||
<Link href="/sign-in" className="mb-4">
|
||||
<Text className="text-center text-blue-600 underline text-lg">
|
||||
Sign In
|
||||
</Text>
|
||||
</Link>
|
||||
<Link href="/sign-in-oauth" className="mb-4">
|
||||
<Text className="text-center text-blue-600 underline text-lg">
|
||||
Sign In OAuth
|
||||
</Text>
|
||||
</Link>
|
||||
<Link href="/sign-up">
|
||||
<Text className="text-center text-blue-600 underline text-lg">
|
||||
Sign Up
|
||||
</Text>
|
||||
</Link>
|
||||
</View>
|
||||
</SignedOut>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
20
examples/chat-rn-expo-clerk/app/(auth)/_layout.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Redirect, Stack } from "expo-router";
|
||||
import { useIsAuthenticated } from "jazz-expo";
|
||||
|
||||
export default function UnAuthenticatedLayout() {
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
|
||||
if (isAuthenticated) {
|
||||
return <Redirect href={"/chat"} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack
|
||||
screenOptions={{
|
||||
headerShown: true,
|
||||
headerBackVisible: true,
|
||||
headerTitle: "",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
65
examples/chat-rn-expo-clerk/app/(auth)/sign-in-oauth.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useOAuth } from "@clerk/clerk-expo";
|
||||
import * as Linking from "expo-linking";
|
||||
import { Link } from "expo-router";
|
||||
import * as WebBrowser from "expo-web-browser";
|
||||
import React from "react";
|
||||
import { Text, TouchableOpacity, View } from "react-native";
|
||||
|
||||
export const useWarmUpBrowser = () => {
|
||||
React.useEffect(() => {
|
||||
// Warm up the android browser to improve UX
|
||||
// https://docs.expo.dev/guides/authentication/#improving-user-experience
|
||||
void WebBrowser.warmUpAsync();
|
||||
return () => {
|
||||
void WebBrowser.coolDownAsync();
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
|
||||
WebBrowser.maybeCompleteAuthSession();
|
||||
|
||||
const SignInWithOAuth = () => {
|
||||
useWarmUpBrowser();
|
||||
|
||||
const { startOAuthFlow } = useOAuth({ strategy: "oauth_google" });
|
||||
|
||||
const onPress = React.useCallback(async () => {
|
||||
try {
|
||||
const { createdSessionId, signIn, signUp, setActive } =
|
||||
await startOAuthFlow({
|
||||
redirectUrl: Linking.createURL("/", {
|
||||
scheme: "jazz-chat-rn-expo-clerk",
|
||||
}),
|
||||
});
|
||||
|
||||
if (createdSessionId) {
|
||||
setActive!({ session: createdSessionId });
|
||||
} else {
|
||||
// Use signIn or signUp for next steps such as MFA
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("OAuth error", err);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
|
||||
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-lg items-center">
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
className="w-full bg-red-500 py-3 rounded-lg flex items-center justify-center"
|
||||
>
|
||||
<Text className="text-white text-lg font-semibold">
|
||||
Sign in with Google
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<Link href="/" className="mt-4">
|
||||
<Text className="text-blue-600 text-lg font-semibold underline mb-6">
|
||||
Back to Home
|
||||
</Text>
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
export default SignInWithOAuth;
|
||||
79
examples/chat-rn-expo-clerk/app/(auth)/sign-in.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { useSignIn } from "@clerk/clerk-expo";
|
||||
import { Link } from "expo-router";
|
||||
import React from "react";
|
||||
import { Text, TextInput, TouchableOpacity, View } from "react-native";
|
||||
|
||||
export default function SignInPage() {
|
||||
const { signIn, setActive, isLoaded } = useSignIn();
|
||||
const [emailAddress, setEmailAddress] = React.useState("");
|
||||
const [password, setPassword] = React.useState("");
|
||||
const [errorMessage, setErrorMessage] = React.useState("");
|
||||
|
||||
const onSignInPress = React.useCallback(async () => {
|
||||
if (!isLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
setErrorMessage("");
|
||||
|
||||
try {
|
||||
const signInAttempt = await signIn.create({
|
||||
identifier: emailAddress,
|
||||
password,
|
||||
});
|
||||
|
||||
if (signInAttempt.status === "complete") {
|
||||
await setActive({ session: signInAttempt.createdSessionId });
|
||||
} else {
|
||||
console.error(JSON.stringify(signInAttempt, null, 2));
|
||||
setErrorMessage("Invalid credentials. Please try again.");
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error(JSON.stringify(err, null, 2));
|
||||
if (err.errors && err.errors[0]?.message) {
|
||||
setErrorMessage(err.errors[0].message);
|
||||
} else {
|
||||
setErrorMessage("An unexpected error occurred. Please try again.");
|
||||
}
|
||||
}
|
||||
}, [isLoaded, emailAddress, password]);
|
||||
|
||||
return (
|
||||
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
|
||||
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-md">
|
||||
<Text className="text-3xl font-bold text-center text-gray-800 mb-6">
|
||||
Sign In
|
||||
</Text>
|
||||
{errorMessage ? (
|
||||
<Text className="text-red-500 text-center mb-4">{errorMessage}</Text>
|
||||
) : null}
|
||||
<TextInput
|
||||
autoCapitalize="none"
|
||||
value={emailAddress}
|
||||
placeholder="Email..."
|
||||
onChangeText={(emailAddress) => setEmailAddress(emailAddress)}
|
||||
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
|
||||
/>
|
||||
<TextInput
|
||||
value={password}
|
||||
placeholder="Password..."
|
||||
secureTextEntry={true}
|
||||
onChangeText={(password) => setPassword(password)}
|
||||
className="w-full h-12 mb-6 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
|
||||
/>
|
||||
<TouchableOpacity
|
||||
onPress={onSignInPress}
|
||||
className="w-full h-12 bg-blue-600 rounded-lg flex items-center justify-center"
|
||||
>
|
||||
<Text className="text-white text-lg font-semibold">Sign In</Text>
|
||||
</TouchableOpacity>
|
||||
<View className="flex-row items-center justify-center mt-4">
|
||||
<Text className="text-gray-600">Don't have an account?</Text>
|
||||
<Link href="/sign-up">
|
||||
<Text className="text-blue-500 ml-2 font-semibold">Sign up</Text>
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
120
examples/chat-rn-expo-clerk/app/(auth)/sign-up.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { useSignUp } from "@clerk/clerk-expo";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import * as React from "react";
|
||||
import { Text, TextInput, TouchableOpacity, View } from "react-native";
|
||||
|
||||
export default function SignUpPage() {
|
||||
const { isLoaded, signUp, setActive } = useSignUp();
|
||||
|
||||
const [emailAddress, setEmailAddress] = React.useState("");
|
||||
const [password, setPassword] = React.useState("");
|
||||
const [pendingVerification, setPendingVerification] = React.useState(false);
|
||||
const [code, setCode] = React.useState("");
|
||||
const [errorMessage, setErrorMessage] = React.useState("");
|
||||
const navigation = useNavigation();
|
||||
|
||||
const onSignUpPress = async () => {
|
||||
if (!isLoaded) return;
|
||||
|
||||
setErrorMessage("");
|
||||
|
||||
try {
|
||||
await signUp.create({
|
||||
emailAddress,
|
||||
password,
|
||||
});
|
||||
|
||||
await signUp.prepareEmailAddressVerification({
|
||||
strategy: "email_code",
|
||||
});
|
||||
|
||||
setPendingVerification(true);
|
||||
} catch (err: any) {
|
||||
console.error(JSON.stringify(err, null, 2));
|
||||
if (err.errors && err.errors[0]?.message) {
|
||||
setErrorMessage(err.errors[0].message);
|
||||
} else {
|
||||
setErrorMessage("An unexpected error occurred. Please try again.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onPressVerify = async () => {
|
||||
if (!isLoaded) return;
|
||||
|
||||
setErrorMessage("");
|
||||
|
||||
try {
|
||||
const completeSignUp = await signUp.attemptEmailAddressVerification({
|
||||
code,
|
||||
});
|
||||
|
||||
if (completeSignUp.status === "complete") {
|
||||
await setActive({ session: completeSignUp.createdSessionId });
|
||||
} else {
|
||||
console.error(JSON.stringify(completeSignUp, null, 2));
|
||||
setErrorMessage("Failed to verify. Please check your code.");
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error(JSON.stringify(err, null, 2));
|
||||
setErrorMessage("Invalid verification code. Please try again.");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
|
||||
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-lg">
|
||||
<Text className="text-3xl font-bold text-center text-gray-800 mb-6">
|
||||
{pendingVerification ? "Verify Email" : "Sign Up"}
|
||||
</Text>
|
||||
{errorMessage ? (
|
||||
<Text className="text-red-500 text-center mb-4">{errorMessage}</Text>
|
||||
) : null}
|
||||
|
||||
{!pendingVerification && (
|
||||
<>
|
||||
<TextInput
|
||||
autoCapitalize="none"
|
||||
value={emailAddress}
|
||||
placeholder="Email..."
|
||||
onChangeText={(email) => setEmailAddress(email)}
|
||||
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
|
||||
/>
|
||||
<TextInput
|
||||
value={password}
|
||||
placeholder="Password..."
|
||||
secureTextEntry={true}
|
||||
onChangeText={(password) => setPassword(password)}
|
||||
className="w-full h-12 mb-6 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
|
||||
/>
|
||||
<TouchableOpacity
|
||||
onPress={onSignUpPress}
|
||||
className="w-full h-12 bg-blue-600 rounded-lg flex justify-center items-center mb-4"
|
||||
>
|
||||
<Text className="text-white text-lg font-semibold">Sign Up</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
)}
|
||||
|
||||
{pendingVerification && (
|
||||
<>
|
||||
<TextInput
|
||||
value={code}
|
||||
placeholder="Verification Code..."
|
||||
onChangeText={(code) => setCode(code)}
|
||||
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
|
||||
/>
|
||||
<TouchableOpacity
|
||||
onPress={onPressVerify}
|
||||
className="w-full h-12 bg-green-600 rounded-lg flex justify-center items-center mb-4"
|
||||
>
|
||||
<Text className="text-white text-lg font-semibold">
|
||||
Verify Email
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
42
examples/chat-rn-expo-clerk/app/+html.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { ScrollViewStyleReset } from "expo-router/html";
|
||||
import { type PropsWithChildren } from "react";
|
||||
|
||||
/**
|
||||
* This file is web-only and used to configure the root HTML for every web page during static rendering.
|
||||
* The contents of this function only run in Node.js environments and do not have access to the DOM or browser APIs.
|
||||
*/
|
||||
export default function Root({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
|
||||
{/*
|
||||
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
|
||||
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
|
||||
*/}
|
||||
<ScrollViewStyleReset />
|
||||
|
||||
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
|
||||
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
|
||||
{/* Add any additional <head> elements that you want globally available on web... */}
|
||||
</head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
const responsiveBackground = `
|
||||
body {
|
||||
background-color: #fff;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: #000;
|
||||
}
|
||||
}`;
|
||||
29
examples/chat-rn-expo-clerk/app/+not-found.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Link, Stack } from "expo-router";
|
||||
import { StyleSheet, Text, View } from "react-native";
|
||||
|
||||
export default function NotFoundScreen() {
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen options={{ title: "Oops!" }} />
|
||||
<View style={styles.container}>
|
||||
<Text>This screen doesn't exist.</Text>
|
||||
<Link href="/" style={styles.link}>
|
||||
<Text>Go to home screen!</Text>
|
||||
</Link>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: 20,
|
||||
},
|
||||
link: {
|
||||
marginTop: 15,
|
||||
paddingVertical: 15,
|
||||
},
|
||||
});
|
||||
71
examples/chat-rn-expo-clerk/app/_layout.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import "../global.css";
|
||||
import { ClerkLoaded, ClerkProvider } from "@clerk/clerk-expo";
|
||||
import { secureStore } from "@clerk/clerk-expo/secure-store";
|
||||
import { useFonts } from "expo-font";
|
||||
import { Slot, useRouter, useSegments } from "expo-router";
|
||||
import * as SplashScreen from "expo-splash-screen";
|
||||
import { useIsAuthenticated, useJazzContext } from "jazz-expo";
|
||||
import React, { useEffect } from "react";
|
||||
import { tokenCache } from "../cache";
|
||||
import { JazzAndAuth } from "../src/auth-context";
|
||||
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
|
||||
function InitialLayout() {
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const segments = useSegments();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const inAuthGroup = segments[0] === "(auth)";
|
||||
|
||||
if (isAuthenticated && inAuthGroup) {
|
||||
router.replace("/chat");
|
||||
} else if (!isAuthenticated && !inAuthGroup) {
|
||||
router.replace("/");
|
||||
}
|
||||
|
||||
SplashScreen.hideAsync();
|
||||
}, [isAuthenticated, segments, router]);
|
||||
|
||||
return <Slot />;
|
||||
}
|
||||
|
||||
export default function RootLayout() {
|
||||
const [fontsLoaded] = useFonts({
|
||||
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
|
||||
});
|
||||
|
||||
const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;
|
||||
|
||||
if (!publishableKey) {
|
||||
throw new Error(
|
||||
"Missing Publishable Key. Please set EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY in your .env",
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (fontsLoaded) {
|
||||
} else {
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
}
|
||||
}, [fontsLoaded]);
|
||||
|
||||
if (!fontsLoaded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ClerkProvider
|
||||
tokenCache={tokenCache}
|
||||
publishableKey={publishableKey}
|
||||
__experimental_resourceCache={secureStore}
|
||||
>
|
||||
<ClerkLoaded>
|
||||
<JazzAndAuth>
|
||||
<InitialLayout />
|
||||
</JazzAndAuth>
|
||||
</ClerkLoaded>
|
||||
</ClerkProvider>
|
||||
);
|
||||
}
|
||||
234
examples/chat-rn-expo-clerk/app/chat/[chatId].tsx
Normal file
@@ -0,0 +1,234 @@
|
||||
import { Chat, Message } from "@/src/schema";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import clsx from "clsx";
|
||||
import * as Clipboard from "expo-clipboard";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import { useLocalSearchParams } from "expo-router";
|
||||
import { useAccount, useCoState } from "jazz-expo";
|
||||
import { ProgressiveImg } from "jazz-expo";
|
||||
import { createImage } from "jazz-react-native-media-images";
|
||||
import { CoPlainText, Group, Loaded } from "jazz-tools";
|
||||
import { useEffect, useLayoutEffect, useState } from "react";
|
||||
import React, {
|
||||
SafeAreaView,
|
||||
View,
|
||||
Text,
|
||||
Alert,
|
||||
TouchableOpacity,
|
||||
FlatList,
|
||||
KeyboardAvoidingView,
|
||||
TextInput,
|
||||
Button,
|
||||
Image,
|
||||
ActivityIndicator,
|
||||
} from "react-native";
|
||||
|
||||
export default function Conversation() {
|
||||
const { chatId } = useLocalSearchParams();
|
||||
const { me } = useAccount();
|
||||
const [chat, setChat] = useState<Loaded<typeof Chat>>();
|
||||
const [message, setMessage] = useState("");
|
||||
const loadedChat = useCoState(Chat, chat?.id, { resolve: { $each: true } });
|
||||
const navigation = useNavigation();
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (chat) return;
|
||||
if (chatId === "new") {
|
||||
createChat();
|
||||
} else {
|
||||
loadChat(chatId as string);
|
||||
}
|
||||
}, [chat]);
|
||||
|
||||
// Effect to dynamically set header options
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerTitle: "Chat",
|
||||
headerRight: () =>
|
||||
chat ? (
|
||||
<Button
|
||||
onPress={() => {
|
||||
if (chat?.id) {
|
||||
Clipboard.setStringAsync(
|
||||
`https://chat.jazz.tools/#/chat/${chat.id}`,
|
||||
);
|
||||
Alert.alert("Copied to clipboard", `Chat ID: ${chat.id}`);
|
||||
}
|
||||
}}
|
||||
title="Share"
|
||||
/>
|
||||
) : null,
|
||||
});
|
||||
}, [navigation, chat]);
|
||||
|
||||
const createChat = () => {
|
||||
const group = Group.create({ owner: me });
|
||||
group.addMember("everyone", "writer");
|
||||
const chat = Chat.create([], { owner: group });
|
||||
setChat(chat);
|
||||
};
|
||||
|
||||
const loadChat = async (chatId: string) => {
|
||||
try {
|
||||
const chat = await Chat.load(chatId);
|
||||
if (chat) setChat(chat);
|
||||
} catch (error) {
|
||||
console.log("Error loading chat", error);
|
||||
Alert.alert("Error", `Error loading chat: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
const sendMessage = () => {
|
||||
if (!chat) return;
|
||||
if (message.trim()) {
|
||||
chat.push(
|
||||
Message.create(
|
||||
{ text: CoPlainText.create(message, chat._owner) },
|
||||
chat._owner,
|
||||
),
|
||||
);
|
||||
setMessage("");
|
||||
}
|
||||
};
|
||||
|
||||
const handleImageUpload = async () => {
|
||||
try {
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
base64: true,
|
||||
quality: 0.7,
|
||||
});
|
||||
|
||||
if (!result.canceled && result.assets[0].base64 && chat) {
|
||||
setIsUploading(true);
|
||||
const base64Uri = `data:image/jpeg;base64,${result.assets[0].base64}`;
|
||||
|
||||
const image = await createImage(base64Uri, {
|
||||
owner: chat._owner,
|
||||
maxSize: 2048,
|
||||
});
|
||||
|
||||
chat.push(
|
||||
Message.create(
|
||||
{ text: CoPlainText.create("", chat._owner), image },
|
||||
chat._owner,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
Alert.alert("Error", "Failed to upload image");
|
||||
} finally {
|
||||
setIsUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const renderMessageItem = ({ item }: { item: Loaded<typeof Message> }) => {
|
||||
const isMe = item._edits.text?.by?.isMe;
|
||||
return (
|
||||
<View
|
||||
className={clsx(
|
||||
`rounded-xl px-3 py-2 max-w-[75%] my-1`,
|
||||
isMe ? `bg-blue-500 self-end` : `bg-gray-200 self-start`,
|
||||
)}
|
||||
>
|
||||
{!isMe ? (
|
||||
<Text
|
||||
className={clsx(
|
||||
`text-xs text-gray-500 mb-1`,
|
||||
isMe ? "text-right" : "text-left",
|
||||
)}
|
||||
>
|
||||
{item._edits.text?.by?.profile?.name}
|
||||
</Text>
|
||||
) : null}
|
||||
<View
|
||||
className={clsx(
|
||||
"flex relative items-end justify-between",
|
||||
isMe ? "flex-row" : "flex-row",
|
||||
)}
|
||||
>
|
||||
{item.image && (
|
||||
<ProgressiveImg image={item.image} maxWidth={1024}>
|
||||
{({ src, res, originalSize }) => (
|
||||
<Image
|
||||
source={{ uri: src }}
|
||||
className="w-48 h-48 rounded-lg mb-2"
|
||||
resizeMode="cover"
|
||||
/>
|
||||
)}
|
||||
</ProgressiveImg>
|
||||
)}
|
||||
{item.text && (
|
||||
<Text
|
||||
className={clsx(
|
||||
!isMe ? "text-black" : "text-gray-200",
|
||||
`text-md max-w-[85%]`,
|
||||
)}
|
||||
>
|
||||
{item.text}
|
||||
</Text>
|
||||
)}
|
||||
<Text
|
||||
className={clsx(
|
||||
"text-[10px] text-right ml-2",
|
||||
!isMe ? "mt-2 text-gray-500" : "mt-1 text-gray-200",
|
||||
)}
|
||||
>
|
||||
{item._edits.text?.madeAt?.getHours().toString().padStart(2, "0")}:
|
||||
{item._edits.text?.madeAt?.getMinutes().toString().padStart(2, "0")}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex-1 bg-gray-50">
|
||||
<FlatList
|
||||
contentContainerStyle={{
|
||||
flexGrow: 1,
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 8,
|
||||
}}
|
||||
className="flex"
|
||||
data={loadedChat}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={renderMessageItem}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
keyboardVerticalOffset={110}
|
||||
behavior="padding"
|
||||
className="p-3 bg-white border-t border-gray-300"
|
||||
>
|
||||
<SafeAreaView className="flex-row items-center gap-2">
|
||||
<TouchableOpacity
|
||||
onPress={handleImageUpload}
|
||||
disabled={isUploading}
|
||||
className="h-10 w-10 items-center justify-center"
|
||||
>
|
||||
{isUploading ? (
|
||||
<ActivityIndicator size="small" color="#0000ff" />
|
||||
) : (
|
||||
<Text className="text-2xl">🖼️</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<TextInput
|
||||
className="flex-1 rounded-full h-10 px-4 bg-gray-100 border border-gray-300 focus:border-blue-500 focus:bg-white"
|
||||
value={message}
|
||||
onChangeText={setMessage}
|
||||
placeholder="Type a message..."
|
||||
textAlignVertical="center"
|
||||
onSubmitEditing={sendMessage}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
onPress={sendMessage}
|
||||
className="bg-blue-500 rounded-full h-10 w-10 items-center justify-center"
|
||||
>
|
||||
<Text className="text-white text-xl">↑</Text>
|
||||
</TouchableOpacity>
|
||||
</SafeAreaView>
|
||||
</KeyboardAvoidingView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
14
examples/chat-rn-expo-clerk/app/chat/_layout.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Stack } from "expo-router";
|
||||
import React from "react";
|
||||
|
||||
export default function ChatLayout() {
|
||||
return (
|
||||
<Stack
|
||||
screenOptions={{
|
||||
headerShown: true,
|
||||
headerBackVisible: true,
|
||||
headerTitle: "",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
90
examples/chat-rn-expo-clerk/app/chat/index.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { useRouter } from "expo-router";
|
||||
import { ID } from "jazz-tools";
|
||||
import { useLayoutEffect } from "react";
|
||||
import React, {
|
||||
Button,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
Alert,
|
||||
} from "react-native";
|
||||
|
||||
import { useUser } from "@clerk/clerk-expo";
|
||||
import { useAccount } from "jazz-expo";
|
||||
import { Chat } from "../../src/schema";
|
||||
|
||||
export default function ChatScreen() {
|
||||
const { logOut } = useAccount();
|
||||
const router = useRouter();
|
||||
const navigation = useNavigation();
|
||||
const { user } = useUser();
|
||||
|
||||
function handleLogOut() {
|
||||
logOut();
|
||||
router.navigate("/");
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerTitle: "Chat",
|
||||
headerRight: () => <Button onPress={handleLogOut} title="Logout" />,
|
||||
});
|
||||
}, [navigation]);
|
||||
|
||||
const loadChat = async (chatId: string | "new") => {
|
||||
router.navigate(`/chat/${chatId}`);
|
||||
};
|
||||
|
||||
const joinChat = () => {
|
||||
Alert.prompt(
|
||||
"Join Chat",
|
||||
"Enter the Chat ID (example: co_zBGEHYvRfGuT2YSBraY3njGjnde)",
|
||||
[
|
||||
{
|
||||
text: "Cancel",
|
||||
style: "cancel",
|
||||
},
|
||||
{
|
||||
text: "Join",
|
||||
onPress: (chatId) => {
|
||||
if (chatId) {
|
||||
loadChat(chatId);
|
||||
} else {
|
||||
Alert.alert("Error", "Chat ID cannot be empty.");
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
"plain-text",
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex-1 bg-gray-50">
|
||||
<View className="flex-1 justify-center items-center px-6">
|
||||
<View className="w-full max-w-sm bg-white p-8 rounded-lg shadow-lg">
|
||||
<Text className="text-xl font-semibold text-gray-800">
|
||||
Welcome, {user?.emailAddresses[0].emailAddress}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => loadChat("new")}
|
||||
className="w-full bg-blue-600 py-4 rounded-md mb-4 mt-4"
|
||||
>
|
||||
<Text className="text-white text-lg font-semibold text-center">
|
||||
Start New Chat
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={joinChat}
|
||||
className="w-full bg-green-500 py-4 rounded-md"
|
||||
>
|
||||
<Text className="text-white text-lg font-semibold text-center">
|
||||
Join Chat
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
BIN
examples/chat-rn-expo-clerk/assets/fonts/SpaceMono-Regular.ttf
Executable file
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
BIN
examples/chat-rn-expo-clerk/assets/images/dark-logo.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
examples/chat-rn-expo-clerk/assets/images/hero.png
Normal file
|
After Width: | Height: | Size: 313 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
BIN
examples/chat-rn-expo-clerk/assets/images/light-logo.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
examples/chat-rn-expo-clerk/assets/images/partial-react-logo.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
examples/chat-rn-expo-clerk/assets/images/react-logo.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
examples/chat-rn-expo-clerk/assets/images/react-logo@2x.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
examples/chat-rn-expo-clerk/assets/images/react-logo@3x.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
examples/chat-rn-expo-clerk/assets/images/splash.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
9
examples/chat-rn-expo-clerk/babel.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
module.exports = function (api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: [
|
||||
["babel-preset-expo", { jsxImportSource: "nativewind" }],
|
||||
"nativewind/babel",
|
||||
],
|
||||
};
|
||||
};
|
||||
39
examples/chat-rn-expo-clerk/cache.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import * as SecureStore from "expo-secure-store";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
export interface TokenCache {
|
||||
getToken: (key: string) => Promise<string | undefined | null>;
|
||||
saveToken: (key: string, token: string) => Promise<void>;
|
||||
clearToken: (key: string) => void;
|
||||
}
|
||||
|
||||
const createTokenCache = (): TokenCache => {
|
||||
return {
|
||||
getToken: async (key: string) => {
|
||||
try {
|
||||
const item = await SecureStore.getItemAsync(key);
|
||||
if (item) {
|
||||
console.log(`${key} was used 🔐 \n`);
|
||||
} else {
|
||||
console.log("No values stored under key: " + key);
|
||||
}
|
||||
return item;
|
||||
} catch (error) {
|
||||
console.error("secure store get item error: ", error);
|
||||
await SecureStore.deleteItemAsync(key);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
saveToken: (key: string, token: string) => {
|
||||
return SecureStore.setItemAsync(key, token);
|
||||
},
|
||||
clearToken: (key: string) => {
|
||||
return SecureStore.deleteItemAsync(key);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// SecureStore is not supported on the web
|
||||
// https://github.com/expo/expo/issues/7744#issuecomment-611093485
|
||||
export const tokenCache =
|
||||
Platform.OS !== "web" ? createTokenCache() : undefined;
|
||||
27
examples/chat-rn-expo-clerk/eas.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"cli": {
|
||||
"version": ">= 12.5.1",
|
||||
"appVersionSource": "remote"
|
||||
},
|
||||
"build": {
|
||||
"development": {
|
||||
"developmentClient": true,
|
||||
"distribution": "internal"
|
||||
},
|
||||
"ios-simulator": {
|
||||
"extends": "development",
|
||||
"ios": {
|
||||
"simulator": true
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
"distribution": "internal"
|
||||
},
|
||||
"production": {
|
||||
"autoIncrement": true
|
||||
}
|
||||
},
|
||||
"submit": {
|
||||
"production": {}
|
||||
}
|
||||
}
|
||||
2
examples/chat-rn-expo-clerk/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import "./polyfills";
|
||||
import "expo-router/entry";
|
||||
35
examples/chat-rn-expo-clerk/metro.config.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// Learn more https://docs.expo.dev/guides/monorepos
|
||||
const { getDefaultConfig } = require("expo/metro-config");
|
||||
const { withNativeWind } = require("nativewind/metro");
|
||||
const { FileStore } = require("metro-cache");
|
||||
const path = require("path");
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const projectRoot = __dirname;
|
||||
const workspaceRoot = path.resolve(projectRoot, "../..");
|
||||
|
||||
const config = getDefaultConfig(projectRoot);
|
||||
|
||||
// Since we are using pnpm, we have to setup the monorepo manually for Metro
|
||||
// #1 - Watch all files in the monorepo
|
||||
config.watchFolders = [workspaceRoot];
|
||||
// #2 - Try resolving with project modules first, then workspace modules
|
||||
config.resolver.nodeModulesPaths = [
|
||||
path.resolve(projectRoot, "node_modules"),
|
||||
path.resolve(workspaceRoot, "node_modules"),
|
||||
];
|
||||
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
|
||||
config.resolver.requireCycleIgnorePatterns = [
|
||||
/(^|\/|\\)node_modules($|\/|\\)/,
|
||||
/(^|\/|\\)packages($|\/|\\)/,
|
||||
];
|
||||
|
||||
// Use turborepo to restore the cache when possible
|
||||
config.cacheStores = [
|
||||
new FileStore({
|
||||
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
|
||||
}),
|
||||
];
|
||||
|
||||
// module.exports = config;
|
||||
module.exports = withNativeWind(config, { input: "./global.css" });
|
||||
1
examples/chat-rn-expo-clerk/nativewind-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="nativewind/types" />
|
||||
67
examples/chat-rn-expo-clerk/package.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "chat-rn-expo-clerk",
|
||||
"main": "index.js",
|
||||
"version": "1.0.126",
|
||||
"scripts": {
|
||||
"build": "expo export -p ios",
|
||||
"start": "expo start",
|
||||
"format-and-lint": "biome check .",
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo prebuild && pnpx pod-install && expo run:ios",
|
||||
"web": "expo start --web",
|
||||
"run:ios": "pnpm expo prebuild && npx pod-install && pnpm expo run:ios"
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@bacons/text-decoder": "0.0.0",
|
||||
"@bam.tech/react-native-image-resizer": "^3.0.11",
|
||||
"@clerk/clerk-expo": "^2.2.21",
|
||||
"@craftzdog/react-native-buffer": "6.0.5",
|
||||
"@expo/vector-icons": "^14.1.0",
|
||||
"@react-native-community/netinfo": "11.4.1",
|
||||
"@react-navigation/native": "7.0.19",
|
||||
"@react-navigation/native-stack": "7.2.1",
|
||||
"clsx": "^2.0.0",
|
||||
"expo": "^53.0.8",
|
||||
"expo-build-properties": "~0.14.6",
|
||||
"expo-clipboard": "~7.1.4",
|
||||
"expo-constants": "~17.1.6",
|
||||
"expo-crypto": "~14.1.4",
|
||||
"expo-dev-client": "~5.1.8",
|
||||
"expo-file-system": "^18.1.9",
|
||||
"expo-font": "~13.3.1",
|
||||
"expo-image-picker": "~16.1.4",
|
||||
"expo-linking": "~7.1.4",
|
||||
"expo-router": "~5.0.6",
|
||||
"expo-secure-store": "~14.2.3",
|
||||
"expo-splash-screen": "~0.30.8",
|
||||
"expo-sqlite": "15.2.9",
|
||||
"expo-status-bar": "~2.2.3",
|
||||
"expo-web-browser": "~14.1.6",
|
||||
"jazz-expo": "workspace:*",
|
||||
"jazz-react-native-media-images": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"nativewind": "^4.1.21",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-native": "0.79.2",
|
||||
"react-native-gesture-handler": "~2.24.0",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"react-native-reanimated": "~3.17.5",
|
||||
"react-native-safe-area-context": "5.4.0",
|
||||
"react-native-screens": "4.10.0",
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"react-native-web": "~0.20.0",
|
||||
"readable-stream": "4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@types/react": "~19.0.14",
|
||||
"@types/react-test-renderer": "^19.0.0",
|
||||
"react-test-renderer": "18.3.1",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "5.8.3"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
@@ -3,6 +3,9 @@
|
||||
// @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);
|
||||
1
examples/chat-rn-expo-clerk/src/apiKey.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const apiKey = "chat-rn-expo-clerk-example-jazz@garden.co";
|
||||
19
examples/chat-rn-expo-clerk/src/auth-context.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useClerk } from "@clerk/clerk-expo";
|
||||
import { JazzProviderWithClerk } from "jazz-expo/auth/clerk";
|
||||
import React, { PropsWithChildren } from "react";
|
||||
import { apiKey } from "./apiKey";
|
||||
|
||||
export function JazzAndAuth({ children }: PropsWithChildren) {
|
||||
const clerk = useClerk();
|
||||
|
||||
return (
|
||||
<JazzProviderWithClerk
|
||||
clerk={clerk}
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</JazzProviderWithClerk>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { co, z } from 'jazz-tools';
|
||||
import { CoList, co, coField, z } from "jazz-tools";
|
||||
|
||||
export const Message = co.map({
|
||||
text: co.plainText(),
|
||||
image: z.optional(co.image())
|
||||
image: z.optional(co.image()),
|
||||
});
|
||||
|
||||
export const Chat = co.list(Message);
|
||||
14
examples/chat-rn-expo-clerk/tailwind.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
// NOTE: Update this to include the paths to all of your component files.
|
||||
content: [
|
||||
"./app/**/*.{js,jsx,ts,tsx}",
|
||||
"./components/**/*.{js,jsx,ts,tsx}",
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
],
|
||||
presets: [require("nativewind/preset")],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
11
examples/chat-rn-expo-clerk/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler",
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx", "nativewind-env.d.ts"]
|
||||
}
|
||||
12
examples/chat-rn-expo/.gitignore
vendored
@@ -7,10 +7,8 @@ node_modules/
|
||||
.expo/
|
||||
dist/
|
||||
web-build/
|
||||
expo-env.d.ts
|
||||
|
||||
# Native
|
||||
.kotlin/
|
||||
*.orig.*
|
||||
*.jks
|
||||
*.p8
|
||||
@@ -35,10 +33,6 @@ yarn-error.*
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
android/
|
||||
ios/
|
||||
# env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
ios
|
||||
android
|
||||
|
||||
@@ -1,107 +1,943 @@
|
||||
# chat-rn-expo
|
||||
|
||||
## 1.0.113
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3d1027f]
|
||||
- Updated dependencies [c240eed]
|
||||
- jazz-tools@0.14.2
|
||||
- jazz-expo@0.14.2
|
||||
|
||||
## 1.0.112
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [cdfc105]
|
||||
- jazz-tools@0.14.1
|
||||
- jazz-expo@0.14.1
|
||||
|
||||
## 1.0.111
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5835ed1]
|
||||
- jazz-tools@0.14.0
|
||||
- jazz-expo@0.14.0
|
||||
|
||||
## 1.0.110
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.32
|
||||
|
||||
## 1.0.109
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e5b170f]
|
||||
- jazz-tools@0.13.31
|
||||
- jazz-expo@0.13.31
|
||||
|
||||
## 1.0.108
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.30
|
||||
- jazz-tools@0.13.30
|
||||
|
||||
## 1.0.107
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.29
|
||||
- jazz-tools@0.13.29
|
||||
|
||||
## 1.0.106
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.28
|
||||
- jazz-tools@0.13.28
|
||||
|
||||
## 1.0.105
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.27
|
||||
- jazz-tools@0.13.27
|
||||
|
||||
## 1.0.104
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ff846d9]
|
||||
- jazz-tools@0.13.26
|
||||
- jazz-expo@0.13.26
|
||||
|
||||
## 1.0.103
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.25
|
||||
- jazz-tools@0.13.25
|
||||
|
||||
## 1.0.102
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [02a240c]
|
||||
- jazz-tools@0.13.23
|
||||
- jazz-expo@0.13.23
|
||||
|
||||
## 1.0.101
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.22
|
||||
|
||||
## 1.0.100
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.21
|
||||
- jazz-tools@0.13.21
|
||||
|
||||
## 1.0.99
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [439f0fe]
|
||||
- jazz-tools@0.13.20
|
||||
- jazz-expo@0.13.20
|
||||
|
||||
## 1.0.98
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [80530a4]
|
||||
- jazz-tools@0.13.19
|
||||
- jazz-expo@0.13.19
|
||||
|
||||
## 1.0.97
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [761759c]
|
||||
- jazz-tools@0.13.18
|
||||
- jazz-expo@0.13.18
|
||||
|
||||
## 1.0.96
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.17
|
||||
- jazz-tools@0.13.17
|
||||
|
||||
## 1.0.95
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.16
|
||||
- jazz-tools@0.13.16
|
||||
|
||||
## 1.0.94
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.15
|
||||
- jazz-tools@0.13.15
|
||||
|
||||
## 1.0.93
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bd94012]
|
||||
- jazz-expo@0.13.14
|
||||
- jazz-tools@0.13.14
|
||||
|
||||
## 1.0.92
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.13
|
||||
- jazz-tools@0.13.13
|
||||
|
||||
## 1.0.91
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4547525]
|
||||
- jazz-tools@0.13.12
|
||||
- jazz-expo@0.13.12
|
||||
|
||||
## 1.0.90
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [17273a6]
|
||||
- jazz-tools@0.13.11
|
||||
- jazz-expo@0.13.11
|
||||
|
||||
## 1.0.89
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.10
|
||||
- jazz-tools@0.13.10
|
||||
|
||||
## 1.0.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a6cf01f]
|
||||
- jazz-tools@0.13.9
|
||||
- jazz-expo@0.13.9
|
||||
|
||||
## 1.0.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.8
|
||||
|
||||
## 1.0.86
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bc3d7bb]
|
||||
- jazz-tools@0.13.7
|
||||
- jazz-expo@0.13.7
|
||||
|
||||
## 1.0.85
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [fe6f561]
|
||||
- jazz-tools@0.13.5
|
||||
- jazz-expo@0.13.5
|
||||
|
||||
## 1.0.84
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3129982]
|
||||
- Updated dependencies [3129982]
|
||||
- jazz-expo@0.13.4
|
||||
- jazz-tools@0.13.4
|
||||
|
||||
## 1.0.83
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [12f8bfa]
|
||||
- Updated dependencies [bd57177]
|
||||
- jazz-tools@0.13.3
|
||||
- jazz-expo@0.13.3
|
||||
|
||||
## 1.0.82
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.13.2
|
||||
- jazz-tools@0.13.2
|
||||
|
||||
## 1.0.81
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [63a7aa0]
|
||||
- jazz-expo@0.13.1
|
||||
|
||||
## 1.0.80
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bce3bcc]
|
||||
- Updated dependencies [afd1374]
|
||||
- jazz-expo@0.13.0
|
||||
- jazz-tools@0.13.0
|
||||
|
||||
## 1.0.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 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
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.9.22
|
||||
|
||||
## 1.0.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1be017d]
|
||||
- jazz-tools@0.9.21
|
||||
- jazz-react-native@0.9.21
|
||||
|
||||
## 1.0.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b01cc1f]
|
||||
- jazz-tools@0.9.20
|
||||
- jazz-react-native@0.9.20
|
||||
|
||||
## 1.0.57
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.9.19
|
||||
- jazz-tools@0.9.19
|
||||
|
||||
## 1.0.56
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.9.18
|
||||
- jazz-tools@0.9.18
|
||||
|
||||
## 1.0.55
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c2ca1fe]
|
||||
- Updated dependencies [1227047]
|
||||
- jazz-tools@0.9.17
|
||||
- jazz-react-native@0.9.17
|
||||
|
||||
## 1.0.54
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [24b3b6a]
|
||||
- jazz-tools@0.9.16
|
||||
- jazz-react-native@0.9.16
|
||||
|
||||
## 1.0.53
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7491711]
|
||||
- jazz-tools@0.9.15
|
||||
- jazz-react-native@0.9.15
|
||||
|
||||
## 1.0.52
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3df93cc]
|
||||
- jazz-tools@0.9.14
|
||||
- jazz-react-native@0.9.14
|
||||
|
||||
## 1.0.51
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.9.13
|
||||
- jazz-tools@0.9.13
|
||||
|
||||
## 1.0.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.9.12
|
||||
- jazz-tools@0.9.12
|
||||
|
||||
## 1.0.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.9.11
|
||||
- jazz-tools@0.9.11
|
||||
|
||||
## 1.0.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [f76274c]
|
||||
- Updated dependencies [5e83864]
|
||||
- jazz-react-native@0.9.10
|
||||
- jazz-tools@0.9.10
|
||||
|
||||
## 1.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8eb9247]
|
||||
- jazz-tools@0.9.9
|
||||
- jazz-react-native@0.9.9
|
||||
|
||||
## 1.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1d773b]
|
||||
- jazz-tools@0.9.8
|
||||
- jazz-react-native@0.9.8
|
||||
|
||||
## 1.0.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8a390d2]
|
||||
- jazz-react-native@0.9.6
|
||||
|
||||
## 1.0.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c871912]
|
||||
- jazz-react-native@0.9.5
|
||||
|
||||
## 1.0.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.9.4
|
||||
|
||||
## 1.0.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7cd691f]
|
||||
- jazz-react-native@0.9.3
|
||||
|
||||
## 1.0.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [80fd3e9]
|
||||
- jazz-react-native@0.9.2
|
||||
|
||||
## 1.0.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1b71969]
|
||||
- jazz-tools@0.9.1
|
||||
- jazz-react-native@0.9.1
|
||||
|
||||
## 1.0.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1da4d55]
|
||||
- Updated dependencies [8eda792]
|
||||
- Updated dependencies [1e5e3a1]
|
||||
- jazz-react-native@0.9.0
|
||||
- jazz-tools@0.9.0
|
||||
|
||||
## 1.0.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [dc62b95]
|
||||
- Updated dependencies [1de26f8]
|
||||
- jazz-tools@0.8.51
|
||||
- jazz-react-native@0.8.51
|
||||
|
||||
## 1.0.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.50
|
||||
- jazz-tools@0.8.50
|
||||
|
||||
## 1.0.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.49
|
||||
- jazz-tools@0.8.49
|
||||
|
||||
## 1.0.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [635e824]
|
||||
- Updated dependencies [0a85982]
|
||||
- jazz-tools@0.8.48
|
||||
- jazz-react-native@0.8.48
|
||||
|
||||
## 1.0.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [33ef9c4]
|
||||
- jazz-react-native@0.8.47
|
||||
|
||||
## 1.0.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ab4ffbd]
|
||||
- jazz-react-native@0.8.46
|
||||
|
||||
## 1.0.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7701307]
|
||||
- Updated dependencies [fa41f8e]
|
||||
- Updated dependencies [88d7d9a]
|
||||
- Updated dependencies [60e35ea]
|
||||
- jazz-react-native@0.8.45
|
||||
- jazz-tools@0.8.45
|
||||
|
||||
## 1.0.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.44
|
||||
- jazz-tools@0.8.44
|
||||
|
||||
## 1.0.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.41
|
||||
- jazz-tools@0.8.41
|
||||
|
||||
## 1.0.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [0c6b0f3]
|
||||
- Updated dependencies [249eecb]
|
||||
- jazz-react-native@0.8.39
|
||||
- jazz-tools@0.8.39
|
||||
|
||||
## 1.0.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.38
|
||||
- jazz-tools@0.8.38
|
||||
|
||||
## 1.0.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.37
|
||||
- jazz-tools@0.8.37
|
||||
|
||||
## 1.0.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c84764a]
|
||||
- Updated dependencies [441fe27]
|
||||
- jazz-react-native@0.8.36
|
||||
- jazz-tools@0.8.36
|
||||
|
||||
## 1.0.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8b87117]
|
||||
- jazz-tools@0.8.35
|
||||
- jazz-react-native@0.8.35
|
||||
|
||||
## 1.0.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.34
|
||||
- jazz-tools@0.8.34
|
||||
|
||||
## 1.0.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [df42b2b]
|
||||
- jazz-tools@0.8.32
|
||||
- jazz-react-native@0.8.32
|
||||
|
||||
## 1.0.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.31
|
||||
- jazz-tools@0.8.31
|
||||
|
||||
## 1.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.30
|
||||
- jazz-tools@0.8.30
|
||||
|
||||
## 1.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.29
|
||||
- jazz-tools@0.8.29
|
||||
|
||||
## 1.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.28
|
||||
- jazz-tools@0.8.28
|
||||
|
||||
## 1.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.27
|
||||
- jazz-tools@0.8.27
|
||||
|
||||
## 1.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d348c2d]
|
||||
- Updated dependencies [6902b5b]
|
||||
- Updated dependencies [1a0cd3d]
|
||||
- jazz-tools@0.8.23
|
||||
- jazz-react-native@0.8.23
|
||||
|
||||
## 1.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [149ca97]
|
||||
- jazz-tools@0.8.21
|
||||
- jazz-react-native@0.8.21
|
||||
|
||||
## 1.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ef3ff3]
|
||||
- jazz-react-native@0.8.20
|
||||
|
||||
## 1.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.8.19
|
||||
- jazz-tools@0.8.19
|
||||
|
||||
## 1.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [048ac1d]
|
||||
- jazz-tools@0.14.22
|
||||
- jazz-expo@0.14.22
|
||||
- jazz-react-native@0.8.18
|
||||
- jazz-tools@0.8.18
|
||||
|
||||
## 1.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e7e505e]
|
||||
- Updated dependencies [cfb6786]
|
||||
- Updated dependencies [13b57aa]
|
||||
- Updated dependencies [5662faa]
|
||||
- Updated dependencies [2116a59]
|
||||
- jazz-tools@0.14.21
|
||||
- jazz-expo@0.14.21
|
||||
- jazz-react-native@0.8.17
|
||||
- jazz-tools@0.8.17
|
||||
|
||||
## 1.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6f72419]
|
||||
- Updated dependencies [04b20c2]
|
||||
- jazz-tools@0.14.20
|
||||
- jazz-expo@0.14.20
|
||||
- jazz-react-native@0.8.16
|
||||
- jazz-tools@0.8.16
|
||||
|
||||
## 1.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [061ec99]
|
||||
- jazz-expo@0.14.19
|
||||
- jazz-tools@0.14.19
|
||||
- Updated dependencies [cce679b]
|
||||
- jazz-tools@0.8.15
|
||||
- jazz-react-native@0.8.15
|
||||
|
||||
## 1.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4b950bc]
|
||||
- Updated dependencies [d6d9c0a]
|
||||
- Updated dependencies [c559054]
|
||||
- jazz-tools@0.14.18
|
||||
- jazz-expo@0.14.18
|
||||
- Updated dependencies [36273b3]
|
||||
- jazz-tools@0.8.14
|
||||
- jazz-react-native@0.8.14
|
||||
|
||||
## 1.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e512df4]
|
||||
- jazz-tools@0.14.17
|
||||
- jazz-expo@0.14.17
|
||||
- Updated dependencies [fd011d7]
|
||||
- jazz-tools@0.8.13
|
||||
- jazz-react-native@0.8.13
|
||||
|
||||
## 1.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.14.16
|
||||
- jazz-tools@0.14.16
|
||||
- jazz-react-native@0.8.12
|
||||
- jazz-tools@0.8.12
|
||||
|
||||
## 1.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.14.15
|
||||
- jazz-tools@0.14.15
|
||||
- jazz-react-native@0.8.11
|
||||
- jazz-tools@0.8.11
|
||||
|
||||
## 1.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e32a1f7]
|
||||
- jazz-tools@0.14.14
|
||||
- jazz-expo@0.14.14
|
||||
- b7639cf: feat(react-native): replaced react-native-mmkv with expo-secure-store and initialize it by default as kvStore in createJazzRNApp() (BREAKING)
|
||||
- Updated dependencies [b7639cf]
|
||||
- jazz-react-native@0.8.8
|
||||
|
||||
## 1.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.14.13
|
||||
- Updated dependencies [32b05b6]
|
||||
- jazz-react-native@0.8.7
|
||||
|
||||
## 1.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-expo@0.14.12
|
||||
- jazz-react-native@0.8.6
|
||||
|
||||
## 1.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [98d697f]
|
||||
- jazz-expo@0.14.11
|
||||
- Updated dependencies [c3f4e6b]
|
||||
- Updated dependencies [d9152ed]
|
||||
- jazz-react-native@0.8.5
|
||||
- jazz-tools@0.8.5
|
||||
|
||||
## 1.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [dc746a2]
|
||||
- Updated dependencies [f869d9a]
|
||||
- Updated dependencies [3fe6832]
|
||||
- jazz-tools@0.14.10
|
||||
- jazz-expo@0.14.10
|
||||
- Updated dependencies
|
||||
- jazz-react-native@0.8.3
|
||||
- jazz-tools@0.8.3
|
||||
|
||||
24
examples/chat-rn-expo/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# 🎷 Jazz + Expo + `react-navigation` + Demo Auth
|
||||
|
||||
## 🚀 How to Run
|
||||
|
||||
### 1. Inside the Workspace Root
|
||||
|
||||
First, install dependencies and build the project:
|
||||
|
||||
```bash
|
||||
pnpm i
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
### 2. Inside the `examples/chat-rn-expo` Directory
|
||||
|
||||
Next, navigate to the specific example project and run the following commands:
|
||||
|
||||
```bash
|
||||
pnpm expo prebuild
|
||||
pnpx pod-install
|
||||
pnpm expo run:ios
|
||||
```
|
||||
|
||||
This will set up and launch the app on iOS. For Android, you can replace the last command with `pnpm expo run:android`.
|
||||
55
examples/chat-rn-expo/app.config.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const { withBuildProperties } = require("expo-build-properties");
|
||||
const { withDangerousMod } = require("@expo/config-plugins");
|
||||
const fs = require("fs/promises");
|
||||
const path = require("path");
|
||||
|
||||
/**
|
||||
* https://github.com/mrousavy/nitro/issues/422#issuecomment-2545988256
|
||||
*/
|
||||
function withCustomIosMod(config) {
|
||||
// Use expo-build-properties to bump iOS deployment target
|
||||
config = withBuildProperties(config, { ios: { deploymentTarget: "16.0" } });
|
||||
// Patch the generated Podfile fallback to ensure platform is always 16.0
|
||||
config = withDangerousMod(config, [
|
||||
"ios",
|
||||
async (modConfig) => {
|
||||
const podfilePath = path.join(
|
||||
modConfig.modRequest.platformProjectRoot,
|
||||
"Podfile",
|
||||
);
|
||||
let contents = await fs.readFile(podfilePath, "utf-8");
|
||||
|
||||
// Check if the IPHONEOS_DEPLOYMENT_TARGET setting is already present
|
||||
// We search for the key being assigned, e.g., config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] =
|
||||
const deploymentTargetSettingExists =
|
||||
/\.build_settings\s*\[\s*['"]IPHONEOS_DEPLOYMENT_TARGET['"]\s*\]\s*=/.test(
|
||||
contents,
|
||||
);
|
||||
|
||||
if (!deploymentTargetSettingExists) {
|
||||
// IPHONEOS_DEPLOYMENT_TARGET setting not found, proceed to add it.
|
||||
contents = contents.replace(
|
||||
/(post_install\s+do\s+\|installer\|[\s\S]*?)(\r?\n\s end\s*)$/m,
|
||||
`$1
|
||||
|
||||
# Expo Build Properties: force deployment target
|
||||
# https://github.com/mrousavy/nitro/issues/422#issuecomment-2545988256
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
|
||||
end
|
||||
end
|
||||
$2`,
|
||||
);
|
||||
}
|
||||
|
||||
await fs.writeFile(podfilePath, contents);
|
||||
return modConfig;
|
||||
},
|
||||
]);
|
||||
return config;
|
||||
}
|
||||
|
||||
module.exports = ({ config }) => {
|
||||
return withCustomIosMod(config);
|
||||
};
|
||||
@@ -1,32 +1,39 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "chat-rn-expo",
|
||||
"slug": "chat-rn-expo",
|
||||
"name": "jazz-chat-rn-expo",
|
||||
"scheme": "jazz-chat-rn-expo",
|
||||
"slug": "jazz-chat-rn-expo",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"newArchEnabled": true,
|
||||
"splash": {
|
||||
"image": "./assets/splash-icon.png",
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "tools.jazz.chatrnexpo"
|
||||
"bundleIdentifier": "com.jazz.chatrn"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"edgeToEdgeEnabled": true,
|
||||
"package": "tools.jazz.chatrnexpo"
|
||||
"package": "com.jazz.chatrn"
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
"plugins": [
|
||||
"expo-secure-store",
|
||||
"expo-sqlite",
|
||||
"expo-build-properties",
|
||||
"expo-web-browser"
|
||||
],
|
||||
"extra": {
|
||||
"eas": {
|
||||
"projectId": "e0e61872-1906-4c84-b9d8-9be77355cad0"
|
||||
}
|
||||
},
|
||||
"plugins": ["expo-secure-store", "expo-sqlite"]
|
||||
"owner": "paxx"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
examples/chat-rn-expo/assets/splash.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
9
examples/chat-rn-expo/babel.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
module.exports = function (api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: [
|
||||
["babel-preset-expo", { jsxImportSource: "nativewind" }],
|
||||
"nativewind/babel",
|
||||
],
|
||||
};
|
||||
};
|
||||
27
examples/chat-rn-expo/eas.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"cli": {
|
||||
"version": ">= 12.5.1",
|
||||
"appVersionSource": "remote"
|
||||
},
|
||||
"build": {
|
||||
"development": {
|
||||
"developmentClient": true,
|
||||
"distribution": "internal"
|
||||
},
|
||||
"ios-simulator": {
|
||||
"extends": "development",
|
||||
"ios": {
|
||||
"simulator": true
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
"distribution": "internal"
|
||||
},
|
||||
"production": {
|
||||
"autoIncrement": true
|
||||
}
|
||||
},
|
||||
"submit": {
|
||||
"production": {}
|
||||
}
|
||||
}
|
||||
3
examples/chat-rn-expo/global.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
4
examples/chat-rn-expo/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import "./polyfills";
|
||||
import { registerRootComponent } from "expo";
|
||||
import App from "./src/App";
|
||||
registerRootComponent(App);
|
||||
@@ -1,9 +0,0 @@
|
||||
import { registerRootComponent } from "expo";
|
||||
import "./polyfills";
|
||||
|
||||
import App from "./src/App";
|
||||
|
||||
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
||||
// It also ensures that whether you load the app in Expo Go or in a native build,
|
||||
// the environment is set up appropriately
|
||||
registerRootComponent(App);
|
||||
35
examples/chat-rn-expo/metro.config.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// Learn more https://docs.expo.dev/guides/monorepos
|
||||
const { getDefaultConfig } = require("expo/metro-config");
|
||||
const { withNativeWind } = require("nativewind/metro");
|
||||
const { FileStore } = require("metro-cache");
|
||||
const path = require("path");
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const projectRoot = __dirname;
|
||||
const workspaceRoot = path.resolve(projectRoot, "../..");
|
||||
|
||||
const config = getDefaultConfig(projectRoot, { isCSSEnabled: true });
|
||||
|
||||
// Since we are using pnpm, we have to setup the monorepo manually for Metro
|
||||
// #1 - Watch all files in the monorepo
|
||||
config.watchFolders = [workspaceRoot];
|
||||
// #2 - Try resolving with project modules first, then workspace modules
|
||||
config.resolver.nodeModulesPaths = [
|
||||
path.resolve(projectRoot, "node_modules"),
|
||||
path.resolve(workspaceRoot, "node_modules"),
|
||||
];
|
||||
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
|
||||
config.resolver.requireCycleIgnorePatterns = [
|
||||
/(^|\/|\\)node_modules($|\/|\\)/,
|
||||
/(^|\/|\\)packages($|\/|\\)/,
|
||||
];
|
||||
|
||||
// Use turborepo to restore the cache when possible
|
||||
config.cacheStores = [
|
||||
new FileStore({
|
||||
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
|
||||
}),
|
||||
];
|
||||
|
||||
// module.exports = config;
|
||||
module.exports = withNativeWind(config, { input: "./global.css" });
|
||||
1
examples/chat-rn-expo/nativewind-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="nativewind/types" />
|
||||
@@ -1,32 +1,53 @@
|
||||
{
|
||||
"name": "chat-rn-expo",
|
||||
"main": "index.ts",
|
||||
"version": "1.0.113",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "expo prebuild",
|
||||
"build": "tsc --noEmit && expo export -p ios",
|
||||
"start": "expo start",
|
||||
"format-and-lint": "biome check .",
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo run:ios",
|
||||
"ios": "expo prebuild && pnpx pod-install && expo run:ios",
|
||||
"web": "expo start --web"
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@bacons/text-decoder": "^0.0.0",
|
||||
"@bam.tech/react-native-image-resizer": "^3.0.11",
|
||||
"@bacons/text-decoder": "0.0.0",
|
||||
"@craftzdog/react-native-buffer": "6.0.5",
|
||||
"@react-native-community/netinfo": "11.4.1",
|
||||
"expo": "54.0.0-canary-20250701-6a945c5",
|
||||
"expo-clipboard": "^7.1.4",
|
||||
"@react-navigation/native": "7.0.19",
|
||||
"@react-navigation/native-stack": "7.2.1",
|
||||
"clsx": "^2.0.0",
|
||||
"expo": "53.0.8",
|
||||
"expo-build-properties": "~0.14.6",
|
||||
"expo-clipboard": "~7.1.4",
|
||||
"expo-constants": "~17.1.6",
|
||||
"expo-dev-client": "~5.1.8",
|
||||
"expo-linking": "~7.1.4",
|
||||
"expo-secure-store": "~14.2.3",
|
||||
"expo-sqlite": "~15.2.10",
|
||||
"expo-sqlite": "15.2.9",
|
||||
"expo-status-bar": "~2.2.3",
|
||||
"expo-web-browser": "~14.1.6",
|
||||
"jazz-expo": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "19.1.0",
|
||||
"react-native": "0.80.0",
|
||||
"nativewind": "^4.1.21",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-native": "0.79.2",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"readable-stream": "^4.7.0"
|
||||
"react-native-safe-area-context": "5.4.0",
|
||||
"react-native-screens": "4.10.0",
|
||||
"react-native-nitro-modules": "0.25.2",
|
||||
"react-native-quick-crypto": "1.0.0-beta.15",
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"readable-stream": "4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@types/react": "~19.0.10",
|
||||
"typescript": "~5.8.3"
|
||||
"@types/react": "~19.0.14",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "5.8.3"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
// @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);
|
||||
@@ -1,18 +1,74 @@
|
||||
import { JazzExpoProvider } from "jazz-tools/expo";
|
||||
import React, { StrictMode } from "react";
|
||||
import "../global.css";
|
||||
|
||||
import {
|
||||
NavigationContainer,
|
||||
useNavigationContainerRef,
|
||||
} from "@react-navigation/native";
|
||||
import { createNativeStackNavigator } from "@react-navigation/native-stack";
|
||||
import * as Linking from "expo-linking";
|
||||
import { RNQuickCrypto } from "jazz-expo/crypto";
|
||||
import React, { StrictMode, useEffect, useState } from "react";
|
||||
import HandleInviteScreen from "./invite";
|
||||
|
||||
import { JazzProvider } from "jazz-expo";
|
||||
import { apiKey } from "./apiKey";
|
||||
import ChatScreen from "./chat";
|
||||
|
||||
export default function App() {
|
||||
const Stack = createNativeStackNavigator();
|
||||
|
||||
const prefix = Linking.createURL("/");
|
||||
|
||||
const linking = {
|
||||
prefixes: [prefix],
|
||||
config: {
|
||||
screens: {
|
||||
HandleInviteScreen: {
|
||||
path: "router/invite/:valueHint?/:valueID/:inviteSecret",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function App() {
|
||||
const [initialRoute, setInitialRoute] = useState<
|
||||
"ChatScreen" | "HandleInviteScreen"
|
||||
>("ChatScreen");
|
||||
const navigationRef = useNavigationContainerRef();
|
||||
useEffect(() => {
|
||||
Linking.getInitialURL().then((url) => {
|
||||
if (url) {
|
||||
if (url && url.includes("invite")) {
|
||||
setInitialRoute("HandleInviteScreen");
|
||||
}
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<StrictMode>
|
||||
<JazzExpoProvider
|
||||
<JazzProvider
|
||||
CryptoProvider={RNQuickCrypto}
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
>
|
||||
<ChatScreen />
|
||||
</JazzExpoProvider>
|
||||
<NavigationContainer linking={linking} ref={navigationRef}>
|
||||
<Stack.Navigator initialRouteName={initialRoute}>
|
||||
<Stack.Screen
|
||||
options={{ title: "Jazz Chat" }}
|
||||
name="ChatScreen"
|
||||
// @ts-ignore
|
||||
component={ChatScreen}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="HandleInviteScreen"
|
||||
component={HandleInviteScreen}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
</JazzProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import clsx from "clsx";
|
||||
import * as Clipboard from "expo-clipboard";
|
||||
import { Account, Group } from "jazz-tools";
|
||||
import { useState } from "react";
|
||||
import { Group, ID, Loaded, Profile } from "jazz-tools";
|
||||
import { useEffect, useState } from "react";
|
||||
import React, {
|
||||
Button,
|
||||
FlatList,
|
||||
@@ -11,38 +12,54 @@ import React, {
|
||||
TouchableOpacity,
|
||||
View,
|
||||
Alert,
|
||||
StyleSheet,
|
||||
} from "react-native";
|
||||
|
||||
import { useAccount, useCoState } from "jazz-tools/expo";
|
||||
import { useAccount, useCoState } from "jazz-expo";
|
||||
import { Chat, Message } from "./schema";
|
||||
|
||||
export default function ChatScreen() {
|
||||
const { me, logOut } = useAccount(Account, { resolve: { profile: true } });
|
||||
export default function ChatScreen({ navigation }: { navigation: any }) {
|
||||
const { me, logOut } = useAccount();
|
||||
const [chatId, setChatId] = useState<string>();
|
||||
const [chatIdInput, setChatIdInput] = useState<string>();
|
||||
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
|
||||
const [message, setMessage] = useState("");
|
||||
const profile = useCoState(Profile, me._refs.profile?.id, {});
|
||||
|
||||
function handleLogOut() {
|
||||
setChatId(undefined);
|
||||
logOut();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () => <Button onPress={handleLogOut} title="Logout" />,
|
||||
headerLeft: () =>
|
||||
loadedChat ? (
|
||||
<Button
|
||||
onPress={() => {
|
||||
if (loadedChat?.id) {
|
||||
Clipboard.setStringAsync(
|
||||
`https://chat.jazz.tools/#/chat/${loadedChat.id}`,
|
||||
);
|
||||
Alert.alert("Copied to clipboard", `Chat ID: ${loadedChat.id}`);
|
||||
}
|
||||
}}
|
||||
title="Share"
|
||||
/>
|
||||
) : null,
|
||||
});
|
||||
}, [navigation, loadedChat]);
|
||||
|
||||
const createChat = () => {
|
||||
const group = Group.create();
|
||||
const group = Group.create({ owner: me });
|
||||
group.addMember("everyone", "writer");
|
||||
const chat = Chat.create([], group);
|
||||
const chat = Chat.create([], { owner: group });
|
||||
setChatId(chat.id);
|
||||
};
|
||||
|
||||
const joinChat = () => {
|
||||
if (chatIdInput) {
|
||||
if (chatIdInput.startsWith("https://chat.jazz.tools/#/chat/")) {
|
||||
setChatId(chatIdInput.split("/").pop());
|
||||
} else {
|
||||
setChatId(chatIdInput);
|
||||
}
|
||||
setChatId(chatIdInput);
|
||||
} else {
|
||||
Alert.alert("Error", "Chat ID cannot be empty.");
|
||||
}
|
||||
@@ -58,28 +75,41 @@ export default function ChatScreen() {
|
||||
}
|
||||
};
|
||||
|
||||
const renderMessageItem = ({ item }: { item: Message }) => {
|
||||
const renderMessageItem = ({ item }: { item: Loaded<typeof Message> }) => {
|
||||
const isMe = item._edits?.text?.by?.isMe;
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.messageContainer,
|
||||
isMe ? styles.myMessage : styles.otherMessage,
|
||||
]}
|
||||
className={clsx(
|
||||
`rounded-lg p-1 px-1.5 max-w-[80%] `,
|
||||
|
||||
isMe ? `bg-gray-200 self-end text-right` : `bg-gray-300 self-start `,
|
||||
)}
|
||||
>
|
||||
{!isMe ? (
|
||||
<Text
|
||||
style={[
|
||||
styles.messageSender,
|
||||
{ textAlign: isMe ? "right" : "left" },
|
||||
]}
|
||||
className={clsx(
|
||||
`text-xs text-gray-500`,
|
||||
isMe ? "text-right" : "text-left",
|
||||
)}
|
||||
>
|
||||
{item?._edits?.text?.by?.profile?.name}
|
||||
</Text>
|
||||
) : null}
|
||||
<View style={styles.messageContent}>
|
||||
<Text style={styles.messageText}>{item.text}</Text>
|
||||
<Text style={[styles.messageTime, { marginTop: !isMe ? 8 : 4 }]}>
|
||||
<View
|
||||
className={clsx(
|
||||
"flex relative items-end justify-between",
|
||||
isMe ? "flex-row" : "flex-row",
|
||||
)}
|
||||
>
|
||||
<Text className={clsx(`text-black text-md max-w-[85%]`)}>
|
||||
{item.text}
|
||||
</Text>
|
||||
<Text
|
||||
className={clsx(
|
||||
"text-[10px] text-gray-500 text-right ml-2",
|
||||
!isMe ? "mt-2" : "mt-1",
|
||||
)}
|
||||
>
|
||||
{item?._edits?.text?.madeAt?.getHours().toString().padStart(2, "0")}
|
||||
:
|
||||
{item?._edits?.text?.madeAt
|
||||
@@ -93,28 +123,31 @@ export default function ChatScreen() {
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View className="flex flex-col h-full">
|
||||
{!loadedChat ? (
|
||||
<View style={styles.welcomeContainer}>
|
||||
<Text style={styles.usernameTitle}>Username</Text>
|
||||
<View className="flex flex-col h-full items-center justify-center">
|
||||
<Text className="text-m font-bold mb-6">Username</Text>
|
||||
<TextInput
|
||||
style={styles.usernameInput}
|
||||
value={me?.profile.name ?? ""}
|
||||
className="rounded h-12 p-2 mb-12 w-40 border border-gray-200 block"
|
||||
value={profile?.name ?? ""}
|
||||
onChangeText={(value) => {
|
||||
if (me?.profile) {
|
||||
me.profile.name = value;
|
||||
if (profile) {
|
||||
profile.name = value;
|
||||
}
|
||||
}}
|
||||
textAlignVertical="center"
|
||||
onSubmitEditing={sendMessage}
|
||||
testID="username-input"
|
||||
/>
|
||||
<TouchableOpacity onPress={createChat} style={styles.newChatButton}>
|
||||
<Text style={styles.newChatButtonText}>Start new chat</Text>
|
||||
<TouchableOpacity
|
||||
onPress={createChat}
|
||||
className="bg-blue-500 p-4 rounded-md"
|
||||
>
|
||||
<Text className="text-white font-semibold">Start new chat</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.joinChatTitle}>Join existing chat</Text>
|
||||
<Text className="text-m font-bold mt-6">Join existing chat</Text>
|
||||
<TextInput
|
||||
style={styles.chatIdInput}
|
||||
className="rounded h-12 p-2 m-2 mt-4 w-80 border border-gray-200 block"
|
||||
placeholder="Chat ID"
|
||||
value={chatIdInput ?? ""}
|
||||
onChangeText={(value) => {
|
||||
@@ -129,41 +162,21 @@ export default function ChatScreen() {
|
||||
testID="chat-id-input"
|
||||
/>
|
||||
<TouchableOpacity
|
||||
testID="join-chat-button"
|
||||
onPress={joinChat}
|
||||
style={styles.joinChatButton}
|
||||
className="bg-green-500 p-4 rounded-md"
|
||||
>
|
||||
<Text style={styles.newChatButtonText}>Join chat</Text>
|
||||
<Text className="text-white font-semibold">Join chat</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
<View style={styles.chatHeader}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
if (loadedChat?.id) {
|
||||
Clipboard.setStringAsync(
|
||||
`https://chat.jazz.tools/#/chat/${loadedChat.id}`,
|
||||
);
|
||||
Alert.alert(
|
||||
"Copied to clipboard",
|
||||
`Chat ID: ${loadedChat.id}`,
|
||||
);
|
||||
}
|
||||
}}
|
||||
title="Share"
|
||||
/>
|
||||
<Text style={{ fontWeight: "bold", fontSize: 18 }}>Jazz chat</Text>
|
||||
<Button onPress={handleLogOut} title="Logout" />
|
||||
</View>
|
||||
<FlatList
|
||||
contentContainerStyle={{
|
||||
flexGrow: 1,
|
||||
gap: 6,
|
||||
padding: 8,
|
||||
justifyContent: "flex-end",
|
||||
}}
|
||||
style={styles.messageList}
|
||||
className="flex"
|
||||
data={loadedChat}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={renderMessageItem}
|
||||
@@ -172,11 +185,11 @@ export default function ChatScreen() {
|
||||
<KeyboardAvoidingView
|
||||
keyboardVerticalOffset={110}
|
||||
behavior="padding"
|
||||
style={styles.inputContainer}
|
||||
className="p-3 bg-white border-t border-gray-300"
|
||||
>
|
||||
<SafeAreaView style={styles.inputRow}>
|
||||
<SafeAreaView className="flex flex-row items-center gap-2">
|
||||
<TextInput
|
||||
style={styles.messageInput}
|
||||
className="rounded-full h-8 py-0 px-2 border border-gray-200 block flex-1"
|
||||
value={message}
|
||||
onChangeText={setMessage}
|
||||
placeholder="Type a message..."
|
||||
@@ -186,7 +199,7 @@ export default function ChatScreen() {
|
||||
/>
|
||||
<TouchableOpacity
|
||||
onPress={sendMessage}
|
||||
style={styles.sendButton}
|
||||
className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center"
|
||||
testID="send-button"
|
||||
>
|
||||
<Text>↑</Text>
|
||||
@@ -198,133 +211,3 @@ export default function ChatScreen() {
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
},
|
||||
chatHeader: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
padding: 8,
|
||||
paddingTop: 48,
|
||||
backgroundColor: "#f0f0f0",
|
||||
},
|
||||
welcomeContainer: {
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
usernameTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: "bold",
|
||||
marginBottom: 24,
|
||||
},
|
||||
usernameInput: {
|
||||
borderRadius: 4,
|
||||
height: 48,
|
||||
padding: 8,
|
||||
marginBottom: 48,
|
||||
width: 160,
|
||||
borderWidth: 1,
|
||||
borderColor: "#e5e5e5",
|
||||
},
|
||||
newChatButton: {
|
||||
backgroundColor: "#3b82f6",
|
||||
padding: 16,
|
||||
borderRadius: 6,
|
||||
},
|
||||
newChatButtonText: {
|
||||
color: "white",
|
||||
fontWeight: "600",
|
||||
},
|
||||
joinChatTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: "bold",
|
||||
marginTop: 24,
|
||||
},
|
||||
chatIdInput: {
|
||||
borderRadius: 4,
|
||||
height: 48,
|
||||
padding: 8,
|
||||
margin: 8,
|
||||
marginTop: 16,
|
||||
width: 320,
|
||||
borderWidth: 1,
|
||||
borderColor: "#e5e5e5",
|
||||
},
|
||||
joinChatButton: {
|
||||
backgroundColor: "#22c55e",
|
||||
padding: 16,
|
||||
borderRadius: 6,
|
||||
},
|
||||
messageList: {
|
||||
display: "flex",
|
||||
},
|
||||
messageContainer: {
|
||||
borderRadius: 8,
|
||||
padding: 4,
|
||||
paddingHorizontal: 6,
|
||||
maxWidth: "80%",
|
||||
},
|
||||
myMessage: {
|
||||
backgroundColor: "#e5e5e5",
|
||||
alignSelf: "flex-end",
|
||||
},
|
||||
otherMessage: {
|
||||
backgroundColor: "#d4d4d4",
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
messageSender: {
|
||||
fontSize: 12,
|
||||
color: "#6b7280",
|
||||
},
|
||||
messageContent: {
|
||||
flexDirection: "row",
|
||||
alignItems: "flex-end",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
messageText: {
|
||||
color: "black",
|
||||
fontSize: 16,
|
||||
maxWidth: "85%",
|
||||
},
|
||||
messageTime: {
|
||||
fontSize: 10,
|
||||
color: "#6b7280",
|
||||
marginLeft: 8,
|
||||
},
|
||||
inputContainer: {
|
||||
padding: 12,
|
||||
backgroundColor: "white",
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: "#d4d4d4",
|
||||
},
|
||||
inputRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
},
|
||||
messageInput: {
|
||||
borderRadius: 9999,
|
||||
height: 32,
|
||||
paddingVertical: 0,
|
||||
paddingHorizontal: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: "#e5e5e5",
|
||||
flex: 1,
|
||||
},
|
||||
sendButton: {
|
||||
backgroundColor: "#d4d4d4",
|
||||
borderRadius: 9999,
|
||||
height: 32,
|
||||
width: 32,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
});
|
||||
|
||||
18
examples/chat-rn-expo/src/invite.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useAcceptInvite } from "jazz-expo";
|
||||
import React, { Text } from "react-native";
|
||||
import { Chat } from "./schema";
|
||||
|
||||
export default function HandleInviteScreen({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: any;
|
||||
}) {
|
||||
useAcceptInvite({
|
||||
invitedObjectSchema: Chat,
|
||||
onAccept: async (chatId) => {
|
||||
navigation.navigate("ChatScreen", { chatId });
|
||||
},
|
||||
});
|
||||
|
||||
return <Text>Accepting invite...</Text>;
|
||||
}
|
||||
@@ -3,7 +3,5 @@ import { co, z } from "jazz-tools";
|
||||
export const Message = co.map({
|
||||
text: z.string(),
|
||||
});
|
||||
export type Message = co.loaded<typeof Message>;
|
||||
|
||||
export const Chat = co.list(Message);
|
||||
export type Chat = co.loaded<typeof Chat>;
|
||||
|
||||
14
examples/chat-rn-expo/tailwind.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
// NOTE: Update this to include the paths to all of your component files.
|
||||
content: [
|
||||
"./app/**/*.{js,jsx,ts,tsx}",
|
||||
"./components/**/*.{js,jsx,ts,tsx}",
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
],
|
||||
presets: [require("nativewind/preset")],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
# 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: tools.jazz.chatrnexpo
|
||||
appId: com.jazz.chatrn
|
||||
---
|
||||
- copyTextFrom:
|
||||
id: ${id}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
appId: tools.jazz.chatrnexpo
|
||||
appId: com.jazz.chatrn
|
||||
---
|
||||
- launchApp
|
||||
|
||||
@@ -8,7 +8,10 @@ appId: tools.jazz.chatrnexpo
|
||||
# - assertVisible: "Reload"
|
||||
# - tapOn: "Reload"
|
||||
|
||||
- assertVisible: "Username"
|
||||
# login
|
||||
- assertVisible: "Logout"
|
||||
- tapOn: "Logout"
|
||||
- assertVisible: "Anonymous user"
|
||||
- runFlow:
|
||||
label: "Erase existing username"
|
||||
file: erase_text.yml
|
||||
@@ -40,18 +43,12 @@ appId: tools.jazz.chatrnexpo
|
||||
|
||||
# logout
|
||||
- tapOn: "Logout"
|
||||
- assertVisible: "Username"
|
||||
- assertVisible: "Anonymous user"
|
||||
|
||||
- extendedWaitUntil:
|
||||
visible: "Anonymous user"
|
||||
timeout: 10000
|
||||
# join chat
|
||||
|
||||
## Commented because it fails on CI
|
||||
# - tapOn:
|
||||
# id: "chat-id-input"
|
||||
# - inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
|
||||
# - tapOn:
|
||||
# id: "join-chat-button"
|
||||
# - assertVisible: "boorad"
|
||||
# - assertVisible: "bro, low key, it do be like that tho"
|
||||
# join chat
|
||||
- tapOn:
|
||||
id: "chat-id-input"
|
||||
- inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
|
||||
- tapOn: "Join chat"
|
||||
- assertVisible: "boorad"
|
||||
- assertVisible: "bro, low key, it do be like that tho"
|
||||
|
||||
@@ -5,15 +5,11 @@
|
||||
|
||||
set -e
|
||||
|
||||
OUTPUT_FILE=~/output/android-install.log
|
||||
mkdir -p ~/output
|
||||
touch $OUTPUT_FILE
|
||||
|
||||
# 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_FILE 2>&1
|
||||
./gradlew installRelease >> ~/output/android-install.log 2>&1
|
||||
cd ..
|
||||
|
||||
# run the e2e tests
|
||||
|
||||
@@ -1,13 +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
|
||||
|
||||
# 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
|
||||
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"strict": true
|
||||
}
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
"exclude": ["src/tests"]
|
||||
}
|
||||
|
||||
6
examples/chat-rn/.gitignore
vendored
@@ -73,9 +73,3 @@ yarn-error.log
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
# env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
@@ -1,179 +1,5 @@
|
||||
# chat-rn
|
||||
|
||||
## 1.0.140
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [57fb69f]
|
||||
- Updated dependencies [048ac1d]
|
||||
- cojson@0.14.22
|
||||
- jazz-tools@0.14.22
|
||||
- cojson-transport-ws@0.14.22
|
||||
- jazz-react-native@0.14.22
|
||||
|
||||
## 1.0.139
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e7e505e]
|
||||
- Updated dependencies [c3d8779]
|
||||
- Updated dependencies [13b57aa]
|
||||
- Updated dependencies [5662faa]
|
||||
- Updated dependencies [2116a59]
|
||||
- jazz-tools@0.14.21
|
||||
- cojson@0.14.21
|
||||
- jazz-react-native@0.14.21
|
||||
- cojson-transport-ws@0.14.21
|
||||
|
||||
## 1.0.138
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6f72419]
|
||||
- Updated dependencies [04b20c2]
|
||||
- jazz-tools@0.14.20
|
||||
- jazz-react-native@0.14.20
|
||||
- cojson@0.14.20
|
||||
- cojson-transport-ws@0.14.20
|
||||
|
||||
## 1.0.137
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [061ec99]
|
||||
- jazz-react-native@0.14.19
|
||||
- cojson@0.14.19
|
||||
- cojson-transport-ws@0.14.19
|
||||
- jazz-tools@0.14.19
|
||||
|
||||
## 1.0.136
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4b950bc]
|
||||
- Updated dependencies [0d5ee3e]
|
||||
- Updated dependencies [d6d9c0a]
|
||||
- Updated dependencies [c559054]
|
||||
- jazz-tools@0.14.18
|
||||
- cojson@0.14.18
|
||||
- jazz-react-native@0.14.18
|
||||
- cojson-transport-ws@0.14.18
|
||||
|
||||
## 1.0.135
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e512df4]
|
||||
- jazz-tools@0.14.17
|
||||
- jazz-react-native@0.14.17
|
||||
|
||||
## 1.0.134
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5e253cc]
|
||||
- cojson@0.14.16
|
||||
- cojson-transport-ws@0.14.16
|
||||
- jazz-react-native@0.14.16
|
||||
- jazz-tools@0.14.16
|
||||
|
||||
## 1.0.133
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [23daa7c]
|
||||
- cojson@0.14.15
|
||||
- jazz-react-native@0.14.15
|
||||
- cojson-transport-ws@0.14.15
|
||||
- jazz-tools@0.14.15
|
||||
|
||||
## 1.0.132
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e32a1f7]
|
||||
- jazz-tools@0.14.14
|
||||
- jazz-react-native@0.14.14
|
||||
|
||||
## 1.0.131
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.14.13
|
||||
|
||||
## 1.0.130
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.14.12
|
||||
|
||||
## 1.0.129
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [98d697f]
|
||||
- jazz-react-native@0.14.11
|
||||
|
||||
## 1.0.128
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [dc746a2]
|
||||
- Updated dependencies [f869d9a]
|
||||
- Updated dependencies [3fe6832]
|
||||
- jazz-react-native@0.14.10
|
||||
- jazz-tools@0.14.10
|
||||
|
||||
## 1.0.127
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [22c2600]
|
||||
- jazz-tools@0.14.9
|
||||
- jazz-react-native@0.14.9
|
||||
|
||||
## 1.0.126
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [637ae13]
|
||||
- jazz-tools@0.14.8
|
||||
- jazz-react-native@0.14.8
|
||||
|
||||
## 1.0.125
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [365b0ea]
|
||||
- jazz-tools@0.14.7
|
||||
- jazz-react-native@0.14.7
|
||||
|
||||
## 1.0.124
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9d6d9fe]
|
||||
- Updated dependencies [9d6d9fe]
|
||||
- jazz-tools@0.14.6
|
||||
- jazz-react-native@0.14.6
|
||||
|
||||
## 1.0.123
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [91cbb2f]
|
||||
- Updated dependencies [20b3d88]
|
||||
- jazz-tools@0.14.5
|
||||
- jazz-react-native@0.14.5
|
||||
|
||||
## 1.0.122
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [011af55]
|
||||
- jazz-tools@0.14.4
|
||||
- jazz-react-native@0.14.4
|
||||
|
||||
## 1.0.121
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -26,7 +26,7 @@ This will set up and launch the app on iOS. For Android, you can skip `pnpm pods
|
||||
This was created using the following command:
|
||||
|
||||
```bash
|
||||
pnpx @react-native-community/cli init chat-rn --version 0.76.9 --install-pods true --skip-git-init true --package-name com.chatrn --directory chat-rn
|
||||
pnpx @react-native-community/cli init chat-rn --version 0.76.7 --install-pods true --skip-git-init true --package-name com.chatrn --directory chat-rn
|
||||
```
|
||||
|
||||
Then change package name in `package.json`, and begin build instructions above.
|
||||
|
||||
@@ -11,11 +11,11 @@ react {
|
||||
// The root of your project, i.e. where "package.json" lives. Default is '../..'
|
||||
// root = file("../../")
|
||||
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
|
||||
reactNativeDir = file("../../../../node_modules/react-native")
|
||||
// reactNativeDir = file("../../node_modules/react-native")
|
||||
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
|
||||
codegenDir = file("../../../../node_modules/@react-native/codegen")
|
||||
// codegenDir = file("../../node_modules/@react-native/codegen")
|
||||
// The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
|
||||
cliFile = file("../../../../node_modules/react-native/cli.js")
|
||||
// cliFile = file("../../node_modules/react-native/cli.js")
|
||||
|
||||
/* Variants */
|
||||
// The list of variants to that are debuggable. For those we're going to
|
||||
@@ -63,14 +63,14 @@ def enableProguardInReleaseBuilds = false
|
||||
* The preferred build flavor of JavaScriptCore (JSC)
|
||||
*
|
||||
* For example, to use the international variant, you can use:
|
||||
* `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+`
|
||||
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
||||
*
|
||||
* The international variant includes ICU i18n library and necessary data
|
||||
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
|
||||
* give correct results when using with locales other than en-US. Note that
|
||||
* this variant is about 6MiB larger per architecture than default.
|
||||
*/
|
||||
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
||||
def jscFlavor = 'org.webkit:android-jsc:+'
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
|
||||
@@ -4,11 +4,13 @@ import android.app.Application
|
||||
import com.facebook.react.PackageList
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.facebook.react.ReactHost
|
||||
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
|
||||
import com.facebook.react.ReactNativeHost
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
|
||||
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
|
||||
import com.facebook.react.defaults.DefaultReactNativeHost
|
||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
|
||||
import com.facebook.soloader.SoLoader
|
||||
|
||||
class MainApplication : Application(), ReactApplication {
|
||||
|
||||
@@ -33,6 +35,10 @@ class MainApplication : Application(), ReactApplication {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
loadReactNative(this)
|
||||
SoLoader.init(this, OpenSourceMergedSoMapping)
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
||||
load()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ buildscript {
|
||||
buildToolsVersion = "35.0.0"
|
||||
minSdkVersion = 24
|
||||
compileSdkVersion = 35
|
||||
targetSdkVersion = 35
|
||||
ndkVersion = "27.1.12297006"
|
||||
kotlinVersion = "2.1.20"
|
||||
targetSdkVersion = 34
|
||||
ndkVersion = "26.1.10909125"
|
||||
kotlinVersion = "1.9.25"
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
9
examples/chat-rn/android/gradlew
vendored
@@ -86,7 +86,8 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -114,7 +115,7 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH="\\\"\\\""
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -205,7 +206,7 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
@@ -213,7 +214,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||