Compare commits
142 Commits
cojson-sto
...
jazz-brows
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
597545741b | ||
|
|
5e42e2a8d8 | ||
|
|
19e2a61398 | ||
|
|
5b06a9d0a7 | ||
|
|
41c4fbb8f9 | ||
|
|
95febc7777 | ||
|
|
7ddff0a550 | ||
|
|
cebc58cd3a | ||
|
|
044626fbc8 | ||
|
|
28fdc43c89 | ||
|
|
2602a49f12 | ||
|
|
8505b0a0b6 | ||
|
|
f2418ff364 | ||
|
|
c81a49ebc3 | ||
|
|
3cd07dca31 | ||
|
|
3763a99e14 | ||
|
|
201e2fd015 | ||
|
|
3e743d56d3 | ||
|
|
b3ff726794 | ||
|
|
f98f88d89b | ||
|
|
56974412df | ||
|
|
adaedd2da2 | ||
|
|
a11472a497 | ||
|
|
3f269c7483 | ||
|
|
81b6b8fd04 | ||
|
|
2939790335 | ||
|
|
48c29435bc | ||
|
|
8668906376 | ||
|
|
6d84e9e83f | ||
|
|
1fea0ef69c | ||
|
|
e4314accb6 | ||
|
|
ee3a4048ef | ||
|
|
9ee1edef3b | ||
|
|
8ab5a09a86 | ||
|
|
2624442903 | ||
|
|
2d199089d5 | ||
|
|
683c170b9d | ||
|
|
ce0e9f0102 | ||
|
|
518406e23d | ||
|
|
4dcbafa058 | ||
|
|
7ae9e01848 | ||
|
|
dd9ecf660d | ||
|
|
4f849050dc | ||
|
|
681600220f | ||
|
|
384e239ad5 | ||
|
|
54e1a09a46 | ||
|
|
392a9c5aac | ||
|
|
478334eabf | ||
|
|
479f9b0113 | ||
|
|
812622b161 | ||
|
|
8b35fae4b6 | ||
|
|
9e2ecb0378 | ||
|
|
fe908b5300 | ||
|
|
1f99807971 | ||
|
|
47f54c4d81 | ||
|
|
814f65acaf | ||
|
|
78fd4c86a1 | ||
|
|
678f326bc1 | ||
|
|
ea33ad4864 | ||
|
|
57b6d5efb4 | ||
|
|
15929b121d | ||
|
|
6edd061202 | ||
|
|
eb4cef196c | ||
|
|
85703f9241 | ||
|
|
865d5385e9 | ||
|
|
5bb12523ee | ||
|
|
190cb1efb2 | ||
|
|
46ab1f6db2 | ||
|
|
a44fc6fc6d | ||
|
|
2376a8d3b2 | ||
|
|
2c3ec2fea6 | ||
|
|
da6f6ec4d5 | ||
|
|
8c78b37bfb | ||
|
|
5f382309de | ||
|
|
aa7eb3cf2c | ||
|
|
9b41762e96 | ||
|
|
28be460286 | ||
|
|
df8af06814 | ||
|
|
2ef460fccf | ||
|
|
9660e2c03c | ||
|
|
908645e4b7 | ||
|
|
f3ca37ed5e | ||
|
|
a9d0fd14c4 | ||
|
|
c496f49bb0 | ||
|
|
b26666ab4c | ||
|
|
9088a349a0 | ||
|
|
54b12dcb7a | ||
|
|
a998f94789 | ||
|
|
d17eecfe16 | ||
|
|
71b9a5ce25 | ||
|
|
8ebfbc86db | ||
|
|
abad8e762f | ||
|
|
037e16392e | ||
|
|
49ac65c123 | ||
|
|
3510fb1273 | ||
|
|
bc3efe7ca0 | ||
|
|
3b06a7809e | ||
|
|
58aa04bb10 | ||
|
|
afb94ef043 | ||
|
|
7554dd9f88 | ||
|
|
7a3cfabb4c | ||
|
|
df7101a8ee | ||
|
|
f74b46ee2f | ||
|
|
9177579f53 | ||
|
|
f1c00903f9 | ||
|
|
1ca9299590 | ||
|
|
4f0fb6c27f | ||
|
|
34082ccaf5 | ||
|
|
a09c417d81 | ||
|
|
034bd20b39 | ||
|
|
00a188c22f | ||
|
|
dc630b0807 | ||
|
|
484baabe22 | ||
|
|
f529bede7b | ||
|
|
87f82ac7cd | ||
|
|
6f637d21ab | ||
|
|
aeb96510da | ||
|
|
d53cc3676d | ||
|
|
81dedb6395 | ||
|
|
17cb04bfb1 | ||
|
|
a98b4e5d81 | ||
|
|
7eb7e2f656 | ||
|
|
80703ea1cc | ||
|
|
d46e0b9d0c | ||
|
|
430a9e252a | ||
|
|
6f519462df | ||
|
|
a0ae2811ce | ||
|
|
73e5a3548a | ||
|
|
c5da3a42a1 | ||
|
|
8ef14d4850 | ||
|
|
1a7b7942ad | ||
|
|
5f42c97184 | ||
|
|
2a2b474aa4 | ||
|
|
e8c1a3535a | ||
|
|
b05878962b | ||
|
|
54b4595f23 | ||
|
|
99a2d9be00 | ||
|
|
bf1fbdc8c4 | ||
|
|
14b3aa29c7 | ||
|
|
bfaadb9d67 | ||
|
|
cb770e565d | ||
|
|
a50a9e6c9b |
2
.github/workflows/build-starters.yaml
vendored
@@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
starter: ["react-passkey-auth"]
|
starter: ["react-passkey-auth", "svelte-passkey-auth"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
3
.github/workflows/playwright-homepage.yml
vendored
@@ -22,6 +22,9 @@ jobs:
|
|||||||
- name: Setup Source Code
|
- name: Setup Source Code
|
||||||
uses: ./.github/actions/source-code/
|
uses: ./.github/actions/source-code/
|
||||||
|
|
||||||
|
- name: Install root dependencies
|
||||||
|
run: pnpm install && pnpm turbo build
|
||||||
|
|
||||||
- name: Install project dependencies
|
- name: Install project dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
working-directory: ./${{ matrix.project }}
|
working-directory: ./${{ matrix.project }}
|
||||||
|
|||||||
22
.github/workflows/playwright.yml
vendored
@@ -13,7 +13,21 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
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"]
|
project: [
|
||||||
|
"tests/e2e",
|
||||||
|
"examples/chat",
|
||||||
|
"examples/clerk",
|
||||||
|
"examples/betterauth",
|
||||||
|
"examples/file-share-svelte",
|
||||||
|
"examples/form",
|
||||||
|
"examples/inspector",
|
||||||
|
"examples/music-player",
|
||||||
|
"examples/organization",
|
||||||
|
"examples/pets",
|
||||||
|
"starters/react-passkey-auth",
|
||||||
|
"starters/svelte-passkey-auth",
|
||||||
|
"packages/jazz-svelte"
|
||||||
|
]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -24,7 +38,11 @@ jobs:
|
|||||||
uses: ./.github/actions/source-code/
|
uses: ./.github/actions/source-code/
|
||||||
|
|
||||||
- name: Pnpm Build
|
- name: Pnpm Build
|
||||||
run: pnpm turbo build
|
run: |
|
||||||
|
if [ -f .env.test ]; then
|
||||||
|
cp .env.test .env
|
||||||
|
fi
|
||||||
|
pnpm turbo build
|
||||||
working-directory: ./${{ matrix.project }}
|
working-directory: ./${{ matrix.project }}
|
||||||
|
|
||||||
- name: Install Playwright Browsers
|
- name: Install Playwright Browsers
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"**/android/**",
|
"**/android/**",
|
||||||
"packages/jazz-svelte/**",
|
"packages/jazz-svelte/**",
|
||||||
"examples/*svelte*/**",
|
"examples/*svelte*/**",
|
||||||
|
"starters/*svelte*/**",
|
||||||
"examples/jazz-paper-scissors/src/routeTree.gen.ts",
|
"examples/jazz-paper-scissors/src/routeTree.gen.ts",
|
||||||
"homepage/homepage/**",
|
"homepage/homepage/**",
|
||||||
"**/package.json"
|
"**/package.json"
|
||||||
|
|||||||
6
examples/betterauth/.gitignore
vendored
@@ -36,8 +36,10 @@ yarn-error.log*
|
|||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
# env files (can opt-in for committing if needed)
|
# env files (can opt-in for committing if needed)
|
||||||
.env*
|
.env
|
||||||
!.env
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ This example demonstrates how to integrate [Better Auth](https://www.better-auth
|
|||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
To run this example, you may either:
|
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
|
### 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.
|
- `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)
|
- `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)
|
- `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)
|
||||||
@@ -17,38 +19,64 @@ To run this example, you may either:
|
|||||||
### Using this example as a template
|
### Using this example as a template
|
||||||
|
|
||||||
1. Create a new Jazz project, and use this example as a template.
|
1. Create a new Jazz project, and use this example as a template.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npx create-jazz-app@latest betterauth-app --example betterauth
|
npx create-jazz-app@latest betterauth-app --example betterauth
|
||||||
```
|
```
|
||||||
2. Navigate to the new project and start the development server.
|
|
||||||
|
2. Navigate to the new project and install dependencies.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd betterauth-app
|
cd betterauth-app
|
||||||
pnpm install
|
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
|
pnpm dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
https://www.better-auth.com/docs/installation#set-environment-variables
|
||||||
|
|
||||||
### Using the monorepo
|
### Using the monorepo
|
||||||
|
|
||||||
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
|
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
|
||||||
|
|
||||||
Clone the jazz repository.
|
Clone the jazz repository.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/garden-co/jazz.git
|
git clone https://github.com/garden-co/jazz.git
|
||||||
```
|
```
|
||||||
|
|
||||||
Install and build dependencies.
|
Install and build dependencies.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm i && npx turbo build
|
pnpm i && npx turbo build
|
||||||
```
|
```
|
||||||
|
|
||||||
Go to the example directory.
|
Go to the example directory.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd jazz/examples/betterauth/
|
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.
|
Start the dev server.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm dev
|
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,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "betterauth",
|
"name": "betterauth",
|
||||||
"version": "0.1.25",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_ZXZpZGVudC1kYW5lLTg5LmNsZXJrLmFjY291bnRzLmRldiQ
|
|
||||||
1
examples/chat-rn-expo-clerk/.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=
|
||||||
6
examples/chat-rn-expo-clerk/.gitignore
vendored
@@ -15,3 +15,9 @@ web-build/
|
|||||||
|
|
||||||
ios
|
ios
|
||||||
android
|
android
|
||||||
|
|
||||||
|
# Env
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -8,9 +8,12 @@ First, install dependencies and build the project:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm i
|
pnpm i
|
||||||
|
mv .env.example .env
|
||||||
pnpm run build
|
pnpm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Don't forget to update `VITE_CLERK_PUBLISHABLE_KEY` in `.env` with your [Publishable Key](https://clerk.com/docs/deployments/clerk-environment-variables#clerk-publishable-and-secret-keys) from Clerk.
|
||||||
|
|
||||||
### 2. Inside the `examples/chat-rn-expo-clerk` Directory
|
### 2. Inside the `examples/chat-rn-expo-clerk` Directory
|
||||||
|
|
||||||
Next, navigate to the specific example project and run the following commands:
|
Next, navigate to the specific example project and run the following commands:
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "chat-rn-expo-clerk",
|
"name": "chat-rn-expo-clerk",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"version": "1.0.145",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "expo export -p ios",
|
"build": "expo export -p ios",
|
||||||
"start": "expo start",
|
"start": "expo start",
|
||||||
|
|||||||
7
examples/chat-rn-expo/.gitignore
vendored
@@ -36,4 +36,9 @@ yarn-error.*
|
|||||||
# typescript
|
# typescript
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
android/
|
android/
|
||||||
ios/
|
ios/
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "chat-rn-expo",
|
"name": "chat-rn-expo",
|
||||||
"version": "1.0.13",
|
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "expo prebuild",
|
"build": "expo prebuild",
|
||||||
|
|||||||
@@ -128,7 +128,11 @@ export default function ChatScreen() {
|
|||||||
}}
|
}}
|
||||||
testID="chat-id-input"
|
testID="chat-id-input"
|
||||||
/>
|
/>
|
||||||
<TouchableOpacity onPress={joinChat} style={styles.joinChatButton}>
|
<TouchableOpacity
|
||||||
|
testID="join-chat-button"
|
||||||
|
onPress={joinChat}
|
||||||
|
style={styles.joinChatButton}
|
||||||
|
>
|
||||||
<Text style={styles.newChatButtonText}>Join chat</Text>
|
<Text style={styles.newChatButtonText}>Join chat</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -41,12 +41,17 @@ appId: tools.jazz.chatrnexpo
|
|||||||
# logout
|
# logout
|
||||||
- tapOn: "Logout"
|
- tapOn: "Logout"
|
||||||
- assertVisible: "Username"
|
- assertVisible: "Username"
|
||||||
- assertVisible: "Anonymous user"
|
|
||||||
|
|
||||||
# join chat
|
- extendedWaitUntil:
|
||||||
|
visible: "Anonymous user"
|
||||||
|
timeout: 10000
|
||||||
|
# join chat
|
||||||
|
|
||||||
|
## Commented because it fails on CI
|
||||||
# - tapOn:
|
# - tapOn:
|
||||||
# id: "chat-id-input"
|
# id: "chat-id-input"
|
||||||
# - inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
|
# - inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
|
||||||
# - tapOn: "Join chat"
|
# - tapOn:
|
||||||
|
# id: "join-chat-button"
|
||||||
# - assertVisible: "boorad"
|
# - assertVisible: "boorad"
|
||||||
# - assertVisible: "bro, low key, it do be like that tho"
|
# - assertVisible: "bro, low key, it do be like that tho"
|
||||||
|
|||||||
13
examples/chat-rn-expo/test/e2e/runLocal.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/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
|
||||||
6
examples/chat-rn/.gitignore
vendored
@@ -73,3 +73,9 @@ yarn-error.log
|
|||||||
!.yarn/releases
|
!.yarn/releases
|
||||||
!.yarn/sdks
|
!.yarn/sdks
|
||||||
!.yarn/versions
|
!.yarn/versions
|
||||||
|
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "chat-rn",
|
"name": "chat-rn",
|
||||||
"version": "1.0.140",
|
"private": true,
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
|
|||||||
21
examples/chat-svelte/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
node_modules
|
||||||
|
|
||||||
|
# Output
|
||||||
|
.output
|
||||||
|
.vercel
|
||||||
|
/.svelte-kit
|
||||||
|
/build
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Env
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|
||||||
|
# Vite
|
||||||
|
vite.config.js.timestamp-*
|
||||||
|
vite.config.ts.timestamp-*
|
||||||
1
examples/chat-svelte/.npmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
engine-strict=true
|
||||||
4
examples/chat-svelte/.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Package Managers
|
||||||
|
package-lock.json
|
||||||
|
pnpm-lock.yaml
|
||||||
|
yarn.lock
|
||||||
16
examples/chat-svelte/.prettierrc
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"useTabs": false,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"printWidth": 100,
|
||||||
|
"plugins": ["prettier-plugin-svelte"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.svelte",
|
||||||
|
"options": {
|
||||||
|
"parser": "svelte"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
545
examples/chat-svelte/CHANGELOG.md
Normal file
@@ -0,0 +1,545 @@
|
|||||||
|
# passkey-svelte
|
||||||
|
|
||||||
|
## 0.0.85
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [99a2d9b]
|
||||||
|
- jazz-tools@0.14.25
|
||||||
|
- jazz-browser-media-images@0.14.25
|
||||||
|
- jazz-svelte@0.14.25
|
||||||
|
|
||||||
|
## 0.0.84
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.30
|
||||||
|
- jazz-tools@0.13.30
|
||||||
|
|
||||||
|
## 0.0.83
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.29
|
||||||
|
- jazz-tools@0.13.29
|
||||||
|
|
||||||
|
## 0.0.82
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.28
|
||||||
|
- jazz-tools@0.13.28
|
||||||
|
|
||||||
|
## 0.0.81
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.27
|
||||||
|
- jazz-tools@0.13.27
|
||||||
|
|
||||||
|
## 0.0.80
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [ff846d9]
|
||||||
|
- jazz-tools@0.13.26
|
||||||
|
- jazz-svelte@0.13.26
|
||||||
|
|
||||||
|
## 0.0.79
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.25
|
||||||
|
- jazz-tools@0.13.25
|
||||||
|
|
||||||
|
## 0.0.78
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [ec546b4]
|
||||||
|
- jazz-svelte@0.13.24
|
||||||
|
|
||||||
|
## 0.0.77
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [3431076]
|
||||||
|
- Updated dependencies [02a240c]
|
||||||
|
- jazz-svelte@0.13.23
|
||||||
|
- jazz-tools@0.13.23
|
||||||
|
|
||||||
|
## 0.0.76
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.21
|
||||||
|
- jazz-tools@0.13.21
|
||||||
|
|
||||||
|
## 0.0.75
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [439f0fe]
|
||||||
|
- jazz-tools@0.13.20
|
||||||
|
- jazz-svelte@0.13.20
|
||||||
|
|
||||||
|
## 0.0.74
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [80530a4]
|
||||||
|
- jazz-tools@0.13.19
|
||||||
|
- jazz-svelte@0.13.19
|
||||||
|
|
||||||
|
## 0.0.73
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [761759c]
|
||||||
|
- jazz-tools@0.13.18
|
||||||
|
- jazz-svelte@0.13.18
|
||||||
|
|
||||||
|
## 0.0.72
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.17
|
||||||
|
- jazz-tools@0.13.17
|
||||||
|
|
||||||
|
## 0.0.71
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.16
|
||||||
|
- jazz-tools@0.13.16
|
||||||
|
|
||||||
|
## 0.0.70
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.15
|
||||||
|
- jazz-tools@0.13.15
|
||||||
|
|
||||||
|
## 0.0.69
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.14
|
||||||
|
- jazz-tools@0.13.14
|
||||||
|
|
||||||
|
## 0.0.68
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.13
|
||||||
|
- jazz-tools@0.13.13
|
||||||
|
|
||||||
|
## 0.0.67
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [4547525]
|
||||||
|
- jazz-tools@0.13.12
|
||||||
|
- jazz-svelte@0.13.12
|
||||||
|
|
||||||
|
## 0.0.66
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [17273a6]
|
||||||
|
- jazz-tools@0.13.11
|
||||||
|
- jazz-svelte@0.13.11
|
||||||
|
|
||||||
|
## 0.0.65
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.10
|
||||||
|
- jazz-tools@0.13.10
|
||||||
|
|
||||||
|
## 0.0.64
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [a6cf01f]
|
||||||
|
- jazz-tools@0.13.9
|
||||||
|
- jazz-svelte@0.13.9
|
||||||
|
|
||||||
|
## 0.0.63
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.7
|
||||||
|
|
||||||
|
## 0.0.62
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.5
|
||||||
|
|
||||||
|
## 0.0.61
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.4
|
||||||
|
|
||||||
|
## 0.0.60
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.3
|
||||||
|
|
||||||
|
## 0.0.59
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.2
|
||||||
|
|
||||||
|
## 0.0.58
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.13.0
|
||||||
|
|
||||||
|
## 0.0.57
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.12.2
|
||||||
|
|
||||||
|
## 0.0.56
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.12.1
|
||||||
|
|
||||||
|
## 0.0.55
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.12.0
|
||||||
|
|
||||||
|
## 0.0.54
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.11.8
|
||||||
|
|
||||||
|
## 0.0.53
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.11.7
|
||||||
|
|
||||||
|
## 0.0.52
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 1bfa9bb: Removed when="singedUp" from examples apps' Jazz providers. This is a really niche use-case option and can lead to broken-feeling experiences when anonymous users try to load something.
|
||||||
|
- jazz-svelte@0.11.6
|
||||||
|
|
||||||
|
## 0.0.51
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.11.5
|
||||||
|
|
||||||
|
## 0.0.50
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.11.4
|
||||||
|
|
||||||
|
## 0.0.49
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.11.3
|
||||||
|
|
||||||
|
## 0.0.48
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.11.2
|
||||||
|
|
||||||
|
## 0.0.47
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.11.0
|
||||||
|
|
||||||
|
## 0.0.46
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.15
|
||||||
|
|
||||||
|
## 0.0.45
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.14
|
||||||
|
|
||||||
|
## 0.0.44
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.13
|
||||||
|
|
||||||
|
## 0.0.43
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [4612e05]
|
||||||
|
- jazz-svelte@0.10.12
|
||||||
|
|
||||||
|
## 0.0.42
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.9
|
||||||
|
|
||||||
|
## 0.0.41
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.8
|
||||||
|
|
||||||
|
## 0.0.40
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [1136d9b]
|
||||||
|
- jazz-svelte@0.10.7
|
||||||
|
|
||||||
|
## 0.0.39
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.6
|
||||||
|
|
||||||
|
## 0.0.38
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.5
|
||||||
|
|
||||||
|
## 0.0.37
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.4
|
||||||
|
|
||||||
|
## 0.0.36
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.3
|
||||||
|
|
||||||
|
## 0.0.35
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.2
|
||||||
|
|
||||||
|
## 0.0.34
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.10.1
|
||||||
|
|
||||||
|
## 0.0.33
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [b426342]
|
||||||
|
- jazz-svelte@0.10.0
|
||||||
|
|
||||||
|
## 0.0.32
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.23
|
||||||
|
|
||||||
|
## 0.0.31
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.22
|
||||||
|
|
||||||
|
## 0.0.30
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.21
|
||||||
|
|
||||||
|
## 0.0.29
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.20
|
||||||
|
|
||||||
|
## 0.0.28
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.19
|
||||||
|
|
||||||
|
## 0.0.27
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.18
|
||||||
|
|
||||||
|
## 0.0.26
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.17
|
||||||
|
|
||||||
|
## 0.0.25
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.16
|
||||||
|
|
||||||
|
## 0.0.24
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.15
|
||||||
|
|
||||||
|
## 0.0.23
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.14
|
||||||
|
|
||||||
|
## 0.0.22
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.13
|
||||||
|
|
||||||
|
## 0.0.21
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.12
|
||||||
|
|
||||||
|
## 0.0.20
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.11
|
||||||
|
|
||||||
|
## 0.0.19
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.10
|
||||||
|
|
||||||
|
## 0.0.18
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.9
|
||||||
|
|
||||||
|
## 0.0.17
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.8
|
||||||
|
|
||||||
|
## 0.0.16
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.9.1
|
||||||
|
|
||||||
|
## 0.0.15
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [9dd8d95]
|
||||||
|
- jazz-svelte@0.9.0
|
||||||
|
|
||||||
|
## 0.0.14
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.51
|
||||||
|
|
||||||
|
## 0.0.13
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.50
|
||||||
|
|
||||||
|
## 0.0.12
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.49
|
||||||
|
|
||||||
|
## 0.0.11
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.48
|
||||||
|
|
||||||
|
## 0.0.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.45
|
||||||
|
|
||||||
|
## 0.0.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.44
|
||||||
|
|
||||||
|
## 0.0.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.41
|
||||||
|
|
||||||
|
## 0.0.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.40
|
||||||
|
|
||||||
|
## 0.0.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [aa21072]
|
||||||
|
- jazz-svelte@0.8.39
|
||||||
|
|
||||||
|
## 0.0.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.8.38
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.0.4
|
||||||
|
|
||||||
|
## 0.0.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- jazz-svelte@0.0.3
|
||||||
|
|
||||||
|
## 0.0.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [0e59e65]
|
||||||
|
- jazz-svelte@0.0.2
|
||||||
68
examples/chat-svelte/README.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Chat example with Jazz and Svelte
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
You can either
|
||||||
|
|
||||||
|
1. Clone the jazz repository, and run the app within the monorepo.
|
||||||
|
2. Or create a new Jazz project using this example as a template.
|
||||||
|
|
||||||
|
### Using the example as a template
|
||||||
|
|
||||||
|
Create a new Jazz project, and use this example as a template.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx create-jazz-app@latest chat-app --example chat-svelte
|
||||||
|
```
|
||||||
|
|
||||||
|
Go to the new project directory.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd chat-app
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the dev server.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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/chat-svelte/
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the dev server.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.
|
||||||
|
|
||||||
|
## Questions / problems / feedback
|
||||||
|
|
||||||
|
If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
|
||||||
|
|
||||||
|
## Configuration: sync server
|
||||||
|
|
||||||
|
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||||
|
|
||||||
|
You can also run a local sync server by running `npx jazz-run sync`, and setting the `sync` parameter of `JazzProvider` in [./src/routes/+layout.svelte](./src/routes/+layout.svelte) to `{ peer: "ws://localhost:4200" }`.
|
||||||
33
examples/chat-svelte/eslint.config.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import prettier from 'eslint-config-prettier';
|
||||||
|
import js from '@eslint/js';
|
||||||
|
import svelte from 'eslint-plugin-svelte';
|
||||||
|
import globals from 'globals';
|
||||||
|
import ts from 'typescript-eslint';
|
||||||
|
|
||||||
|
export default ts.config(
|
||||||
|
js.configs.recommended,
|
||||||
|
...ts.configs.recommended,
|
||||||
|
...svelte.configs['flat/recommended'],
|
||||||
|
prettier,
|
||||||
|
...svelte.configs['flat/prettier'],
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
...globals.node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.svelte'],
|
||||||
|
|
||||||
|
languageOptions: {
|
||||||
|
parserOptions: {
|
||||||
|
parser: ts.parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ignores: ['build/', '.svelte-kit/', 'dist/']
|
||||||
|
}
|
||||||
|
);
|
||||||
44
examples/chat-svelte/package.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "chat-svelte",
|
||||||
|
"version": "0.0.85",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite dev",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
|
"format": "prettier --write .",
|
||||||
|
"lint": "prettier --check . && eslint .",
|
||||||
|
"format-and-lint": "pnpm run format && pnpm run lint",
|
||||||
|
"format-and-lint:fix": "pnpm run format --write && pnpm run lint --fix",
|
||||||
|
"test:e2e": "playwright test",
|
||||||
|
"test:e2e:ui": "playwright test --ui"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@sveltejs/adapter-auto": "^3.3.1",
|
||||||
|
"@sveltejs/kit": "^2.21.1",
|
||||||
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
|
"@types/eslint": "^9.6.1",
|
||||||
|
"eslint": "^9.27.0",
|
||||||
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-plugin-svelte": "^2.46.1",
|
||||||
|
"globals": "^15.15.0",
|
||||||
|
"jazz-inspector-element": "workspace:*",
|
||||||
|
"prettier": "^3.5.3",
|
||||||
|
"prettier-plugin-svelte": "^3.4.0",
|
||||||
|
"svelte": "^5.31.1",
|
||||||
|
"svelte-check": "^4.2.1",
|
||||||
|
"typescript": "5.6.2",
|
||||||
|
"typescript-eslint": "^8.32.1",
|
||||||
|
"vite": "6.0.11"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tailwindcss/vite": "^4.1.7",
|
||||||
|
"jazz-browser-media-images": "workspace:*",
|
||||||
|
"jazz-svelte": "workspace:*",
|
||||||
|
"jazz-tools": "workspace:*",
|
||||||
|
"tailwindcss": "^4.1.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
54
examples/chat-svelte/playwright.config.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
import isCI from 'is-ci';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read environment variables from file.
|
||||||
|
* https://github.com/motdotla/dotenv
|
||||||
|
*/
|
||||||
|
// import dotenv from 'dotenv';
|
||||||
|
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests',
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: isCI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: isCI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: isCI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: 'html',
|
||||||
|
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
baseURL: 'http://localhost:5173/',
|
||||||
|
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
permissions: ['clipboard-read', 'clipboard-write']
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: [
|
||||||
|
{
|
||||||
|
command: 'pnpm preview --port 5173',
|
||||||
|
url: 'http://localhost:5173/',
|
||||||
|
reuseExistingServer: !isCI
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
1
examples/chat-svelte/src/apiKey.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const apiKey = 'svelte-chat-example@garden.co';
|
||||||
21
examples/chat-svelte/src/app.css
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
@import 'tailwindcss';
|
||||||
|
@theme {
|
||||||
|
--color-stone-50: oklch(0.988281 0.002 75);
|
||||||
|
--color-stone-75: oklch(0.980563 0.002 75);
|
||||||
|
--color-stone-100: oklch(0.964844 0.002 75);
|
||||||
|
--color-stone-200: oklch(0.917969 0.002 75);
|
||||||
|
--color-stone-300: oklch(0.853516 0.002 75);
|
||||||
|
--color-stone-400: oklch(0.789063 0.002 75);
|
||||||
|
--color-stone-500: oklch(0.726563 0.002 75);
|
||||||
|
--color-stone-600: oklch(0.613281 0.002 75);
|
||||||
|
--color-stone-700: oklch(0.523438 0.002 75);
|
||||||
|
--color-stone-800: oklch(0.412109 0.002 75);
|
||||||
|
--color-stone-900: oklch(0.302734 0.002 75);
|
||||||
|
--color-stone-925: oklch(0.22 0.002 75);
|
||||||
|
--color-stone-950: oklch(0.193359 0.002 75);
|
||||||
|
--color-blue: oklch(0.57 0.2346 261.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
@apply outline-hidden;
|
||||||
|
}
|
||||||
13
examples/chat-svelte/src/app.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||||
|
// for information about these interfaces
|
||||||
|
declare global {
|
||||||
|
namespace App {
|
||||||
|
// interface Error {}
|
||||||
|
// interface Locals {}
|
||||||
|
// interface PageData {}
|
||||||
|
// interface PageState {}
|
||||||
|
// interface Platform {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
12
examples/chat-svelte/src/app.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="%sveltekit.assets%/jazz-icon.png" type="image/png" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
%sveltekit.head%
|
||||||
|
</head>
|
||||||
|
<body data-sveltekit-preload-data="hover">
|
||||||
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { children } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex flex-col justify-between w-screen h-screen bg-stone-50 dark:bg-stone-925 dark:text-white"
|
||||||
|
>
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
13
examples/chat-svelte/src/lib/components/BubbleBody.svelte
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
|
||||||
|
let { children, fromMe }: { children: Snippet; fromMe: boolean | undefined } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="line-clamp-10 text-ellipsis rounded-2xl overflow-hidden max-w-[calc(100%-5rem)] shadow-sm p-1 {fromMe
|
||||||
|
? 'bg-white dark:bg-stone-900 dark:text-white'
|
||||||
|
: 'bg-blue text-white'}"
|
||||||
|
>
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
let { children, fromMe }: { children: Snippet; fromMe: boolean | undefined } = $props();
|
||||||
|
const align = fromMe ? 'items-end' : 'items-start';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="{align} flex flex-col m-3" role="row">
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
12
examples/chat-svelte/src/lib/components/BubbleImage.svelte
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { ImageDefinition, type Loaded } from 'jazz-tools';
|
||||||
|
import { useProgressiveImg } from '$lib/utils/useProgressiveImage.svelte';
|
||||||
|
let { image }: { image: Loaded<typeof ImageDefinition> } = $props();
|
||||||
|
const { src } = $derived(
|
||||||
|
useProgressiveImg({
|
||||||
|
image
|
||||||
|
})
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<img class="h-auto max-h-[20rem] max-w-full rounded-t-xl mb-1" {src} alt="" />
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { by, madeAt }: { by: string | undefined; madeAt: Date } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="text-xs text-neutral-500 mt-1.5">
|
||||||
|
{by} · {madeAt.toLocaleTimeString()}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { CoPlainText } from 'jazz-tools';
|
||||||
|
|
||||||
|
let { text, className }: { text: CoPlainText | string | null; className?: string } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="whitespace-pre-wrap"><p class="px-2 leading-relaxed {className}">{text}</p></div>
|
||||||
7
examples/chat-svelte/src/lib/components/ChatBody.svelte
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { children } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex flex-col-reverse flex-1 overflow-y-auto" role="application">
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
36
examples/chat-svelte/src/lib/components/ChatBubble.svelte
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import BubbleBody from '$lib/components/BubbleBody.svelte';
|
||||||
|
import BubbleContainer from '$lib/components/BubbleContainer.svelte';
|
||||||
|
import BubbleImage from '$lib/components/BubbleImage.svelte';
|
||||||
|
import BubbleInfo from '$lib/components/BubbleInfo.svelte';
|
||||||
|
import BubbleText from '$lib/components/BubbleText.svelte';
|
||||||
|
import type { Message } from '$lib/schema';
|
||||||
|
import type { Account, Loaded } from 'jazz-tools';
|
||||||
|
let {
|
||||||
|
me,
|
||||||
|
msg
|
||||||
|
}: {
|
||||||
|
me: Loaded<typeof Account> | null | undefined;
|
||||||
|
msg: Loaded<typeof Message>;
|
||||||
|
} = $props();
|
||||||
|
const lastEdit = $derived(msg._edits.text);
|
||||||
|
const fromMe = $derived(lastEdit?.by?.isMe);
|
||||||
|
const { text, image } = $derived(msg);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if me && (!me.canRead(msg) || !msg.text?.toString())}
|
||||||
|
<BubbleContainer fromMe={false}>
|
||||||
|
<BubbleBody fromMe={false}>
|
||||||
|
<BubbleText text="Message not readable" className="italic text-gray-500"></BubbleText>
|
||||||
|
</BubbleBody>
|
||||||
|
</BubbleContainer>
|
||||||
|
{:else}
|
||||||
|
<BubbleContainer {fromMe}>
|
||||||
|
<BubbleBody {fromMe}>
|
||||||
|
{#if image}
|
||||||
|
<BubbleImage {image} />{/if}
|
||||||
|
<BubbleText {text} />
|
||||||
|
</BubbleBody>
|
||||||
|
<BubbleInfo by={lastEdit?.by?.profile?.name} madeAt={lastEdit?.madeAt || new Date()} />
|
||||||
|
</BubbleContainer>
|
||||||
|
{/if}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<div class="flex items-center justify-center h-full px-3 text-base text-stone-500 md:text-2xl">
|
||||||
|
Start a conversation below.
|
||||||
|
</div>
|
||||||
19
examples/chat-svelte/src/lib/components/ImageIcon.svelte
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { size = 24, strokeWidth = 2 } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width={strokeWidth}
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="lucide lucide-image-icon lucide-image"
|
||||||
|
><rect width="18" height="18" x="3" y="3" rx="2" ry="2" /><circle cx="9" cy="9" r="2" /><path
|
||||||
|
d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
32
examples/chat-svelte/src/lib/components/ImageInput.svelte
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { ChangeEventHandler } from 'svelte/elements';
|
||||||
|
|
||||||
|
import ImageIcon from '$lib/components/ImageIcon.svelte';
|
||||||
|
let { onImageChange }: { onImageChange?: ChangeEventHandler<HTMLInputElement> } = $props();
|
||||||
|
|
||||||
|
let input = $state<HTMLInputElement>();
|
||||||
|
|
||||||
|
const onUploadClick = () => {
|
||||||
|
input?.click();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label="Send image"
|
||||||
|
title="Send image"
|
||||||
|
onclick={onUploadClick}
|
||||||
|
class="text-stone-500 p-1.5 rounded-full hover:bg-stone-100 hover:text-stone-800 dark:hover:bg-stone-800 dark:hover:text-stone-200 transition-colors"
|
||||||
|
>
|
||||||
|
<ImageIcon size={24} strokeWidth={1.5} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<label class="sr-only">
|
||||||
|
Image
|
||||||
|
<input
|
||||||
|
bind:this={input}
|
||||||
|
type="file"
|
||||||
|
accept="image/png, image/jpeg, image/gif"
|
||||||
|
onchange={onImageChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
9
examples/chat-svelte/src/lib/components/InputBar.svelte
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { children } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex gap-1 p-3 mt-auto bg-white border-t shadow-2xl border-stone-200 dark:bg-transparent dark:border-stone-900"
|
||||||
|
>
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
20
examples/chat-svelte/src/lib/components/TextInput.svelte
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { onSubmit }: { onSubmit: (text: string) => void } = $props();
|
||||||
|
const inputId = $props.id();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex-1">
|
||||||
|
<label class="sr-only" for={inputId}> Type a message and press Enter </label>
|
||||||
|
<input
|
||||||
|
id={inputId}
|
||||||
|
class="block w-full px-3 py-1 border rounded-full border-stone-200 placeholder:text-stone-500 dark:bg-stone-925 dark:text-white dark:border-stone-900"
|
||||||
|
placeholder="Type a message and press Enter"
|
||||||
|
maxLength={2048}
|
||||||
|
type="text"
|
||||||
|
onkeydown={({ key, currentTarget: input }) => {
|
||||||
|
if (key !== 'Enter' || !input.value) return;
|
||||||
|
onSubmit(input.value);
|
||||||
|
input.value = '';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
9
examples/chat-svelte/src/lib/components/TopBar.svelte
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { children } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex justify-between w-full gap-2 p-3 bg-white border-b border-stone-200 dark:bg-transparent dark:border-stone-900"
|
||||||
|
>
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
8
examples/chat-svelte/src/lib/schema.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { co, z } from 'jazz-tools';
|
||||||
|
|
||||||
|
export const Message = co.map({
|
||||||
|
text: co.plainText(),
|
||||||
|
image: z.optional(co.image())
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Chat = co.list(Message);
|
||||||
16
examples/chat-svelte/src/lib/utils.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
const animals = [
|
||||||
|
'elephant',
|
||||||
|
'penguin',
|
||||||
|
'giraffe',
|
||||||
|
'octopus',
|
||||||
|
'kangaroo',
|
||||||
|
'dolphin',
|
||||||
|
'cheetah',
|
||||||
|
'koala',
|
||||||
|
'platypus',
|
||||||
|
'pangolin'
|
||||||
|
];
|
||||||
|
|
||||||
|
export function getRandomUsername() {
|
||||||
|
return `Anonymous ${animals[Math.floor(Math.random() * animals.length)]}`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { ImageDefinition, type Loaded } from 'jazz-tools';
|
||||||
|
import { onDestroy } from 'svelte';
|
||||||
|
|
||||||
|
export function useProgressiveImg({
|
||||||
|
image,
|
||||||
|
maxWidth,
|
||||||
|
targetWidth
|
||||||
|
}: {
|
||||||
|
image: Loaded<typeof ImageDefinition> | null | undefined;
|
||||||
|
maxWidth?: number;
|
||||||
|
targetWidth?: number;
|
||||||
|
}) {
|
||||||
|
let current = $state<{
|
||||||
|
src?: string;
|
||||||
|
res?: `${number}x${number}` | 'placeholder';
|
||||||
|
}>();
|
||||||
|
const originalSize = $state(image?.originalSize);
|
||||||
|
|
||||||
|
const unsubscribe = image?.subscribe({}, (update: Loaded<typeof ImageDefinition>) => {
|
||||||
|
const highestRes = ImageDefinition.highestResAvailable(update, { maxWidth, targetWidth });
|
||||||
|
if (highestRes) {
|
||||||
|
if (highestRes.res !== current?.res) {
|
||||||
|
const blob = highestRes.stream.toBlob();
|
||||||
|
if (blob) {
|
||||||
|
const blobURI = URL.createObjectURL(blob);
|
||||||
|
current = { src: blobURI, res: highestRes.res };
|
||||||
|
|
||||||
|
setTimeout(() => URL.revokeObjectURL(blobURI), 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current = {
|
||||||
|
src: update?.placeholderDataURL,
|
||||||
|
res: 'placeholder'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => () => {
|
||||||
|
unsubscribe?.();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
get src() {
|
||||||
|
return current?.src;
|
||||||
|
},
|
||||||
|
get res() {
|
||||||
|
return current?.res;
|
||||||
|
},
|
||||||
|
|
||||||
|
originalSize
|
||||||
|
};
|
||||||
|
}
|
||||||
32
examples/chat-svelte/src/routes/+layout.svelte
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import '../app.css';
|
||||||
|
import { JazzProvider } from 'jazz-svelte';
|
||||||
|
import 'jazz-inspector-element';
|
||||||
|
import { page } from '$app/state';
|
||||||
|
import { apiKey } from '../apiKey';
|
||||||
|
import { getRandomUsername } from '$lib/utils';
|
||||||
|
let { children } = $props();
|
||||||
|
const defaultProfileName = getRandomUsername();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Jazz Chat Example</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="h-full bg-white text-stone-700 dark:text-stone-400 dark:bg-stone-925">
|
||||||
|
<JazzProvider
|
||||||
|
sync={{
|
||||||
|
peer: `wss://cloud.jazz.tools/?key=${apiKey}`
|
||||||
|
}}
|
||||||
|
{defaultProfileName}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</JazzProvider>
|
||||||
|
<jazz-inspector></jazz-inspector>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:global(html, body) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
16
examples/chat-svelte/src/routes/+page.svelte
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { Chat } from '$lib/schema';
|
||||||
|
import { AccountCoState } from 'jazz-svelte';
|
||||||
|
import { Account, Group } from 'jazz-tools';
|
||||||
|
|
||||||
|
const account = new AccountCoState(Account);
|
||||||
|
const me = $derived(account.current);
|
||||||
|
$effect(() => {
|
||||||
|
if (!me) return;
|
||||||
|
const group = Group.create();
|
||||||
|
group.addMember('everyone', 'writer');
|
||||||
|
const chat = Chat.create([], group);
|
||||||
|
goto(`/chat/${chat.id}`);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
116
examples/chat-svelte/src/routes/chat/[id]/+page.svelte
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createImage } from 'jazz-browser-media-images';
|
||||||
|
import { AccountCoState, CoState } from 'jazz-svelte';
|
||||||
|
import { Account, CoPlainText, type ID } from 'jazz-tools';
|
||||||
|
|
||||||
|
import { page } from '$app/state';
|
||||||
|
|
||||||
|
import { Chat, Message } from '$lib/schema';
|
||||||
|
|
||||||
|
import AppContainer from '$lib/components/AppContainer.svelte';
|
||||||
|
import ChatBody from '$lib/components/ChatBody.svelte';
|
||||||
|
import ChatBubble from '$lib/components/ChatBubble.svelte';
|
||||||
|
import EmptyChatMessage from '$lib/components/EmptyChatMessage.svelte';
|
||||||
|
import ImageInput from '$lib/components/ImageInput.svelte';
|
||||||
|
import InputBar from '$lib/components/InputBar.svelte';
|
||||||
|
import TopBar from '$lib/components/TopBar.svelte';
|
||||||
|
import TextInput from '$lib/components/TextInput.svelte';
|
||||||
|
|
||||||
|
const chatId = $derived(page.params.id) as ID<typeof Chat>;
|
||||||
|
const chat = $derived(
|
||||||
|
new CoState(Chat, chatId, {
|
||||||
|
resolve: {
|
||||||
|
$each: {
|
||||||
|
text: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const account = new AccountCoState(Account, {
|
||||||
|
resolve: {
|
||||||
|
profile: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const me = $derived(account.current);
|
||||||
|
let showNLastMessages = $state(30);
|
||||||
|
const sendImage = (event: Event & { currentTarget: HTMLInputElement }) => {
|
||||||
|
const file = event.currentTarget.files?.[0];
|
||||||
|
|
||||||
|
if (!file || !chat.current) return;
|
||||||
|
|
||||||
|
if (file.size > 5000000) {
|
||||||
|
alert('Please upload an image less than 5MB.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createImage(file, { owner: chat.current._owner }).then((image) => {
|
||||||
|
if (!chat.current) return;
|
||||||
|
chat.current.push(
|
||||||
|
Message.create(
|
||||||
|
{
|
||||||
|
text: CoPlainText.create(file.name, chat.current._owner),
|
||||||
|
image: image
|
||||||
|
},
|
||||||
|
chat.current._owner
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AppContainer>
|
||||||
|
<TopBar>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={me?.profile?.name ?? ''}
|
||||||
|
class="bg-transparent"
|
||||||
|
onchange={(e) => {
|
||||||
|
if (!me?.profile) return;
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
me.profile.name = target.value;
|
||||||
|
}}
|
||||||
|
placeholder="Set username"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onclick={() => {
|
||||||
|
account.logOut();
|
||||||
|
window.location.reload(); // Otherwise the provider will not update with default profile name
|
||||||
|
}}>Log out</button
|
||||||
|
>
|
||||||
|
</TopBar>
|
||||||
|
{#if !chat}
|
||||||
|
<div class="flex items-center justify-center flex-1">Loading...</div>
|
||||||
|
{:else}
|
||||||
|
<ChatBody>
|
||||||
|
{#if chat.current && chat.current.length > 0}
|
||||||
|
{#each chat.current.slice(-showNLastMessages).reverse() as msg (msg.id)}
|
||||||
|
<ChatBubble {me} {msg} />
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
<EmptyChatMessage />
|
||||||
|
{/if}
|
||||||
|
{#if chat.current && chat.current.length > showNLastMessages}
|
||||||
|
<button
|
||||||
|
class="block px-4 py-1 mx-auto my-2 border rounded"
|
||||||
|
onclick={() => (showNLastMessages += 10)}
|
||||||
|
>
|
||||||
|
Show more
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</ChatBody>
|
||||||
|
<InputBar>
|
||||||
|
<ImageInput onImageChange={sendImage} />
|
||||||
|
<TextInput
|
||||||
|
onSubmit={(text: string) => {
|
||||||
|
if (!chat.current) return;
|
||||||
|
chat.current.push(
|
||||||
|
Message.create(
|
||||||
|
{ text: CoPlainText.create(text, chat.current._owner) },
|
||||||
|
chat.current._owner
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</InputBar>
|
||||||
|
{/if}
|
||||||
|
</AppContainer>
|
||||||
BIN
examples/chat-svelte/static/jazz-icon.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
18
examples/chat-svelte/svelte.config.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import adapter from '@sveltejs/adapter-auto';
|
||||||
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
|
||||||
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
|
const config = {
|
||||||
|
// Consult https://svelte.dev/docs/kit/integrations
|
||||||
|
// for more information about preprocessors
|
||||||
|
preprocess: vitePreprocess(),
|
||||||
|
|
||||||
|
kit: {
|
||||||
|
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
||||||
|
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||||
|
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
||||||
|
adapter: adapter()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
40
examples/chat-svelte/tests/chat.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { expect } from 'vitest';
|
||||||
|
import { ChatPage } from './pages/ChatPage';
|
||||||
|
import { test } from '@playwright/test';
|
||||||
|
|
||||||
|
test('chat works between two windows', async ({ page: marioPage, browser }) => {
|
||||||
|
await marioPage.goto('/');
|
||||||
|
const context = await browser.newContext();
|
||||||
|
const luigiPage = await context.newPage();
|
||||||
|
|
||||||
|
await marioPage.waitForURL('/chat/**');
|
||||||
|
const roomUrl = marioPage.url();
|
||||||
|
await luigiPage.goto(roomUrl);
|
||||||
|
|
||||||
|
const marioChat = new ChatPage(marioPage);
|
||||||
|
const luigiChat = new ChatPage(luigiPage);
|
||||||
|
|
||||||
|
|
||||||
|
await marioChat.setUsername('Mario');
|
||||||
|
|
||||||
|
const message1ByMario = 'Hello Luigi, are you ready to save the princess?';
|
||||||
|
|
||||||
|
await marioChat.sendMessage(message1ByMario);
|
||||||
|
await marioChat.expectMessageRow(message1ByMario);
|
||||||
|
|
||||||
|
const roomURL = marioPage.url();
|
||||||
|
await luigiPage.goto(roomURL);
|
||||||
|
|
||||||
|
await luigiChat.setUsername('Luigi');
|
||||||
|
|
||||||
|
await luigiChat.expectMessageRow(message1ByMario);
|
||||||
|
|
||||||
|
const message2ByLuigi = "No, I'm not ready yet. I'm still trying to find the key to the castle.";
|
||||||
|
|
||||||
|
await luigiChat.sendMessage(message2ByLuigi);
|
||||||
|
await luigiChat.expectMessageRow(message2ByLuigi);
|
||||||
|
|
||||||
|
await marioChat.expectMessageRow(message1ByMario);
|
||||||
|
await luigiChat.expectMessageRow(message2ByLuigi);
|
||||||
|
await context.close();
|
||||||
|
});
|
||||||
41
examples/chat-svelte/tests/pages/ChatPage.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { type Locator, type Page, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
export class ChatPage {
|
||||||
|
readonly page: Page;
|
||||||
|
readonly messageInput: Locator;
|
||||||
|
readonly logoutButton: Locator;
|
||||||
|
readonly usernameInput: Locator;
|
||||||
|
constructor(page: Page) {
|
||||||
|
this.page = page;
|
||||||
|
this.messageInput = page.getByRole('textbox', {
|
||||||
|
name: 'Type a message and press Enter'
|
||||||
|
});
|
||||||
|
this.logoutButton = page.getByRole('button', {
|
||||||
|
name: 'Log out'
|
||||||
|
});
|
||||||
|
this.usernameInput = page.getByPlaceholder('Set username');
|
||||||
|
}
|
||||||
|
|
||||||
|
async setUsername(username: string) {
|
||||||
|
await this.usernameInput.fill(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendMessage(message: string) {
|
||||||
|
await this.messageInput.fill(message);
|
||||||
|
await this.messageInput.press('Enter');
|
||||||
|
}
|
||||||
|
|
||||||
|
async expectMessageRow(message: string) {
|
||||||
|
await expect(this.page.getByText(message)).toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async expectUserNameNotToBeAnonymousUser() {
|
||||||
|
await expect(this.usernameInput).not.toHaveValue(/anonymous user/i);
|
||||||
|
await expect(this.usernameInput).toHaveValue(/^Anonymous \w+/);
|
||||||
|
}
|
||||||
|
|
||||||
|
async logout() {
|
||||||
|
await this.logoutButton.click();
|
||||||
|
await this.page.goto('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
19
examples/chat-svelte/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"extends": "./.svelte-kit/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "bundler"
|
||||||
|
}
|
||||||
|
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||||
|
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||||
|
//
|
||||||
|
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||||
|
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||||
|
}
|
||||||
7
examples/chat-svelte/vite.config.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [tailwindcss(), sveltekit()]
|
||||||
|
});
|
||||||
7
examples/chat-vue/.gitignore
vendored
@@ -1 +1,6 @@
|
|||||||
dist
|
dist
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="./public/favicon.ico" type="image/png">
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jazz Chat Vue Example</title>
|
<title>Jazz Chat Vue Example</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "chat-vue",
|
"name": "chat-vue",
|
||||||
"version": "0.0.120",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
6
examples/chat/.gitignore
vendored
@@ -29,3 +29,9 @@ sync-db/
|
|||||||
/playwright-report/
|
/playwright-report/
|
||||||
/blob-report/
|
/blob-report/
|
||||||
/playwright/.cache/
|
/playwright/.cache/
|
||||||
|
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en" class="h-full">
|
<html lang="en" class="h-full">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/png" href="/jazz-logo.png" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<link rel="stylesheet" href="/src/index.css" />
|
<link rel="stylesheet" href="/src/index.css" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jazz Chat Example</title>
|
<title>Jazz Chat Example</title>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-example-chat",
|
"name": "jazz-example-chat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.220",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
1
examples/clerk/.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VITE_CLERK_PUBLISHABLE_KEY=
|
||||||
@@ -1 +1 @@
|
|||||||
VITE_CLERK_PUBLISHABLE_KEY=pk_test_ZXZpZGVudC1kYW5lLTg5LmNsZXJrLmFjY291bnRzLmRldiQ
|
VITE_CLERK_PUBLISHABLE_KEY=pk_test_ZXZpZGVudC1kYW5lLTg5LmNsZXJrLmFjY291bnRzLmRldiQ
|
||||||
8
examples/clerk/.gitignore
vendored
@@ -23,4 +23,10 @@ dist-ssr
|
|||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
playwright-report
|
playwright-report
|
||||||
|
|
||||||
|
# Env
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -7,23 +7,34 @@ Live version: [https://clerk-demo.jazz.tools](https://clerk-demo.jazz.tools)
|
|||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
You can either
|
You can either
|
||||||
|
|
||||||
1. Clone the jazz repository, and run the app within the monorepo.
|
1. Clone the jazz repository, and run the app within the monorepo.
|
||||||
2. Or create a new Jazz project using this example as a template.
|
2. Or create a new Jazz project using this example as a template.
|
||||||
|
|
||||||
|
|
||||||
### Using the example as a template
|
### Using the example as a template
|
||||||
|
|
||||||
Create a new Jazz project, and use this example as a template.
|
Create a new Jazz project, and use this example as a template.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx create-jazz-app@latest clerk-app --example clerk
|
npx create-jazz-app@latest clerk-app --example clerk
|
||||||
```
|
```
|
||||||
|
|
||||||
Go to the new project directory.
|
Go to the new project directory.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd clerk-app
|
cd clerk-app
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Rename .env.example to .env
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mv .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Update `VITE_CLERK_PUBLISHABLE_KEY` with your [Publishable Key](https://clerk.com/docs/deployments/clerk-environment-variables#clerk-publishable-and-secret-keys) from Clerk.
|
||||||
|
|
||||||
Run the dev server.
|
Run the dev server.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
@@ -33,21 +44,33 @@ npm run dev
|
|||||||
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
|
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
|
||||||
|
|
||||||
Clone the jazz repository.
|
Clone the jazz repository.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/garden-co/jazz.git
|
git clone https://github.com/garden-co/jazz.git
|
||||||
```
|
```
|
||||||
|
|
||||||
Install and build dependencies.
|
Install and build dependencies.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm i && npx turbo build
|
pnpm i && npx turbo build
|
||||||
```
|
```
|
||||||
|
|
||||||
Go to the example directory.
|
Go to the example directory.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd jazz/examples/clerk/
|
cd jazz/examples/clerk/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Rename .env.example to .env
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mv .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Update `VITE_CLERK_PUBLISHABLE_KEY` with your [Publishable Key](https://clerk.com/docs/deployments/clerk-environment-variables#clerk-publishable-and-secret-keys) from Clerk.
|
||||||
|
|
||||||
Start the dev server.
|
Start the dev server.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm dev
|
pnpm dev
|
||||||
```
|
```
|
||||||
@@ -57,4 +80,3 @@ Open [http://localhost:5173](http://localhost:5173) with your browser to see the
|
|||||||
## Questions / problems / feedback
|
## Questions / problems / feedback
|
||||||
|
|
||||||
If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
|
If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Minimal Auth Clerk Example | Jazz</title>
|
<title>Minimal Auth Clerk Example | Jazz</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "clerk",
|
"name": "clerk",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.119",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -14,6 +13,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clerk/clerk-react": "^5.4.1",
|
"@clerk/clerk-react": "^5.4.1",
|
||||||
|
"jazz-inspector": "workspace:*",
|
||||||
"jazz-react": "workspace:*",
|
"jazz-react": "workspace:*",
|
||||||
"jazz-react-auth-clerk": "workspace:*",
|
"jazz-react-auth-clerk": "workspace:*",
|
||||||
"jazz-tools": "workspace:*",
|
"jazz-tools": "workspace:*",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -3,6 +3,7 @@ import { StrictMode } from "react";
|
|||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
import { JazzInspector } from "jazz-inspector";
|
||||||
import { JazzProviderWithClerk } from "jazz-react-auth-clerk";
|
import { JazzProviderWithClerk } from "jazz-react-auth-clerk";
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { apiKey } from "./apiKey";
|
import { apiKey } from "./apiKey";
|
||||||
@@ -44,6 +45,7 @@ if (location.search.includes("expirationTest")) {
|
|||||||
<ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/">
|
<ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/">
|
||||||
<JazzProvider>
|
<JazzProvider>
|
||||||
<App />
|
<App />
|
||||||
|
<JazzInspector />
|
||||||
</JazzProvider>
|
</JazzProvider>
|
||||||
</ClerkProvider>
|
</ClerkProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "file-share-svelte",
|
"name": "file-share-svelte",
|
||||||
"version": "0.0.104",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
<link rel="icon" type="image/png" href="%sveltekit.assets%/favicon.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -1,11 +1,3 @@
|
|||||||
<script lang="ts" module>
|
|
||||||
declare module 'jazz-svelte' {
|
|
||||||
interface Register {
|
|
||||||
Account: typeof FileShareAccount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { JazzProvider } from 'jazz-svelte';
|
import { JazzProvider } from 'jazz-svelte';
|
||||||
import "jazz-inspector-element"
|
import "jazz-inspector-element"
|
||||||
|
|||||||
8
examples/filestream/.gitignore
vendored
@@ -25,4 +25,10 @@ dist-ssr
|
|||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
playwright-report
|
playwright-report
|
||||||
|
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en" class="h-full">
|
<html lang="en" class="h-full">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/png" href="./public/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jazz | React + Demo Auth + Tailwind</title>
|
<title>Jazz | React + Demo Auth + Tailwind</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "filestream",
|
"name": "filestream",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.59",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
6
examples/form/.gitignore
vendored
@@ -25,3 +25,9 @@ dist-ssr
|
|||||||
|
|
||||||
/test-results/
|
/test-results/
|
||||||
/playwright-report/
|
/playwright-report/
|
||||||
|
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<html lang="en" class="h-full">
|
<html lang="en" class="h-full">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jazz | Form example</title>
|
<title>Jazz | Form example</title>
|
||||||
<link rel="icon" type="image/png" href="./public/favicon.ico">
|
|
||||||
</head>
|
</head>
|
||||||
<body class="h-full flex flex-col bg-white text-stone-700 dark:text-stone-400 dark:bg-stone-925">
|
<body class="h-full flex flex-col bg-white text-stone-700 dark:text-stone-400 dark:bg-stone-925">
|
||||||
<div id="root" class="align-self-center flex-1"></div>
|
<div id="root" class="align-self-center flex-1"></div>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "form",
|
"name": "form",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.60",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -12,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hash-slash": "workspace:*",
|
"hash-slash": "workspace:*",
|
||||||
|
"jazz-inspector": "workspace:*",
|
||||||
"jazz-react": "workspace:*",
|
"jazz-react": "workspace:*",
|
||||||
"jazz-tools": "workspace:*",
|
"jazz-tools": "workspace:*",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { JazzInspector } from "jazz-inspector";
|
||||||
import { JazzProvider } from "jazz-react";
|
import { JazzProvider } from "jazz-react";
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
@@ -15,6 +16,7 @@ createRoot(document.getElementById("root")!).render(
|
|||||||
AccountSchema={JazzAccount}
|
AccountSchema={JazzAccount}
|
||||||
>
|
>
|
||||||
<App />
|
<App />
|
||||||
|
<JazzInspector />
|
||||||
</JazzProvider>
|
</JazzProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
6
examples/image-upload/.gitignore
vendored
@@ -22,3 +22,9 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jazz | Image upload example</title>
|
<title>Jazz | Image upload example</title>
|
||||||
<link rel="icon" href="./public/favicon.ico" type="image/png">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "image-upload",
|
"name": "image-upload",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.116",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -11,6 +10,7 @@
|
|||||||
"format-and-lint:fix": "biome check . --write"
|
"format-and-lint:fix": "biome check . --write"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"jazz-inspector": "workspace:*",
|
||||||
"jazz-react": "workspace:*",
|
"jazz-react": "workspace:*",
|
||||||
"jazz-tools": "workspace:*",
|
"jazz-tools": "workspace:*",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { JazzInspector } from "jazz-inspector";
|
||||||
import { JazzProvider } from "jazz-react";
|
import { JazzProvider } from "jazz-react";
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
@@ -15,6 +16,7 @@ createRoot(document.getElementById("root")!).render(
|
|||||||
AccountSchema={JazzAccount}
|
AccountSchema={JazzAccount}
|
||||||
>
|
>
|
||||||
<App />
|
<App />
|
||||||
|
<JazzInspector />
|
||||||
</JazzProvider>
|
</JazzProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
8
examples/inspector/.gitignore
vendored
@@ -23,4 +23,10 @@ dist-ssr
|
|||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
sync-db/
|
sync-db/
|
||||||
|
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/png" href="/jazz-logo.png" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<link rel="stylesheet" href="/src/index.css" />
|
<link rel="stylesheet" href="/src/index.css" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jazz Inspector</title>
|
<title>Jazz Inspector</title>
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-inspector-app",
|
"name": "jazz-inspector-app",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.169",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
|
"test": "playwright test",
|
||||||
|
"test:headed": "playwright test --headed",
|
||||||
"format-and-lint": "biome check .",
|
"format-and-lint": "biome check .",
|
||||||
"format-and-lint:fix": "biome check . --write",
|
"format-and-lint:fix": "biome check . --write",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jazz-inspector": "workspace:*",
|
"jazz-inspector": "workspace:*",
|
||||||
|
"jazz-tools": "workspace:*",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"cojson": "workspace:*",
|
"cojson": "workspace:*",
|
||||||
"cojson-transport-ws": "workspace:*",
|
"cojson-transport-ws": "workspace:*",
|
||||||
"hash-slash": "workspace:*",
|
"hash-slash": "workspace:*",
|
||||||
"lucide-react": "^0.274.0",
|
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"react-router": "^6.16.0",
|
|
||||||
"react-router-dom": "^6.16.0",
|
|
||||||
"react-use": "^17.4.0"
|
"react-use": "^17.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.50.1",
|
||||||
"@types/react": "19.0.0",
|
"@types/react": "19.0.0",
|
||||||
"@types/react-dom": "19.0.0",
|
"@types/react-dom": "19.0.0",
|
||||||
"@vitejs/plugin-react-swc": "^3.10.1",
|
"@vitejs/plugin-react-swc": "^3.10.1",
|
||||||
|
|||||||
46
examples/inspector/playwright.config.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { defineConfig, devices } from "@playwright/test";
|
||||||
|
import isCI from "is-ci";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: "./tests",
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: isCI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: isCI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: isCI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: "html",
|
||||||
|
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
baseURL: "http://localhost:5173/",
|
||||||
|
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: "on-first-retry",
|
||||||
|
permissions: ["clipboard-read", "clipboard-write"],
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: "chromium",
|
||||||
|
use: { ...devices["Desktop Chrome"] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: [
|
||||||
|
{
|
||||||
|
command: "pnpm preview --port 5173",
|
||||||
|
url: "http://localhost:5173/",
|
||||||
|
reuseExistingServer: !isCI,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -35,6 +35,7 @@ interface JazzLoggedInSecret {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function CoJsonViewerApp() {
|
export default function CoJsonViewerApp() {
|
||||||
|
const [errors, setErrors] = useState<string | null>(null);
|
||||||
const [accounts, setAccounts] = useState<Account[]>(() => {
|
const [accounts, setAccounts] = useState<Account[]>(() => {
|
||||||
const storedAccounts = localStorage.getItem("inspectorAccounts");
|
const storedAccounts = localStorage.getItem("inspectorAccounts");
|
||||||
return storedAccounts ? JSON.parse(storedAccounts) : [];
|
return storedAccounts ? JSON.parse(storedAccounts) : [];
|
||||||
@@ -80,23 +81,46 @@ export default function CoJsonViewerApp() {
|
|||||||
websocket: new WebSocket("wss://cloud.jazz.tools"),
|
websocket: new WebSocket("wss://cloud.jazz.tools"),
|
||||||
role: "server",
|
role: "server",
|
||||||
});
|
});
|
||||||
const node = await LocalNode.withLoadedAccount({
|
let node;
|
||||||
accountID: currentAccount.id,
|
try {
|
||||||
accountSecret: currentAccount.secret,
|
node = await LocalNode.withLoadedAccount({
|
||||||
sessionID: crypto.newRandomSessionID(currentAccount.id),
|
accountID: currentAccount.id,
|
||||||
peersToLoadFrom: [wsPeer],
|
accountSecret: currentAccount.secret,
|
||||||
crypto,
|
sessionID: crypto.newRandomSessionID(currentAccount.id),
|
||||||
migration: async () => {
|
peersToLoadFrom: [wsPeer],
|
||||||
console.log("Not running any migration in inspector");
|
crypto,
|
||||||
},
|
migration: async () => {
|
||||||
});
|
console.log("Not running any migration in inspector");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err.toString().includes("invalid id")) {
|
||||||
|
setAccounts(accounts.filter((acc) => acc.id !== currentAccount.id));
|
||||||
|
//remove from localStorage
|
||||||
|
localStorage.removeItem("lastSelectedAccountId");
|
||||||
|
localStorage.setItem(
|
||||||
|
"inspectorAccounts",
|
||||||
|
JSON.parse(localStorage.inspectorAccounts).filter(
|
||||||
|
(acc: Account) => acc.id != currentAccount.id,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
setCurrentAccount(null);
|
||||||
|
setErrors("Trying to load covalue with invalid id");
|
||||||
|
} else {
|
||||||
|
setErrors("The account could not be loaded");
|
||||||
|
}
|
||||||
|
setLocalNode(null);
|
||||||
|
goToIndex(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setLocalNode(node);
|
setLocalNode(node);
|
||||||
});
|
});
|
||||||
}, [currentAccount, goToIndex, path]);
|
}, [currentAccount, accounts, goToIndex, path]);
|
||||||
|
|
||||||
const addAccount = (id: RawAccountID, secret: AgentSecret) => {
|
const addAccount = (id: RawAccountID, secret: AgentSecret) => {
|
||||||
const newAccount = { id, secret };
|
const newAccount = { id, secret };
|
||||||
const accountExists = accounts.some((account) => account.id === id);
|
const accountExists = accounts.some((account) => account.id === id);
|
||||||
|
//todo: ideally there would be some validation here so we don't have to manually remove a non existent account from localStorage
|
||||||
if (!accountExists) {
|
if (!accountExists) {
|
||||||
setAccounts([...accounts, newAccount]);
|
setAccounts([...accounts, newAccount]);
|
||||||
}
|
}
|
||||||
@@ -174,7 +198,9 @@ export default function CoJsonViewerApp() {
|
|||||||
goBack={goBack}
|
goBack={goBack}
|
||||||
addPages={addPages}
|
addPages={addPages}
|
||||||
>
|
>
|
||||||
{!currentAccount && <AddAccountForm addAccount={addAccount} />}
|
{!currentAccount && (
|
||||||
|
<AddAccountForm addAccount={addAccount} errors={errors} />
|
||||||
|
)}
|
||||||
|
|
||||||
{currentAccount && path.length <= 0 && (
|
{currentAccount && path.length <= 0 && (
|
||||||
<form
|
<form
|
||||||
@@ -270,8 +296,10 @@ function AccountSwitcher({
|
|||||||
|
|
||||||
function AddAccountForm({
|
function AddAccountForm({
|
||||||
addAccount,
|
addAccount,
|
||||||
|
errors,
|
||||||
}: {
|
}: {
|
||||||
addAccount: (id: RawAccountID, secret: AgentSecret) => void;
|
addAccount: (id: RawAccountID, secret: AgentSecret) => void;
|
||||||
|
errors: string | null;
|
||||||
}) {
|
}) {
|
||||||
const [id, setId] = useState("");
|
const [id, setId] = useState("");
|
||||||
const [secret, setSecret] = useState("");
|
const [secret, setSecret] = useState("");
|
||||||
@@ -305,8 +333,17 @@ function AddAccountForm({
|
|||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="flex flex-col gap-3 max-w-md mx-auto h-full justify-center"
|
className={`flex flex-col max-w-[30rem] mx-auto justify-center ${errors == null ? "h-full" : ""}`}
|
||||||
>
|
>
|
||||||
|
{errors != null && (
|
||||||
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mt-4 font-mono whitespace-pre-wrap break-words mb-8">
|
||||||
|
<h3>Error</h3>
|
||||||
|
<pre className="whitespace-pre-wrap break-words overflow-hidden">
|
||||||
|
{errors}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<h2 className="text-2xl font-medium text-gray-900 dark:text-white">
|
<h2 className="text-2xl font-medium text-gray-900 dark:text-white">
|
||||||
Add an account to inspect
|
Add an account to inspect
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
91
examples/inspector/tests/data.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { co, z } from "jazz-tools";
|
||||||
|
|
||||||
|
const projectsData: {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
issues: {
|
||||||
|
title: string;
|
||||||
|
status: "open" | "closed";
|
||||||
|
labels: string[];
|
||||||
|
}[];
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
name: "Jazz",
|
||||||
|
description: "Jazz is a framework for building collaborative apps.",
|
||||||
|
issues: [
|
||||||
|
{
|
||||||
|
title: "Issue 1",
|
||||||
|
status: "open",
|
||||||
|
labels: [
|
||||||
|
"bug",
|
||||||
|
"feature",
|
||||||
|
"enhancement",
|
||||||
|
"documentation",
|
||||||
|
"homepage",
|
||||||
|
"help needed",
|
||||||
|
"requested",
|
||||||
|
"blocked",
|
||||||
|
"high priority",
|
||||||
|
"urgent",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ title: "Issue 2", status: "closed", labels: ["bug"] },
|
||||||
|
{ title: "Issue 3", status: "open", labels: ["feature", "enhancement"] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Waffle",
|
||||||
|
description: "Start waffling",
|
||||||
|
issues: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Garden",
|
||||||
|
description: "Grow your garden",
|
||||||
|
issues: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Tilescape",
|
||||||
|
description: "",
|
||||||
|
issues: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const Issue = co.map({
|
||||||
|
title: z.string(),
|
||||||
|
status: z.enum(["open", "closed"]),
|
||||||
|
labels: co.list(z.string()),
|
||||||
|
});
|
||||||
|
|
||||||
|
const Project = co.map({
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
issues: co.list(Issue),
|
||||||
|
});
|
||||||
|
|
||||||
|
const Organization = co.map({
|
||||||
|
name: z.string(),
|
||||||
|
projects: co.list(Project),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createOrganization = () => {
|
||||||
|
return Organization.create({
|
||||||
|
name: "Garden Computing",
|
||||||
|
projects: co.list(Project).create(
|
||||||
|
projectsData.map((project) =>
|
||||||
|
Project.create({
|
||||||
|
name: project.name,
|
||||||
|
description: project.description,
|
||||||
|
issues: co.list(Issue).create(
|
||||||
|
project.issues.map((issue) =>
|
||||||
|
Issue.create({
|
||||||
|
title: issue.title,
|
||||||
|
status: issue.status,
|
||||||
|
labels: co.list(z.string()).create(issue.labels),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
};
|
||||||
82
examples/inspector/tests/inspector.spec.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { expect, test } from "@playwright/test";
|
||||||
|
import { createOrganization } from "./data";
|
||||||
|
import { createAccount, initializeKvStore } from "./lib";
|
||||||
|
|
||||||
|
initializeKvStore();
|
||||||
|
const { account, accountID, accountSecret } = await createAccount();
|
||||||
|
|
||||||
|
test("should add and delete account in dropdown", async ({ page }) => {
|
||||||
|
await page.goto("/");
|
||||||
|
await page.getByLabel("Account ID").fill(accountID);
|
||||||
|
await page.getByLabel("Account secret").fill(accountSecret);
|
||||||
|
await page.getByRole("button", { name: "Add account" }).click();
|
||||||
|
|
||||||
|
await expect(page.getByText("Jazz CoValue Inspector")).toBeVisible();
|
||||||
|
await page
|
||||||
|
.getByLabel("Account to inspect")
|
||||||
|
.selectOption(`Inspector test account <${accountID}>`);
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "Remove account" }).click();
|
||||||
|
await expect(page.getByText("Jazz CoValue Inspector")).not.toBeVisible();
|
||||||
|
await expect(page.getByText("Add an account to inspect")).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByText(`Inspector test account <${accountID}>`),
|
||||||
|
).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should inspect account", async ({ page }) => {
|
||||||
|
await page.goto("/");
|
||||||
|
await page.getByLabel("Account ID").fill(accountID);
|
||||||
|
await page.getByLabel("Account secret").fill(accountSecret);
|
||||||
|
await page.getByRole("button", { name: "Add account" }).click();
|
||||||
|
await page.getByRole("button", { name: "Inspect my account" }).click();
|
||||||
|
|
||||||
|
await expect(page.getByRole("heading", { name: accountID })).toBeVisible();
|
||||||
|
await expect(page.getByText("👤 Account")).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "profile {} CoMap name:" }).click();
|
||||||
|
await expect(page.getByText("Role: admin")).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should inspect CoValue", async ({ page }) => {
|
||||||
|
await page.goto("/");
|
||||||
|
await page.getByLabel("Account ID").fill(accountID);
|
||||||
|
await page.getByLabel("Account secret").fill(accountSecret);
|
||||||
|
await page.getByRole("button", { name: "Add account" }).click();
|
||||||
|
|
||||||
|
const organization = createOrganization();
|
||||||
|
|
||||||
|
await account.waitForAllCoValuesSync(); // Ensures that the organization is uploaded
|
||||||
|
|
||||||
|
await page.getByLabel("CoValue ID").fill(organization.id);
|
||||||
|
await page.getByRole("button", { name: "Inspect CoValue" }).click();
|
||||||
|
|
||||||
|
await expect(page.getByText(/Garden Computing/)).toHaveCount(2);
|
||||||
|
await expect(
|
||||||
|
page.getByRole("heading", { name: organization.id }),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(page.getByText("Role: admin")).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: /projects/ }).click();
|
||||||
|
await expect(page.getByText("Showing 4 of 4")).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "View" }).first().click();
|
||||||
|
await expect(
|
||||||
|
page.getByText("Jazz is a framework for building collaborative apps."),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: /issues/ }).click();
|
||||||
|
await expect(page.getByText("Showing 3 of 3")).toBeVisible();
|
||||||
|
await page.getByRole("button", { name: "View" }).first().click();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: /labels/ }).click();
|
||||||
|
// currently broken:
|
||||||
|
// await expect(page.getByText("Showing 10 of 10")).toBeVisible();
|
||||||
|
await expect(page.getByRole("table").getByRole("row")).toHaveCount(11);
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "issues" }).click();
|
||||||
|
await expect(page.getByRole("table").getByRole("row")).toHaveCount(4);
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "projects" }).click();
|
||||||
|
await expect(page.getByRole("table").getByRole("row")).toHaveCount(5);
|
||||||
|
});
|
||||||
43
examples/inspector/tests/lib.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { createWebSocketPeer } from "cojson-transport-ws";
|
||||||
|
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
||||||
|
import {
|
||||||
|
AuthSecretStorage,
|
||||||
|
InMemoryKVStore,
|
||||||
|
KvStoreContext,
|
||||||
|
co,
|
||||||
|
createJazzContext,
|
||||||
|
randomSessionProvider,
|
||||||
|
z,
|
||||||
|
} from "jazz-tools";
|
||||||
|
|
||||||
|
export const initializeKvStore = () => {
|
||||||
|
const kvStore = new InMemoryKVStore();
|
||||||
|
KvStoreContext.getInstance().initialize(kvStore);
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function createAccount() {
|
||||||
|
const { account, authSecretStorage } = await createJazzContext({
|
||||||
|
defaultProfileName: "Inspector test account",
|
||||||
|
crypto: await WasmCrypto.create(),
|
||||||
|
sessionProvider: randomSessionProvider,
|
||||||
|
authSecretStorage: new AuthSecretStorage(),
|
||||||
|
peersToLoadFrom: [
|
||||||
|
createWebSocketPeer({
|
||||||
|
id: "upstream",
|
||||||
|
role: "server",
|
||||||
|
websocket: new WebSocket(
|
||||||
|
"wss://cloud.jazz.tools/?key=inspector-test@jazz.tools",
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await account.waitForAllCoValuesSync();
|
||||||
|
|
||||||
|
const credentials = await authSecretStorage.get();
|
||||||
|
if (!credentials) {
|
||||||
|
throw new Error("No credentials found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return { account, ...credentials };
|
||||||
|
}
|
||||||
6
examples/jazz-nextjs/.gitignore
vendored
@@ -39,3 +39,9 @@ yarn-error.log*
|
|||||||
# typescript
|
# typescript
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
|
|
||||||
|
# env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "jazz-nextjs",
|
"name": "jazz-nextjs",
|
||||||
"version": "0.1.9",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack",
|
"dev": "next dev --turbopack",
|
||||||
@@ -12,6 +11,7 @@
|
|||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"next": "15.3.2",
|
"next": "15.3.2",
|
||||||
|
"jazz-inspector": "workspace:*",
|
||||||
"jazz-react": "workspace:*",
|
"jazz-react": "workspace:*",
|
||||||
"jazz-tools": "workspace:*"
|
"jazz-tools": "workspace:*"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { JazzInspector } from "jazz-inspector";
|
||||||
import { JazzProvider } from "jazz-react";
|
import { JazzProvider } from "jazz-react";
|
||||||
|
|
||||||
export function Jazz({ children }: { children: React.ReactNode }) {
|
export function Jazz({ children }: { children: React.ReactNode }) {
|
||||||
@@ -11,6 +12,7 @@ export function Jazz({ children }: { children: React.ReactNode }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
<JazzInspector />
|
||||||
</JazzProvider>
|
</JazzProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||