Compare commits

..

103 Commits

Author SHA1 Message Date
Guido D'Orsi
a383c7e984 Merge pull request #2432 from garden-co/changeset-release/main
Version Packages
2025-06-05 13:11:13 +02:00
github-actions[bot]
8ca283147d Version Packages 2025-06-05 11:04:14 +00:00
Guido D'Orsi
c3d87796ed chore: update changeset 2025-06-05 13:00:37 +02:00
Guido D'Orsi
cb88caced9 fix(comap): return a valid value on _createdAt even when setting a custom uniqueness value 2025-06-05 12:58:26 +02:00
Guido D'Orsi
6313ead62d Revert "fix: use creation time from CoValue header"
This reverts commit cc0479afe0.
2025-06-05 12:38:23 +02:00
Guido D'Orsi
f674910aa9 Merge pull request #2426 from garden-co/emil/comap-time-getters
feat: `_createdAt` and `_lastUpdatedAt`
2025-06-05 12:23:23 +02:00
Guido D'Orsi
37fc25f5a6 Merge pull request #2434 from garden-co/fix/svelte-costate
Fix id reactivity on CoState for Svelte 5.33 (second try)
2025-06-05 12:22:19 +02:00
Guido D'Orsi
5e9c338c27 Merge pull request #2436 from garden-co/feat/react-19-updates
fix(react-19): optimize re-renders when the values are already in memory
2025-06-05 12:21:55 +02:00
Guido D'Orsi
4b61f7c7a5 chore: format 2025-06-05 12:20:58 +02:00
Guido D'Orsi
1c8472ffbd Merge pull request #2441 from garden-co/fix/union-schema-conversion
Fix union schemas in anySchemaToCoSchema
2025-06-05 12:19:33 +02:00
Benjamin S. Leveritt
9dba68ac36 Remove migration script
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-06-05 11:18:29 +01:00
Anselm
13b57aa576 Add changeset 2025-06-05 11:10:05 +01:00
Anselm
aedf0f3ac5 Fix union schemas in anySchemaToCoSchema 2025-06-05 11:09:06 +01:00
Benjamin S. Leveritt
7fa61644b0 Revert turbo.json to original state 2025-06-05 10:19:22 +01:00
Benjamin S. Leveritt
12389c82f9 Add migration script to update all projects to enhanced ignore script 2025-06-05 10:05:16 +01:00
Benjamin S. Leveritt
4c03a17d3a Optimize turbo.json for better caching and build performance 2025-06-05 10:04:51 +01:00
Benjamin S. Leveritt
5d1ea45a9c Add enhanced Vercel build ignore script with change detection 2025-06-05 10:04:34 +01:00
Emil Sayahi
cc0479afe0 fix: use creation time from CoValue header 2025-06-04 15:45:59 -07:00
Emil Sayahi
cfb6786468 feat(jazz-expo): API for clearing local DB (#2427)
* feat(jazz-expo): API for clearing local DB

todo:
- tests
- changeset

* Revert "feat(jazz-expo): API for clearing local DB"

This reverts commit 459e1d04ea.

* feat(jazz-expo): API for clearing local DB

* chore: changeset

* Update .changeset/plenty-ways-smash.md

Co-authored-by: Guido D'Orsi <guido@garden.co>

---------

Co-authored-by: Guido D'Orsi <guido@garden.co>
2025-06-04 12:35:04 -07:00
Emil Sayahi
5662faa9c0 chore: changeset 2025-06-04 12:10:15 -07:00
Emil Sayahi
3e7d9cb585 feat: tests 2025-06-04 12:08:56 -07:00
Guido D'Orsi
2116a598ae fix(react-19): optimize re-renders when the values are already in memory 2025-06-04 19:34:12 +02:00
Guido D'Orsi
d14a069a12 Fix id reactivity on CoState for Svelte 5.33 (second try) 2025-06-04 16:11:14 +02:00
Anselm Eickhoff
aacef80994 Merge pull request #2433 from garden-co/fix/team-page
update team page, adding me and making all socials the same order
2025-06-04 14:46:10 +01:00
Sammii
2a237e5d32 amending file .ext 2025-06-04 14:39:27 +01:00
Sammii
0fe30eca0b update team page, adding me and making all socials the same order 2025-06-04 14:23:40 +01:00
Guido D'Orsi
dea7a8dfd9 Merge pull request #2282 from Wizzel1/Add-missing-discriminator
Add missing discriminator
2025-06-04 15:21:29 +02:00
Guido D'Orsi
ab7191bed0 Merge remote-tracking branch 'origin/main' into Add-missing-discriminator 2025-06-04 15:12:14 +02:00
Guido D'Orsi
901b7c0a51 Merge pull request #2377 from garden-co/2376-groupmakepublic-as-an-alias
Add makePublic to group
2025-06-04 15:02:05 +02:00
Benjamin S. Leveritt
17bea5975c Merge pull request #2430 from garden-co/test-create-jazz-app
Test `create-jazz-app`
2025-06-04 12:54:56 +01:00
Benjamin S. Leveritt
e005ecd0a1 Add changeset 2025-06-04 12:08:27 +01:00
Benjamin S. Leveritt
e7e505e5f3 Add changeset 2025-06-04 12:03:58 +01:00
Benjamin S. Leveritt
d6ffe03d3c Add makePublic to docs 2025-06-04 12:02:18 +01:00
Benjamin S. Leveritt
1120747a24 Add makePublic alias to some example apps 2025-06-04 11:50:24 +01:00
Benjamin S. Leveritt
1e2d7d1c4e Add makePublic to group 2025-06-04 11:44:06 +01:00
Benjamin S. Leveritt
e26f110acd Merge pull request #2428 from garden-co/feature/co-map-migrations
Tweak CoMap migration copy and examples
2025-06-04 11:37:21 +01:00
Benjamin S. Leveritt
28f84a4ee6 Update lock 2025-06-04 11:31:36 +01:00
Benjamin S. Leveritt
cffe4abb84 Handle SIGINT gracefully 2025-06-04 11:21:00 +01:00
Benjamin S. Leveritt
2e0b7cee8c Refactor package manager detection into utils 2025-06-04 11:21:00 +01:00
Benjamin S. Leveritt
d3b47f59e8 Add automatic tests 2025-06-04 11:21:00 +01:00
Benjamin S. Leveritt
aea3287965 Merge pull request #2373 from lukahartwig/main
Set default package manager based on command runner
2025-06-04 11:17:25 +01:00
Benjamin S. Leveritt
6525f8a12e Merge pull request #2325 from garden-co/2324-turbo-dev-doesnt-need-to-build-the-local-package
Turbo just builds deps now
2025-06-04 09:11:16 +01:00
Benjamin S. Leveritt
fe4c934a4b Tweak copy and examples in the docs 2025-06-04 08:26:05 +01:00
Emil Sayahi
60261c8dba feat: _createdAt and _lastUpdatedAt 2025-06-03 13:34:55 -07:00
Guido D'Orsi
7411049faa Merge pull request #2423 from garden-co/changeset-release/main
Version Packages
2025-06-03 19:48:03 +02:00
github-actions[bot]
356b06559b Version Packages 2025-06-03 17:45:08 +00:00
Guido D'Orsi
193738cfe2 Merge pull request #2405 from garden-co/feature/co-map-migrations
feat: add support for coMap migrations
2025-06-03 19:40:53 +02:00
Guido D'Orsi
ddb74fa167 docs: remove unused import 2025-06-03 19:35:31 +02:00
Guido D'Orsi
aca5642671 Merge pull request #2422 from garden-co/changeset-release/main
Version Packages
2025-06-03 19:27:45 +02:00
github-actions[bot]
a5bed20c4a Version Packages 2025-06-03 17:25:46 +00:00
Guido D'Orsi
09bf53a8d3 Merge pull request #2421 from garden-co/fix/react-native-account-schema
fix: fix the AccountSchema prop type to accept co.account schemas
2025-06-03 19:22:11 +02:00
Guido D'Orsi
061ec996b1 fix: F=fix the AccountSchema prop type to accept co.account schemas 2025-06-03 19:17:19 +02:00
Guido D'Orsi
a7ee0465b5 docs: small fix 2025-06-03 18:35:04 +02:00
Guido D'Orsi
e995d8a1fe chore: fix type issue in todo example 2025-06-03 17:50:17 +02:00
Guido D'Orsi
5ccb48446e docs: cover CoMap migrations 2025-06-03 17:46:12 +02:00
Guido D'Orsi
04b20c2e42 fix: fix castAs for Zod schemas and make the CoMap migrations stable 2025-06-03 17:14:59 +02:00
Benjamin S. Leveritt
7aae2441a1 Merge pull request #2231 from garden-co/2223-history-and-time-travel-doc
2223-history-and-time-travel-doc
2025-06-03 14:35:30 +01:00
Benjamin S. Leveritt
650e95a528 Merge pull request #2414 from garden-co/2412-fix-jazz-vue-builds-following-014
Add typecheck to jazz-vue before build
2025-06-03 14:34:53 +01:00
Benjamin S. Leveritt
3d80ab11d9 Minor tweak for efficiency 2025-06-03 14:32:59 +01:00
Benjamin S. Leveritt
85e6489a3e Add note about finding from field.all and chronological order 2025-06-03 14:30:03 +01:00
Benjamin S. Leveritt
45b6c87ade Fix chronological order notes 2025-06-03 14:16:39 +01:00
Guido D'Orsi
edadc4b986 Merge pull request #2411 from garden-co/fix/id-reactivity
fix: fix id reactivity in CoState for svelte > 5.33
2025-06-03 15:06:56 +02:00
Benjamin S. Leveritt
455b722357 Add typecheck before build 2025-06-03 13:25:53 +01:00
Benjamin S. Leveritt
ad2e1d1e98 Suppress the supressions
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-06-03 13:17:37 +01:00
Benjamin S. Leveritt
7c94b70c31 Add biome linting 2025-06-03 12:53:00 +01:00
Benjamin S. Leveritt
74bcf1752e Update Provider types 2025-06-03 12:16:42 +01:00
Guido D'Orsi
97a54b3911 fix: revert changes on src/lib/jazz.class.svelte.ts 2025-06-03 13:07:23 +02:00
Benjamin S. Leveritt
c393c8880f Fix import 2025-06-03 11:41:20 +01:00
Guido D'Orsi
359157fa70 chore: add comment 2025-06-03 12:40:02 +02:00
Guido D'Orsi
62d9680449 chore: update vite to the latest version 2025-06-03 12:38:45 +02:00
Trisha Lim
db6067439d fix missing date 2025-06-03 11:26:51 +01:00
Guido D'Orsi
5051d6a410 fix: fix id reactivity in CoState for svelte > 5.33 2025-06-03 12:23:18 +02:00
Trisha Lim
25efaf30f5 add docs for storing createdAt manually 2025-06-03 11:18:37 +01:00
Trisha Lim
98aadd9842 Show date created on version history example 2025-06-03 11:17:54 +01:00
Trisha Lim
d555b18c11 test homepage routes (#2399)
* test homepage routes

* add playwright.yml to homepage dir

* Revert "add playwright.yml to homepage dir"

This reverts commit f0507ee4f7dd29d25db56d3227937c901f9225a0.

* Add turbo dep to homepage

* Split homepage playwright script out

* remove playwright from test command

* install homepage deps

* update lock file

---------

Co-authored-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-06-03 09:25:28 +01:00
Benjamin S. Leveritt
550111f8a1 Merge pull request #2408 from garden-co/2407-remove-api-reference-from-build
Remove api references from build
2025-06-02 21:05:16 +01:00
Trisha Lim
3d4a00a19d Merge pull request #2409 from garden-co/fix/expo-dark-logo
fix: expo logo color on dark mode
2025-06-02 21:03:41 +01:00
Benjamin S. Leveritt
d06c6677dc Purge typedoc dep 2025-06-02 20:45:31 +01:00
Trisha Lim
ce30f3c4ff fix: expo logo color on dark mode 2025-06-02 20:32:23 +01:00
Benjamin S. Leveritt
1072b9c2fe Remove api ref docs from llms.txt 2025-06-02 20:28:24 +01:00
Benjamin S. Leveritt
5ea41c69ef Remove all the references to API refs 2025-06-02 20:18:11 +01:00
Guido D'Orsi
2d8eed3b69 chore: remove unused var 2025-06-02 21:13:59 +02:00
Benjamin S. Leveritt
45c9c8558f Remove build script 2025-06-02 20:08:19 +01:00
Guido D'Orsi
dccb80edf0 fix: quick fix layout overflows and restore automatic next song 2025-06-02 21:07:58 +02:00
Guido D'Orsi
6f72419b6e feat: add support for coMap migrations 2025-06-02 20:23:52 +02:00
Luka Hartwig
fa2227716f Remove return type 2025-05-27 23:08:56 +02:00
Luka Hartwig
38dabd4602 Set default package manager based on command runner 2025-05-27 16:34:40 +02:00
Benjamin S. Leveritt
156167e6d7 Update nav items
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-05-23 07:56:06 +01:00
Benjamin S. Leveritt
aef84cf2ef Tweak History title
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-05-22 21:15:50 +01:00
Benjamin S. Leveritt
275a26e2c1 Splits history patterns out of history doc
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-05-22 21:12:14 +01:00
Benjamin S. Leveritt
946ae63070 Fix codeblocks for 0.14
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-05-22 16:38:05 +01:00
Benjamin S. Leveritt
5cfe47ebbe Add history to nav 2025-05-22 13:33:52 +01:00
Benjamin S. Leveritt
6ee0ec755e Minor tweaks 2025-05-22 13:33:52 +01:00
Benjamin S. Leveritt
8ffca202bd Adds type checking plus tweaks 2025-05-22 13:33:51 +01:00
Benjamin S. Leveritt
6d2bcc7490 Rename history doc 2025-05-22 13:30:54 +01:00
Benjamin S. Leveritt
69709c2cf2 Turbo just builds deps now
What a smol change?
2025-05-22 10:29:42 +01:00
Wizzel1
e88252bee4 Fix formatting 2025-05-19 20:20:52 +02:00
Wizzel1
a6b7857f6f Fix markdown formatting 2025-05-19 20:06:28 +02:00
Wizzel1
265c30158e Fix markdown formatting 2025-05-19 19:59:56 +02:00
Wizzel1
505e132f1e Run format script 2025-05-19 19:53:12 +02:00
Wizzel1
c6d5195cb5 Update tests 2025-05-19 19:48:22 +02:00
Wizzel1
8af543e7d6 Update docs 2025-05-19 19:48:17 +02:00
Wizzel1
016b2098a7 Update example 2025-05-19 19:48:11 +02:00
235 changed files with 5602 additions and 7016 deletions

View File

@@ -0,0 +1,46 @@
name: Playwright Tests
on:
push:
branches: ["main"]
pull_request:
types: [opened, synchronize, reopened]
jobs:
test:
timeout-minutes: 60
runs-on: blacksmith-4vcpu-ubuntu-2204
strategy:
matrix:
project: ["homepage/homepage"]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Install project dependencies
run: pnpm install
working-directory: ./${{ matrix.project }}
- name: Pnpm Build
run: pnpm turbo build
working-directory: ./${{ matrix.project }}
- name: Install Playwright Browsers
run: pnpm exec playwright install
working-directory: ./${{ matrix.project }}
- name: Run Playwright tests
run: pnpm exec playwright test
working-directory: ./${{ matrix.project }}
- uses: actions/upload-artifact@v4
if: failure()
with:
name: ${{ hashFiles(format('{0}/package.json', matrix.project)) }}-playwright-report
path: ./${{ matrix.project }}/playwright-report/
retention-days: 30

View File

@@ -64,7 +64,7 @@
}
},
{
"include": ["packages/**/src/tests/**"],
"include": ["**/tests/**"],
"linter": {
"rules": {
"correctness": {

View File

@@ -1,5 +1,44 @@
# betterauth
## 0.1.24
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-betterauth-server-plugin@0.14.21
- jazz-inspector@0.14.21
- jazz-react@0.14.21
- jazz-react-auth-betterauth@0.14.21
- jazz-betterauth-client-plugin@0.14.21
## 0.1.23
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-betterauth-server-plugin@0.14.20
- jazz-inspector@0.14.20
- jazz-react@0.14.20
- jazz-react-auth-betterauth@0.14.20
- jazz-betterauth-client-plugin@0.14.20
## 0.1.22
### Patch Changes
- jazz-betterauth-client-plugin@0.14.19
- jazz-betterauth-server-plugin@0.14.19
- jazz-react-auth-betterauth@0.14.19
- jazz-inspector@0.14.19
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.1.21
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "betterauth",
"version": "0.1.21",
"version": "0.1.24",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,37 @@
# chat-rn-expo-clerk
## 1.0.144
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [cfb6786]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-expo@0.14.21
- jazz-react-native-media-images@0.14.21
## 1.0.143
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-expo@0.14.20
- jazz-react-native-media-images@0.14.20
## 1.0.142
### Patch Changes
- Updated dependencies [061ec99]
- jazz-expo@0.14.19
- jazz-react-native-media-images@0.14.19
- jazz-tools@0.14.19
## 1.0.141
### Patch Changes

View File

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

View File

@@ -1,5 +1,34 @@
# chat-rn-expo
## 1.0.12
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [cfb6786]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-expo@0.14.21
## 1.0.11
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-expo@0.14.20
## 1.0.10
### Patch Changes
- Updated dependencies [061ec99]
- jazz-expo@0.14.19
- jazz-tools@0.14.19
## 1.0.9
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn-expo",
"version": "1.0.9",
"version": "1.0.12",
"main": "index.ts",
"scripts": {
"build": "expo prebuild",

View File

@@ -1,5 +1,40 @@
# chat-rn
## 1.0.139
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [c3d8779]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- cojson@0.14.21
- jazz-react-native@0.14.21
- cojson-transport-ws@0.14.21
## 1.0.138
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react-native@0.14.20
- cojson@0.14.20
- cojson-transport-ws@0.14.20
## 1.0.137
### Patch Changes
- Updated dependencies [061ec99]
- jazz-react-native@0.14.19
- cojson@0.14.19
- cojson-transport-ws@0.14.19
- jazz-tools@0.14.19
## 1.0.136
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.136",
"version": "1.0.139",
"main": "index.js",
"scripts": {
"android": "react-native run-android",

View File

@@ -1,5 +1,35 @@
# chat-vue
## 0.0.119
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-browser@0.14.21
- jazz-vue@0.14.21
## 0.0.118
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-browser@0.14.20
- jazz-vue@0.14.20
## 0.0.117
### Patch Changes
- jazz-browser@0.14.19
- jazz-tools@0.14.19
- jazz-vue@0.14.19
## 0.0.116
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.116",
"version": "0.0.119",
"private": true,
"type": "module",
"scripts": {
@@ -32,7 +32,7 @@
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11",
"vite": "6.3.5",
"vite-plugin-vue-devtools": "^7.4.6",
"vue-tsc": "^2.1.6"
}

View File

@@ -1,5 +1,35 @@
# jazz-example-chat
## 0.0.219
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-inspector@0.14.21
- jazz-react@0.14.21
## 0.0.218
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-inspector@0.14.20
- jazz-react@0.14.20
## 0.0.217
### Patch Changes
- jazz-inspector@0.14.19
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.216
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.216",
"version": "0.0.219",
"type": "module",
"scripts": {
"dev": "vite",
@@ -27,12 +27,12 @@
"@playwright/test": "^1.50.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"@vitejs/plugin-react-swc": "^3.10.1",
"autoprefixer": "^10.4.20",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -18,7 +18,7 @@ export function App() {
const createChat = () => {
if (!me) return;
const group = Group.create();
group.addMember("everyone", "writer");
group.makePublic("writer");
const chat = Chat.create([], group);
router.navigate("/#/chat/" + chat.id);

View File

@@ -1,5 +1,35 @@
# minimal-auth-clerk
## 0.0.118
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
- jazz-react-auth-clerk@0.14.21
## 0.0.117
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
- jazz-react-auth-clerk@0.14.20
## 0.0.116
### Patch Changes
- jazz-react@0.14.19
- jazz-react-auth-clerk@0.14.19
- jazz-tools@0.14.19
## 0.0.115
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.115",
"version": "0.0.118",
"type": "module",
"scripts": {
"dev": "vite",
@@ -25,9 +25,9 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,36 @@
# file-share-svelte
## 0.0.103
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [d14a069]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-svelte@0.14.21
- jazz-inspector-element@0.14.21
## 0.0.102
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-inspector-element@0.14.20
- jazz-svelte@0.14.20
## 0.0.101
### Patch Changes
- jazz-inspector-element@0.14.19
- jazz-svelte@0.14.19
- jazz-tools@0.14.19
## 0.0.100
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.100",
"version": "0.0.103",
"private": true,
"type": "module",
"scripts": {
@@ -30,12 +30,12 @@
"prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.2.6",
"prettier-plugin-tailwindcss": "^0.6.5",
"svelte": "^5.0.0",
"svelte": "^5.33.0",
"svelte-check": "^4.0.0",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"typescript-eslint": "^8.0.0",
"vite": "6.0.11"
"vite": "6.3.5"
},
"dependencies": {
"@tailwindcss/typography": "^0.5.15",

View File

@@ -1,5 +1,35 @@
# jazz-tailwind-demo-auth-starter
## 0.0.58
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-inspector@0.14.21
- jazz-react@0.14.21
## 0.0.57
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-inspector@0.14.20
- jazz-react@0.14.20
## 0.0.56
### Patch Changes
- jazz-inspector@0.14.19
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.55
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "filestream",
"private": true,
"version": "0.0.55",
"version": "0.0.58",
"type": "module",
"scripts": {
"dev": "vite",
@@ -21,13 +21,13 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,32 @@
# form
## 0.1.59
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.1.58
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.1.57
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.1.56
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.1.56",
"version": "0.1.59",
"type": "module",
"scripts": {
"dev": "vite",
@@ -23,13 +23,13 @@
"@tailwindcss/forms": "^0.5.9",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,32 @@
# image-upload
## 0.0.115
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.114
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.113
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.112
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.112",
"version": "0.0.115",
"type": "module",
"scripts": {
"dev": "vite",
@@ -20,10 +20,10 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",
"vite": "6.0.11",
"vite": "6.3.5",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17"

View File

@@ -1,5 +1,30 @@
# jazz-example-inspector
## 0.0.168
### Patch Changes
- Updated dependencies [c3d8779]
- cojson@0.14.21
- jazz-inspector@0.14.21
- cojson-transport-ws@0.14.21
## 0.0.167
### Patch Changes
- jazz-inspector@0.14.20
- cojson@0.14.20
- cojson-transport-ws@0.14.20
## 0.0.166
### Patch Changes
- cojson@0.14.19
- cojson-transport-ws@0.14.19
- jazz-inspector@0.14.19
## 0.0.165
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector-app",
"private": true,
"version": "0.0.165",
"version": "0.0.168",
"type": "module",
"scripts": {
"dev": "vite",
@@ -26,11 +26,11 @@
"devDependencies": {
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"@vitejs/plugin-react-swc": "^3.10.1",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,32 @@
# jazz-nextjs
## 0.1.8
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.1.7
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.1.6
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.1.5
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-nextjs",
"version": "0.1.5",
"version": "0.1.8",
"private": true,
"scripts": {
"dev": "next dev --turbopack",

View File

@@ -41,6 +41,6 @@
"npm-run-all": "^4.1.5",
"tsx": "^4.19.3",
"typescript": "~5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,32 @@
# multi-cursors
## 0.0.111
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.110
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.109
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.108
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "multi-cursors",
"private": true,
"version": "0.0.108",
"version": "0.0.111",
"type": "module",
"scripts": {
"dev": "vite",
@@ -23,14 +23,14 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11",
"vite": "6.3.5",
"vitest": "3.1.1"
}
}

View File

@@ -36,7 +36,7 @@ export const CursorAccount = co
if (account.profile === undefined) {
const group = Group.create();
group.addMember("everyone", "reader"); // The profile info is visible to everyone
group.makePublic(); // The profile info is visible to everyone
account.profile = CursorProfile.create(
{

View File

@@ -1,5 +1,35 @@
# multiauth
## 0.0.59
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
- jazz-react-auth-clerk@0.14.21
## 0.0.58
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
- jazz-react-auth-clerk@0.14.20
## 0.0.57
### Patch Changes
- jazz-react@0.14.19
- jazz-react-auth-clerk@0.14.19
- jazz-tools@0.14.19
## 0.0.56
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "multiauth",
"private": true,
"version": "0.0.56",
"version": "0.0.59",
"type": "module",
"scripts": {
"dev": "vite",
@@ -22,9 +22,9 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,35 @@
# jazz-example-musicplayer
## 0.0.140
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-inspector@0.14.21
- jazz-react@0.14.21
## 0.0.139
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-inspector@0.14.20
- jazz-react@0.14.20
## 0.0.138
### Patch Changes
- jazz-inspector@0.14.19
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.137
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.137",
"version": "0.0.140",
"type": "module",
"scripts": {
"dev": "vite",
@@ -37,11 +37,11 @@
"@playwright/test": "^1.50.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"@vitejs/plugin-react-swc": "^3.10.1",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -41,8 +41,8 @@ export const MusicTrack = co.map({
/**
* You can use getters for recusrive relations
*/
get sourceTrack(): z.ZodOptional<typeof MusicTrack> {
return z.optional(MusicTrack);
get sourceTrack() {
return MusicTrack.optional();
},
});
export type MusicTrack = co.loaded<typeof MusicTrack>;

View File

@@ -14,6 +14,7 @@ import { apiKey } from "@/apiKey.ts";
import { SidebarProvider } from "@/components/ui/sidebar";
import { JazzProvider } from "jazz-react";
import { onAnonymousAccountDiscarded } from "./4_actions";
import { KeyboardListener } from "./components/PlayerControls";
import { useUploadExampleData } from "./lib/useUploadExampleData";
/**
@@ -50,7 +51,7 @@ function Main() {
return (
<>
<RouterProvider router={router} />
{/* <PlayerControls mediaPlayer={mediaPlayer} /> */}
<KeyboardListener mediaPlayer={mediaPlayer} />
<Toaster />
</>
);

View File

@@ -67,7 +67,7 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
<SidebarInset className="flex flex-col h-screen text-gray-800 bg-blue-50">
<div className="flex flex-1 overflow-hidden">
<SidePanel mediaPlayer={mediaPlayer} />
<main className="flex-1 p-6 overflow-y-auto">
<main className="flex-1 p-6 overflow-y-auto overflow-x-hidden">
<SidebarTrigger />
<div className="flex items-center justify-between mb-6">
{isRootPlaylist ? (
@@ -90,7 +90,7 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
)}
</div>
</div>
<ul className="flex flex-col">
<ul className="flex flex-col max-w-full">
{playlist?.tracks?.map(
(track) =>
track && (

View File

@@ -62,9 +62,7 @@ export function MusicTrackRow({
return (
<li
className={
"flex gap-1 hover:bg-slate-200 group py-2 px-2 cursor-pointer"
}
className={"flex gap-1 hover:bg-slate-200 group py-2 px-2 cursor-pointer"}
onClick={handleTrackClick}
>
<button

View File

@@ -31,7 +31,7 @@ export function MusicTrackTitleInput({
return (
<div
className="relative flex-grow"
className="relative flex-grow max-w-64"
onClick={(evt) => evt.stopPropagation()}
>
<input

View File

@@ -15,13 +15,6 @@ export function PlayerControls({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
resolve: { root: { activePlaylist: true } },
}).me?.root.activePlaylist;
useMediaEndListener(mediaPlayer.playNextTrack);
useKeyboardListener("Space", () => {
if (document.activeElement !== document.body) return;
playState.toggle();
});
const activeTrack = useCoState(MusicTrack, mediaPlayer.activeTrackId, {
resolve: { waveform: true },
});
@@ -73,3 +66,18 @@ export function PlayerControls({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
</footer>
);
}
export function KeyboardListener({
mediaPlayer,
}: { mediaPlayer: MediaPlayer }) {
const playState = usePlayState();
useMediaEndListener(mediaPlayer.playNextTrack);
useKeyboardListener("Space", () => {
if (document.activeElement !== document.body) return;
playState.toggle();
});
return null;
}

View File

@@ -1,5 +1,32 @@
# organization
## 0.0.111
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.110
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.109
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.108
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "organization",
"private": true,
"version": "0.0.108",
"version": "0.0.111",
"type": "module",
"scripts": {
"dev": "vite",
@@ -27,12 +27,12 @@
"@tailwindcss/forms": "^0.5.9",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,33 @@
# passkey-svelte
## 0.0.105
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [d14a069]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-svelte@0.14.21
## 0.0.104
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-svelte@0.14.20
## 0.0.103
### Patch Changes
- jazz-svelte@0.14.19
- jazz-tools@0.14.19
## 0.0.102
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "passkey-svelte",
"version": "0.0.102",
"version": "0.0.105",
"type": "module",
"private": true,
"scripts": {
@@ -25,11 +25,11 @@
"globals": "^15.11.0",
"prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.2.6",
"svelte": "^5.0.0",
"svelte": "^5.33.0",
"svelte-check": "^4.0.0",
"typescript": "5.6.2",
"typescript-eslint": "^8.0.0",
"vite": "6.0.11"
"vite": "6.3.5"
},
"dependencies": {
"jazz-svelte": "workspace:*",

View File

@@ -1,5 +1,32 @@
# minimal-auth-passkey
## 0.0.116
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.115
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.114
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.113
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "passkey",
"private": true,
"version": "0.0.113",
"version": "0.0.116",
"type": "module",
"scripts": {
"dev": "vite",
@@ -20,9 +20,9 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,32 @@
# passphrase
## 0.0.113
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.112
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.111
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.110
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "passphrase",
"private": true,
"version": "0.0.110",
"version": "0.0.113",
"type": "module",
"scripts": {
"dev": "vite",
@@ -20,9 +20,9 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,32 @@
# jazz-password-manager
## 0.0.137
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.136
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.135
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.134
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.134",
"version": "0.0.137",
"type": "module",
"scripts": {
"dev": "vite",
@@ -22,12 +22,12 @@
"devDependencies": {
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react-swc": "^3.3.2",
"@vitejs/plugin-react": "^4.5.1",
"@vitejs/plugin-react-swc": "^3.10.1",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,32 @@
# jazz-example-pets
## 0.0.235
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.234
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.233
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.232
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.232",
"version": "0.0.235",
"type": "module",
"scripts": {
"dev": "vite",
@@ -37,14 +37,14 @@
"@types/qrcode": "^1.5.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"@vitejs/plugin-react-swc": "^3.10.1",
"autoprefixer": "^10.4.20",
"is-ci": "^3.0.1",
"jazz-run": "workspace:*",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11",
"vite": "6.3.5",
"vite-plugin-top-level-await": "^1.4.4"
}
}

View File

@@ -1,5 +1,32 @@
# reactions
## 0.0.115
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.114
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.113
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.112
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "reactions",
"private": true,
"version": "0.0.112",
"version": "0.0.115",
"type": "module",
"scripts": {
"dev": "vite",
@@ -21,9 +21,9 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,5 +1,35 @@
# richtext-tiptap
## 0.1.28
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
- jazz-richtext-tiptap@0.14.21
## 0.1.27
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
- jazz-richtext-tiptap@0.14.20
## 0.1.26
### Patch Changes
- jazz-react@0.14.19
- jazz-richtext-tiptap@0.14.19
- jazz-tools@0.14.19
## 0.1.25
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "richtext-tiptap",
"private": true,
"version": "0.1.25",
"version": "0.1.28",
"type": "module",
"scripts": {
"dev": "vite",
@@ -33,13 +33,13 @@
"@playwright/test": "^1.50.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -44,7 +44,7 @@ export const JazzAccount = co
if (account.profile === undefined) {
const group = Group.create();
group.addMember("everyone", "reader"); // The profile info is visible to everyone
group.makePublic(); // The profile info is visible to everyone
account.profile = JazzProfile.create(
{

View File

@@ -1,5 +1,35 @@
# richtext
## 0.0.105
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
- jazz-richtext-prosemirror@0.14.21
## 0.0.104
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
- jazz-richtext-prosemirror@0.14.20
## 0.0.103
### Patch Changes
- jazz-react@0.14.19
- jazz-richtext-prosemirror@0.14.19
- jazz-tools@0.14.19
## 0.0.102
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "richtext",
"private": true,
"version": "0.0.102",
"version": "0.0.105",
"type": "module",
"scripts": {
"dev": "vite",
@@ -30,13 +30,13 @@
"@playwright/test": "^1.50.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -46,7 +46,7 @@ export const JazzAccount = co
if (account.profile === undefined) {
const group = Group.create();
group.addMember("everyone", "reader"); // The profile info is visible to everyone
group.makePublic(); // The profile info is visible to everyone
account.profile = JazzProfile.create(
{

View File

@@ -1,5 +1,35 @@
# todo-vue
## 0.0.117
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-browser@0.14.21
- jazz-vue@0.14.21
## 0.0.116
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-browser@0.14.20
- jazz-vue@0.14.20
## 0.0.115
### Patch Changes
- jazz-browser@0.14.19
- jazz-tools@0.14.19
- jazz-vue@0.14.19
## 0.0.114
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "todo-vue",
"version": "0.0.114",
"version": "0.0.117",
"private": true,
"type": "module",
"scripts": {
@@ -32,7 +32,7 @@
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11",
"vite": "6.3.5",
"vite-plugin-vue-devtools": "^7.4.6",
"vue-tsc": "^2.1.6"
}

View File

@@ -1,5 +1,32 @@
# jazz-example-todo
## 0.0.234
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-react@0.14.21
## 0.0.233
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-react@0.14.20
## 0.0.232
### Patch Changes
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.231
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.231",
"version": "0.0.234",
"type": "module",
"scripts": {
"dev": "vite",
@@ -33,11 +33,11 @@
"@types/qrcode": "^1.5.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"@vitejs/plugin-react-swc": "^3.10.1",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -1,4 +1,4 @@
import { co, z } from "jazz-tools";
import { CoPlainText, co, z } from "jazz-tools";
/** Walkthrough: Defining the data model with CoJSON
*
@@ -11,9 +11,30 @@ import { co, z } from "jazz-tools";
**/
/** An individual task which collaborators can tick or rename */
export const Task = co.map({
export const Task = co
.map({
done: z.boolean(),
text: co.plainText(),
version: z.literal(1),
})
.withMigration((task) => {
if (!task.version) {
// Cast to the v1 version
const task_v1 = task.castAs(Task_V1);
// Check if the task text field is a string or an id
// if it's a string migrate to plaintext
// We need to do this check because some tasks with plainText have been created before we added the version field
if (!task_v1.text.startsWith("co_z")) {
task.text = CoPlainText.create(task_v1.text, task._owner);
}
task.version = 1;
}
});
const Task_V1 = co.map({
done: z.boolean(),
text: co.plainText(),
text: z.string(),
});
/** Our top level object: a project with a title, referencing a list of tasks */

View File

@@ -51,6 +51,7 @@ export function ProjectTodoTable() {
{
done: false,
text: CoPlainText.create(text, project._owner),
version: 1,
},
project._owner,
);

View File

@@ -19,6 +19,7 @@ export function generateRandomProject(
faker.lorem.sentence({ min: 3, max: 8 }),
tasks._owner,
),
version: 1,
});
tasks.push(task);
}

View File

@@ -1,5 +1,35 @@
# version-history
## 0.0.113
### Patch Changes
- Updated dependencies [e7e505e]
- Updated dependencies [13b57aa]
- Updated dependencies [5662faa]
- Updated dependencies [2116a59]
- jazz-tools@0.14.21
- jazz-inspector@0.14.21
- jazz-react@0.14.21
## 0.0.112
### Patch Changes
- Updated dependencies [6f72419]
- Updated dependencies [04b20c2]
- jazz-tools@0.14.20
- jazz-inspector@0.14.20
- jazz-react@0.14.20
## 0.0.111
### Patch Changes
- jazz-inspector@0.14.19
- jazz-react@0.14.19
- jazz-tools@0.14.19
## 0.0.110
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "version-history",
"private": true,
"version": "0.0.110",
"version": "0.0.113",
"type": "module",
"scripts": {
"dev": "vite",
@@ -23,9 +23,9 @@
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",
"vite": "6.0.11"
"vite": "6.3.5"
}
}

View File

@@ -27,6 +27,7 @@ function App() {
),
estimate: 5,
status: "backlog",
createdAt: new Date(),
},
group,
);

View File

@@ -74,6 +74,8 @@ export function IssueVersionHistory({ id }: { id: string }) {
].sort((a, b) => (a.madeAt < b.madeAt ? -1 : a.madeAt > b.madeAt ? 1 : 0));
}, [issue?._edits]);
if (!issue) return;
return (
<>
<div className="flex flex-col text-sm gap-2">
@@ -98,6 +100,12 @@ export function IssueVersionHistory({ id }: { id: string }) {
<hr />
<DescriptionVersionHistory id={id} />
<hr />
<div>
<p>This issue was created at {issue.createdAt.toLocaleString()}</p>
</div>
</>
);
}

View File

@@ -22,6 +22,7 @@ export function ProjectComponent({ projectID }: { projectID: string }) {
description: CoPlainText.create("", project._owner),
estimate: 0,
status: "backlog",
createdAt: new Date(),
},
project._owner,
),

View File

@@ -10,6 +10,7 @@ export const Issue = co.map({
description: co.plainText(),
estimate: z.number(),
status: z.literal(["backlog", "in progress", "done"]),
createdAt: z.date(),
});
export const Project = co.map({

View File

@@ -34,5 +34,4 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts
typedoc
codeSamples

View File

@@ -20,6 +20,7 @@ export const team: Array<TeamMember> = [
github: "aeplay",
website: "http://anselm.io",
bluesky: "anselm.io",
linkedin: "anselm-eickhoff",
},
{
name: "Guido D'Orsi",
@@ -29,12 +30,13 @@ export const team: Array<TeamMember> = [
github: "gdorsi",
},
{
name: "Andrei Popa",
titles: ["Full-Stack Dev", "Infra"],
image: "andrei.jpeg",
location: "Bucharest, Romania ",
x: "elitepax",
github: "pax-k",
name: "Giordano Ricci",
titles: ["Full-Stack Dev", "Observability Expert"],
location: "Lisbon, Portugal ",
github: "Elfo404",
website: "https://giordanoricci.com",
linkedin: "giordanoricci",
image: "gio.jpg",
},
{
name: "Trisha Lim",
@@ -51,22 +53,13 @@ export const team: Array<TeamMember> = [
location: "Portsmouth, UK ",
github: "bensleveritt",
},
{
name: "Giordano Ricci",
titles: ["Full-Stack Dev", "DevOps"],
location: "Lisbon, Portugal ",
linkedin: "giordanoricci",
github: "Elfo404",
website: "https://giordanoricci.com",
image: "gio.jpg",
},
{
name: "Nikos Papadopoulos",
titles: ["Full-Stack Dev"],
location: "Farnham, UK",
github: "4rknova",
website: "https://www.4rknova.com",
linkedin: "nikpapas",
github: "4rknova",
image: "nikos.png",
},
{
@@ -74,8 +67,8 @@ export const team: Array<TeamMember> = [
titles: ["Full-Stack Dev", "Support Dev"],
location: "San Francisco, California, US",
github: "emmyoh",
linkedin: "emil-sayahi",
bluesky: "sayahi.bsky.social",
linkedin: "emil-sayahi",
image: "emil.jpg",
},
{
@@ -85,30 +78,23 @@ export const team: Array<TeamMember> = [
github: "mculotta120",
image: "meg.jpg",
},
{
name: "James Vickery",
location: "Birmingham, UK",
titles: ["Full-Stack Dev", "Support Dev"],
github: "jmsv",
bluesky: "jmsv.bsky.social",
image: "james.jpg",
},
{
name: "Stephanie Lemmeyer",
location: "Boston, Massachusetts, US",
titles: ["Lead DevOps"],
github: "slemmeyer",
linkedin: "stephanielemmeyer",
website: "https://stephanielemmeyer.me",
image: "stephanie.jpg",
},
{
name: "Nikita Voloboev",
location: "Barcelona, Spain",
titles: ["Full-Stack Dev"],
github: "nikitavoloboev",
x: "nikitavoloboev",
github: "nikitavoloboev",
website: "https://nikiv.dev",
image: "nikita.jpg",
},
{
name: "Sammii Kellow",
location: "London, UK",
titles: ["Design Engineer", "Marketing"],
x: "SammiiHaylock",
github: "sammii-hk",
website: "https://sammii.dev",
linkedin: "sammii",
image: "sammii.jpg",
},
];

View File

@@ -44,7 +44,6 @@
"autoprefixer": "^10",
"postcss": "^8",
"tailwindcss": "^3",
"typedoc": "^0.25.13",
"typescript": "^5.3.3"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

View File

@@ -34,7 +34,6 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts
typedoc
codeSamples
# Turborepo
.turbo

View File

@@ -1,29 +0,0 @@
import { PackageDocs } from "@/components/docs/packageDocs";
import { packages } from "@/content/packages";
import { notFound } from "next/navigation";
interface Props {
params: Promise<{ package: string }>;
}
export default async function Page({ params }: Props) {
const packageName = (await params).package;
if (!packages.map((p) => p.name).includes(packageName)) {
return notFound();
}
return <PackageDocs package={packageName} />;
}
export async function generateMetadata({ params }: Props) {
const packageName = (await params).package;
return {
title: `${packageName} - jazz`,
description: `API reference for ${packageName}.`,
};
}
export async function generateStaticParams() {
// TODO: ideally we check which files exist in ../../typedoc
return packages.map((pkg) => ({ package: pkg.name }));
}

View File

@@ -1,37 +0,0 @@
import { SideNavLayout } from "@/components/SideNavLayout";
import { ApiNav } from "@/components/docs/ApiNav";
import { JazzMobileNav } from "@/components/nav";
import { Prose } from "@garden-co/design-system/src/components/molecules/Prose";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<SideNavLayout
sideNav={<ApiNav />}
floatingNavSections={[
{
name: "API Ref",
content: <ApiNav />,
icon: "package",
},
]}
>
<Prose className="overflow-x-hidden lg:flex-1 pb-10 pt-[calc(61px+2.5rem)] md:pt-10">
{children}
</Prose>
<JazzMobileNav
sections={[
{
name: "API Ref",
content: <ApiNav />,
icon: "package",
},
]}
/>
</SideNavLayout>
);
}

View File

@@ -1,107 +0,0 @@
import { packages } from "@/content/packages";
import { Icon } from "@garden-co/design-system/src/components/atoms/Icon";
import { clsx } from "clsx";
import type { Metadata } from "next";
import Link from "next/link";
export const metadata: Metadata = {
title: "API reference",
openGraph: {
title: "API reference",
},
};
const CardHeading = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return (
<h2
className={clsx(
className,
"font-medium text-stone-950 dark:text-white text-lg transition-colors",
)}
>
{children}
</h2>
);
};
const CardBody = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return <p className={clsx(className, "text-sm")}>{children}</p>;
};
const Card = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return (
<div
className={clsx(
className,
"not-prose p-4 h-full rounded-xl flex flex-col gap-1.5 group lg:p-5",
)}
>
{children}
</div>
);
};
export default function Page() {
return (
<>
<h1>API Reference</h1>
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
{packages.map(({ name, description }) => (
<Link
className="not-prose block"
href={`/api-reference/${name}`}
key={name}
>
<Card className="border shadow-sm">
<Icon name="package" className="text-stone-500" />
<CardHeading className="group-hover:text-primary dark:group-hover:text-blue-600">
{name}
</CardHeading>
<CardBody>{description}</CardBody>
</Card>
</Link>
))}
<Card className="bg-stone-50 dark:bg-stone-925">
<Icon name="help" size="md" className="text-stone-500 " />
<CardHeading>
Can&apos;t find what you&apos;re looking for?
</CardHeading>
<CardBody>
Get help from our{" "}
<Link href="https://discord.gg/utDMjHYg42" className="underline">
Discord
</Link>
, or open an issue on{" "}
<Link
href="https://github.com/garden-co/jazz"
className="underline"
>
GitHub
</Link>
.
</CardBody>
</Card>
</div>
</>
);
}

View File

@@ -1,78 +0,0 @@
import { SideNav, SideNavBody, SideNavHeader } from "@/components/SideNav";
import { SideNavItem } from "@/components/SideNavItem";
import { packages } from "@/content/packages";
import { Icon } from "@garden-co/design-system/src/components/atoms/Icon";
import Link from "next/link";
import { requestProject } from "./requestProject";
export function ApiNav({ className }: { className?: string }) {
return (
<SideNav className={className}>
<SideNavBody>
<SideNavHeader className="mb-5" href="/api-reference">
API Reference
</SideNavHeader>
<ul className="space-y-5">
{packages.map(({ name }) => (
<li key={name}>
<PackageNavItem package={name} />
</li>
))}
</ul>
</SideNavBody>
</SideNav>
);
}
export async function PackageNavItem({
package: packageName,
}: {
package: string;
}) {
let project = await requestProject(packageName as any);
return (
<>
<SideNavItem
className="mb-1 flex gap-2 items-center"
href={`/api-reference/${packageName}`}
>
<Icon name="package" size="xs" />
{packageName}
</SideNavItem>
{project.categories?.map((category) => {
return (
<details
key={category.title}
open={category.title !== "Other"}
className="group ml-1.5 border-l"
>
<summary className="pl-[13px] py-1 cursor-pointer flex gap-2 items-center justify-between hover:text-stone-800 dark:hover:text-stone-200 [&::-webkit-details-marker]:hidden">
{category.title}
<Icon
name="chevronRight"
size="sm"
className="text-stone-300 group-open:rotate-90 transition-transform dark:text-stone-800"
/>
</summary>
<div className="pl-6">
{category.children.map(
(child, i, children) =>
(i == 0 || child.name !== children[i - 1]!.name) && (
<Link
key={child.id}
className="block py-0.5 text-ellipsis overflow-hidden font-mono hover:text-stone-800 dark:hover:text-stone-200"
href={`/api-reference/${packageName}#${child.name}`}
>
{child.name}
</Link>
),
)}
</div>
</details>
);
})}
</>
);
}

View File

@@ -1,425 +0,0 @@
import { Icon } from "@garden-co/design-system/src/components/atoms/Icon";
import { Fragment } from "react";
import {
CommentDisplayPart,
DeclarationReflection,
ReflectionKind,
SignatureReflection,
SomeType,
TypeContext,
TypeParameterReflection,
} from "typedoc";
import { requestProject } from "./requestProject";
import {
ClassOrInterface,
DocComment,
FnDecl,
Highlight,
PropCategory,
PropDecl,
} from "./tags";
export async function PackageDocs({
package: packageName,
}: {
package: string;
}) {
let project = await requestProject(packageName as any);
// console.dir(project, {depth: 10});
return (
<>
<h2 className="flex items-center gap-2">
<code>{packageName}</code> <Icon name="package" size="md" />
</h2>
{project.categories?.map((category) => {
return (
<section key={category.title}>
<h2>{category.title}</h2>
{category.children.map(
(child) =>
// Ability to link external documents has been added. Turning it off for now
// https://typedoc.org/documents/External_Documents.html
child.variant !== "document" && (
<RenderPackageChild
child={child}
key={child.id}
inPackage={packageName}
/>
),
)}
</section>
);
})}
</>
);
}
function RenderPackageChild({
child,
inPackage,
}: {
child: DeclarationReflection;
inPackage: string;
}) {
if (
child.kind === ReflectionKind.Class ||
child.kind === ReflectionKind.Interface
) {
return (
<RenderClassOrInterface classOrInterface={child} inPackage={inPackage} />
);
} else if (child.kind === ReflectionKind.TypeAlias) {
return <RenderTypeAlias inPackage={inPackage} child={child} />;
} else if (child.kind === ReflectionKind.Function) {
return child.getAllSignatures().map((signature, i) => {
const paramTypes = printParamsWithTypes(signature);
return (
<div
key={i}
id={child.name}
className="not-prose mt-4 p-3 rounded bg-stone-50 dark:bg-stone-925"
>
{
<Highlight hide={[0, 2]}>
{`function \n${printSimpleSignature(child, signature) + ":"}\n {}`}
</Highlight>
}{" "}
<span className="opacity-75 text-xs pl-1">
<Highlight>{printType(signature.type)}</Highlight>
</span>
<div className="ml-4 mt-0 text-xs opacity-75 flex">
{paramTypes.length > 0 && (
<div>
<Highlight
hide={[0, 1 + paramTypes.length]}
>{`function fn(...args: [\n${paramTypes.join(
",\n",
)}\n]) {}`}</Highlight>
</div>
)}
</div>
</div>
);
});
} else {
return (
<h3 id={child.name}>
{child.name} {child.type?.type}
</h3>
);
}
}
function RenderTypeAlias({
inPackage,
child,
}: {
inPackage: string;
child: DeclarationReflection;
}) {
const typeParameters = child.typeParameters?.map(
(tParam) =>
tParam.name + (tParam.type ? ` extends ${printType(tParam.type)}` : ""),
);
return (
<div className="mt-4">
<h3 className="not-prose" id={child.name}>
<Highlight>{`type ${child.name}`}</Highlight>
</h3>
<p className="not-prose text-sm ml-4">
<Highlight>{`type ${child.name}${typeParameters?.length && `<${typeParameters?.join(", ")}>`} = ${printType(
child.type,
)}`}</Highlight>
</p>
<div className="ml-4 mt-2 flex-[3]">
<DocComment>
{child.comment
? renderSummary(child.comment.summary)
: "⚠️ undocumented"}
</DocComment>
</div>
</div>
);
}
function RenderClassOrInterface({
inPackage,
classOrInterface: classOrInterface,
}: {
inPackage: string;
classOrInterface: DeclarationReflection;
}) {
const commentSummary = classOrInterface.comment?.summary;
const typeParamsWithConstraints = printTypeParamsWithConstraints(
classOrInterface.typeParameters,
);
return (
<ClassOrInterface
inPackage={inPackage}
name={classOrInterface.name}
doc={renderSummary(commentSummary)}
isInterface={classOrInterface.kind === ReflectionKind.Interface}
typeParameters={
classOrInterface.typeParameters?.length
? "<" +
classOrInterface.typeParameters
.map((tParam) => tParam.name)
.join(", ") +
">"
: ""
}
>
{typeParamsWithConstraints.length > 0 && (
<div className="text-sm -mt-4">
<Highlight
hide={[0, 1 + typeParamsWithConstraints.length]}
>{`class Thing<\n${typeParamsWithConstraints.join(
",\n",
)}\n]> {}`}</Highlight>
</div>
)}
{classOrInterface.categories?.map((category) => (
<div className="flex flex-col mt-6 first:mt-0" key={category.title}>
<PropCategory
name={category.title}
description={renderSummary(
category.description?.filter(
(p) => p.kind !== "code" || !p.text.startsWith("```"),
),
)}
example={renderSummary(
category.description?.filter(
(p) => p.kind === "code" && p.text.startsWith("```"),
),
)}
/>
{category.children.map(
(prop) =>
prop.variant !== "document" && (
<RenderProp
prop={prop}
klass={classOrInterface}
key={prop.id}
/>
),
)}
</div>
))}
</ClassOrInterface>
);
}
function renderSummary(commentSummary: CommentDisplayPart[] | undefined) {
return commentSummary?.map((part, idx) =>
part.kind === "text" ? (
<span key={idx}>
{part.text.split("\n").map((line, i, lines) => (
<Fragment key={i}>
{line}
{i !== lines.length - 1 && <br />}
</Fragment>
))}
</span>
) : part.kind === "inline-tag" ? (
<code key={idx}>
{part.tag} {part.text}
</code>
) : part.text.startsWith("```") ? (
<pre key={idx} className="text-xs sm:text-sm">
<Highlight>{part.text.split("\n").slice(1, -1).join("\n")}</Highlight>
</pre>
) : (
<Highlight className="whitespace-nowrap" key={idx}>
{part.text.slice(1, -1)}
</Highlight>
),
);
}
function RenderProp({
prop,
klass,
}: {
prop: DeclarationReflection;
klass: DeclarationReflection;
}) {
const propOrGetSig = prop.getSignature ? prop.getSignature : prop;
return prop.kind & ReflectionKind.FunctionOrMethod ? (
prop
.getAllSignatures()
.map((signature) => (
<FnDecl
key={signature.id}
signature={printSimplePropSignature(prop, klass, signature)}
typeParams={printTypeParamsWithConstraints(signature.typeParameters)}
paramTypes={printParamsWithTypes(signature)}
returnType={printType(signature.type)}
doc={renderSummary(signature.comment?.summary)}
example={renderSummary(
signature.comment?.getTag("@example")?.content,
)}
/>
))
) : (
<PropDecl
name={
(prop.flags.isStatic ? klass.name : "") +
(prop.name.startsWith("[") ? "" : ".") +
prop.name
}
type={printType(propOrGetSig.type)}
doc={propOrGetSig.comment && renderSummary(propOrGetSig.comment.summary)}
example={renderSummary(propOrGetSig.comment?.getTag("@example")?.content)}
/>
);
}
function printSimplePropSignature(
prop: DeclarationReflection,
klass: DeclarationReflection,
signature: SignatureReflection,
): string {
return (
`${prop.flags.isStatic ? klass.name : ""}.` +
printSimpleSignature(prop, signature)
);
}
function printSimpleSignature(
item: DeclarationReflection,
signature: SignatureReflection,
) {
return `${item.name}${
signature.typeParameters?.length
? "<" +
signature.typeParameters.map((tParam) => tParam.name).join(", ") +
">"
: ""
}(${printParams(signature)?.join(", ")})`;
}
function printParams(signature: SignatureReflection) {
return (
signature.parameters?.flatMap((param) =>
param.name === "this"
? []
: [
param.name === "__namedParameters" &&
param.type?.type === "reflection"
? "{ " +
param.type.declaration.children
?.map(
(child) => child.name + (child.flags.isOptional ? "?" : ""),
)
.join(", ") +
" }"
: param.name + (param.defaultValue ? "?" : ""),
],
) || []
);
}
function printParamsWithTypes(signature: SignatureReflection) {
return (
signature.parameters?.map(
(param) =>
(param.name === "__namedParameters"
? ""
: param.name + (param.defaultValue ? "?" : "") + ": ") +
printType(param.type),
) || []
);
}
function printTypeParamsWithConstraints(
typeParams: TypeParameterReflection[] | undefined,
): string[] {
return (
typeParams?.flatMap((tParam) =>
tParam.type ? [`${tParam.name} extends ${printType(tParam.type)}`] : [],
) || []
);
}
function printType(type: SomeType | undefined): string {
if (!type) return "NO TYPE";
if (type.type === "reflection") {
if (type.declaration.kind === ReflectionKind.TypeLiteral) {
if (type.declaration.signatures?.length) {
return (
type.declaration.signatures
?.map(
(sig) =>
`(${printParamsWithTypes(sig).join(
", ",
)}) => ${printType(sig.type)}`,
)
.join(" | ") || ""
);
} else {
return (
"{ " +
type.declaration.children
?.map((child) => `${child.name}: ${printType(child.type)}`)
.join(", ") +
" }"
);
}
}
return "TODO reflection type " + type.declaration.kind;
} else if (type.type === "reference") {
return (
type.name +
(type.typeArguments?.length
? "<" + type.typeArguments.map(printType).join(", ") + ">"
: "")
);
} else if (type.type === "intersection") {
return (
type.types
?.map((part) =>
part.needsParenthesis(TypeContext["intersectionElement"])
? `(${printType(part)})`
: printType(part),
)
.join(" & ") || "NO TYPES"
);
} else if (type.type === "union") {
return (
type.types
.sort((a, b) => (a.type === "intrinsic" ? 1 : -1))
?.map((part) =>
part.needsParenthesis(TypeContext["unionElement"])
? `(${printType(part)})`
: printType(part),
)
.join(" | ") || "NO TYPES"
);
} else if (type.type === "tuple") {
return `[${type.elements.map(printType).join(", ")}]`;
} else if (type.type === "array") {
if (type.needsParenthesis()) {
return `(${printType(type.elementType)})[]`;
} else {
return printType(type.elementType) + "[]";
}
} else if (type.type === "mapped") {
return `{[${type.parameter} in ${printType(
type.parameterType,
)}]: ${printType(type.templateType)}}`;
} else if (type.type === "indexedAccess") {
return `${printType(type.objectType)}[${printType(type.indexType)}]`;
} else if (type.type === "intrinsic") {
return type.name;
} else if (type.type === "predicate") {
return `${type.name} is ${printType(type.targetType)}`;
} else if (type.type === "query") {
return printType(type.queryType);
} else if (type.type === "literal") {
return JSON.stringify(type.value);
} else {
return "TODO type " + type.type;
}
}

View File

@@ -1,31 +0,0 @@
import {
Deserializer,
FileRegistry,
JSONOutput,
ProjectReflection,
} from "typedoc";
import JazzBrowserMediaImagesDocs from "../../typedoc/jazz-browser-media-images.json";
import JazzBrowserDocs from "../../typedoc/jazz-browser.json";
import JazzNodejsDocs from "../../typedoc/jazz-nodejs.json";
import JazzReactDocs from "../../typedoc/jazz-react.json";
import JazzToolsDocs from "../../typedoc/jazz-tools.json";
const docs = {
"jazz-tools": JazzToolsDocs as unknown as JSONOutput.ProjectReflection,
"jazz-react": JazzReactDocs as unknown as JSONOutput.ProjectReflection,
"jazz-browser": JazzBrowserDocs as unknown as JSONOutput.ProjectReflection,
"jazz-browser-media-images":
JazzBrowserMediaImagesDocs as unknown as JSONOutput.ProjectReflection,
"jazz-nodejs": JazzNodejsDocs as unknown as JSONOutput.ProjectReflection,
};
export async function requestProject(
packageName: keyof typeof docs,
): Promise<ProjectReflection> {
const deserializer = new Deserializer({} as any);
return deserializer.reviveProject(packageName, docs[packageName], {
projectRoot: "/",
registry: new FileRegistry(),
});
}

View File

@@ -1,7 +1,7 @@
```tsx
const group = Group.create();
group.addMember(Alice, "writer");
group.addMember("everyone", "reader");
group.makePublic();
Message.create({ text: "..." }, group);
```

View File

@@ -13,7 +13,7 @@ export function ExpoLogo(props: SVGProps<SVGSVGElement>) {
>
<path
d="M11.39 8.269c.19-.277.397-.312.565-.312.168 0 .447.035.637.312 1.49 2.03 3.95 6.075 5.765 9.06 1.184 1.945 2.093 3.44 2.28 3.63.7.714 1.66.269 2.218-.541.549-.797.701-1.357.701-1.954 0-.407-7.958-15.087-8.759-16.309C14.027.98 13.775.683 12.457.683h-.988c-1.315 0-1.505.297-2.276 1.472C8.392 3.377.433 18.057.433 18.463c0 .598.153 1.158.703 1.955.558.81 1.518 1.255 2.218.54.186-.19 1.095-1.684 2.279-3.63 1.815-2.984 4.267-7.029 5.758-9.06z"
fill="#000"
className="fill-black dark:fill-white"
/>
</svg>
);

View File

@@ -0,0 +1,246 @@
import { CodeGroup } from "@/components/forMdx";
export const metadata = { title: "History Patterns" };
# History Patterns
Jazz's automatic history tracking enables powerful patterns for building collaborative features. Here's how to implement common history-based functionality.
## Audit Logs
Build a complete audit trail showing all changes to your data:
<CodeGroup>
```ts twoslash
import { co, z } from 'jazz-tools'
import { createJazzTestAccount } from 'jazz-tools/testing'
const me = await createJazzTestAccount();
const Task = co.map({
title: z.string(),
status: z.literal(["todo", "in-progress", "completed"]),
});
type Task = co.loaded<typeof Task>;
const task = Task.create({ title: "New task", status: "todo" }, { owner: me });
// ---cut---
function getAuditLog(task: Task) {
const changes = [];
// Collect edits for all fields
const fields = Object.keys(task);
for (const field of fields) {
const editField = field as keyof typeof task._edits;
if (!task._edits[editField]) continue;
for (const edit of task._edits[editField].all) {
changes.push({
field,
value: edit.value,
by: edit.by,
at: edit.madeAt,
});
}
}
// Sort by timestamp (newest first)
return changes.sort((a, b) => b.at.getTime() - a.at.getTime());
}
// Use it to show change history
const auditLog = getAuditLog(task);
auditLog.forEach((entry) => {
const when = entry.at.toLocaleString();
const who = entry.by?.profile?.name;
const what = entry.field;
const value = entry.value;
console.log(`${when} - ${who} changed ${what} to "${value}"`);
// 22/05/2025, 12:00:00 - Alice changed title to "New task"
});
```
</CodeGroup>
## Activity Feeds
Show recent activity across your application:
<CodeGroup>
```ts twoslash
import { co, z } from 'jazz-tools'
import { createJazzTestAccount } from 'jazz-tools/testing'
const me = await createJazzTestAccount();
const Project = co.map({
name: z.string(),
status: z.literal(["todo", "in-progress", "completed"]),
});
type Project = co.loaded<typeof Project>;
const project = Project.create({ name: "New project", status: "todo" }, { owner: me });
const myProjects = [project];
// ---cut---
function getRecentActivity(projects: Project[], since: Date) {
const activity = [];
for (const project of projects) {
// Get all fields that might have edits
const fields = Object.keys(project);
// Check each field for edit history
for (const field of fields) {
const editField = field as keyof typeof project._edits;
// Skip if no edits exist for this field
if (!project._edits[editField]) continue;
for (const edit of project._edits[editField].all) {
// Only include edits made after the 'since' date
if (edit.madeAt > since) {
activity.push({
project: project.name,
field,
value: edit.value,
by: edit.by,
at: edit.madeAt
});
}
}
}
}
return activity.sort((a, b) => b.at.getTime() - a.at.getTime());
}
// Show activity from the last hour
const hourAgo = new Date(Date.now() - 60 * 60 * 1000);
const recentActivity = getRecentActivity(myProjects, hourAgo);
// [{
// project: "New project",
// field: "name",
// value: "New project",
// by: Account,
// at: Date
// }]
```
</CodeGroup>
## Change Indicators
Show when something was last updated:
<CodeGroup>
```ts twoslash
import { co, z } from 'jazz-tools'
import { createJazzTestAccount } from 'jazz-tools/testing'
const me = await createJazzTestAccount();
const Task = co.map({
title: z.string(),
status: z.literal(["todo", "in-progress", "completed"]),
});
type Task = co.loaded<typeof Task>;
const task = Task.create({ title: "New task", status: "todo" }, { owner: me });
// ---cut---
function getLastUpdated(task: Task) {
// Find the most recent edit across all fields
let lastEdit: any = null;
for (const field of Object.keys(task)) {
const editField = field as keyof typeof task._edits;
// Skip if no edits exist for this field
if (!task._edits[editField]) continue;
const fieldEdit = task._edits[editField];
if (fieldEdit && (!lastEdit || fieldEdit.madeAt > lastEdit.madeAt)) {
lastEdit = fieldEdit;
}
}
if (!lastEdit) return null;
return {
updatedBy: lastEdit.by?.profile?.name,
updatedAt: lastEdit.madeAt,
message: `Last updated by ${lastEdit.by?.profile?.name} at ${lastEdit.madeAt.toLocaleString()}`
};
}
const lastUpdated = getLastUpdated(task);
console.log(lastUpdated?.message);
// "Last updated by Alice at 22/05/2025, 12:00:00"
```
</CodeGroup>
## Finding Specific Changes
Query history for specific events:
<CodeGroup>
```ts twoslash
import { co, z } from 'jazz-tools'
import { createJazzTestAccount } from 'jazz-tools/testing'
const me = await createJazzTestAccount();
const Task = co.map({
title: z.string(),
status: z.literal(["todo", "in-progress", "completed"]),
});
type Task = co.loaded<typeof Task>;
const task = Task.create({ title: "New task", status: "todo" }, { owner: me });
task.status = "completed";
task.status = "in-progress";
task.status = "completed";
// ---cut---
// Find when a task was completed
function findCompletionTime(task: Task): Date | null {
if (!task._edits.status) return null;
// find() returns the FIRST completion time
// If status toggles (completed → in-progress → completed),
// this gives you the earliest completion, not the latest
const completionEdit = task._edits.status.all.find(
edit => edit.value === "completed"
);
return completionEdit?.madeAt || null;
}
// To get the LATEST completion time instead reverse the array, then find:
function findLatestCompletionTime(task: Task): Date | null {
if (!task._edits.status) return null;
// Reverse and find (stops at first match)
const latestCompletionEdit = task._edits.status.all
.slice() // Create copy to avoid mutating original
.reverse()
.find(edit => edit.value === "completed");
return latestCompletionEdit?.madeAt || null;
}
console.log(findCompletionTime(task)); // First completion
console.log(findLatestCompletionTime(task)); // Most recent completion
// Find who made a specific change
function findWhoChanged(task: Task, field: string, value: any) {
const edits = task._edits[field as keyof typeof task._edits];
if (!edits) return null;
const matchingEdit = edits.all.find(edit => edit.value === value);
return matchingEdit?.by || null;
}
const account = findWhoChanged(task, "status", "completed");
console.log(account?.profile?.name);
// Alice
```
</CodeGroup>
## Further Reading
- [History](/docs/using-covalues/history) - Complete reference for the history API
- [Subscription & Loading](/docs/using-covalues/subscription-and-loading) - Ensure CoValues are loaded before accessing history

View File

@@ -213,9 +213,9 @@ export const docNavigationItems = [
done: 80,
},
{
name: "History & time travel",
name: "History",
href: "/docs/using-covalues/history",
done: 0,
done: 100,
},
],
},
@@ -296,6 +296,11 @@ export const docNavigationItems = [
href: "/docs/design-patterns/organization",
done: 80,
},
{
name: "History Patterns",
href: "/docs/design-patterns/history-patterns",
done: 100,
},
],
},
{

View File

@@ -8,8 +8,7 @@ import { ContentByFramework, CodeGroup } from '@/components/forMdx'
## Public sharing
You can share CoValues publicly by setting the `owner` to a `Group`, and granting
access to "everyone".
You can share CoValues publicly by setting the `owner` to a `Group`, and granting access to "everyone".
<CodeGroup>
```ts twoslash
@@ -20,6 +19,19 @@ group.addMember("everyone", "writer");
```
</CodeGroup>
You can also use `makePublic(role)` alias to grant access to everyone with a specific role (defaults to `reader`).
<CodeGroup>
```ts twoslash
import { Group } from "jazz-tools";
// ---cut---
const group = Group.create();
group.addMember("everyone", "writer"); // [!code --]
group.makePublic("writer"); // [!code ++]
// group.makePublic(); // Defaults to "reader" access
```
</CodeGroup>
This is done in the [chat example](https://github.com/garden-co/jazz/tree/main/examples/chat) where anyone can join the chat, and send messages.
You can also [add members by Account ID](/docs/groups/intro#adding-group-members-by-id).

View File

@@ -209,7 +209,7 @@ export const MyAppAccount = co.account({
if (account.profile === undefined) {
const profileGroup = Group.create();
// Unlike the root, we want the profile to be publicly readable.
profileGroup.addMember("everyone", "reader");
profileGroup.makePublic();
account.profile = MyAppProfile.create({
name: creationProps?.name ?? "New user",

View File

@@ -1,5 +1,5 @@
export const metadata = {
description: "CoValues are the core abstraction of Jazz. They're your bread-and-butter datastructures that you use to represent everything in your app."
description: "CoValues are the core abstraction of Jazz. They're your bread-and-butter datastructures that you use to represent everything in your app.",
};
import { CodeGroup, ComingSoon } from "@/components/forMdx";
@@ -23,6 +23,7 @@ CoValues model JSON with CoMaps and CoLists, but also offer CoFeeds for simple p
Fundamentally, CoValues are as dynamic and flexible as JSON, but in Jazz you use them by defining fixed schemas to describe the shape of data in your app.
This helps correctness and development speed, but is particularly important...
- when you evolve your app and need migrations
- when different clients and server workers collaborate on CoValues and need to make compatible changes
@@ -76,6 +77,7 @@ const project = TodoProject.create(
Group.create()
);
```
</CodeGroup>
## Types of CoValues
@@ -96,6 +98,7 @@ const Task = co.map({
completed: z.boolean(),
});
```
</CodeGroup>
Or record-like CoMaps (key-value pairs, where keys are always `string`):
@@ -112,6 +115,7 @@ const ColorToHex = co.record(z.string(), z.string());
const ColorToFruit = co.record(z.string(), Fruit);
```
</CodeGroup>
@@ -137,6 +141,7 @@ const Task = co.map({
const ListOfColors = co.list(z.string());
const ListOfTasks = co.list(Task);
```
</CodeGroup>
See the corresponding sections for [creating](/docs/using-covalues/colists#creating-colists),
@@ -207,7 +212,7 @@ import { co, z } from "jazz-tools";
const ButtonWidget = co.map({
type: z.literal("button"),
label: z.string(),
});
});
const SliderWidget = co.map({
type: z.literal("slider"),
@@ -215,8 +220,9 @@ const SliderWidget = co.map({
max: z.number(),
});
const WidgetUnion = z.discriminatedUnion([ButtonWidget, SliderWidget]);
const WidgetUnion = z.discriminatedUnion("type", [ButtonWidget, SliderWidget]);
```
</CodeGroup>
See the corresponding sections for [creating](/docs/using-covalues/schemaunions#creating-schemaunions),
@@ -246,15 +252,15 @@ export const ListOfColors = co.list(z.string());
Here's a quick overview of the primitive types you can use:
<CodeGroup>
```ts twoslash
import { z } from "jazz-tools";
// ---cut---
z.string(); // For simple strings
z.number(); // For numbers
```ts twoslash
import {z} from "jazz-tools";
// ---cut---
z.string(); // For simple strings
z.number(); // For numbers
z.boolean(); // For booleans
z.null(); // For null
z.date(); // For dates
z.literal(["waiting", "ready"]); // For enums
z.null(); // For null
z.date(); // For dates
z.literal(["waiting", "ready"]); // For enums
```
</CodeGroup>
@@ -311,6 +317,7 @@ const Company = co.map({
members: ListOfPeople,
});
```
</CodeGroup>
#### Optional References
@@ -363,6 +370,7 @@ const Person = co.map({
const ListOfPeople = co.list(Person);
```
</CodeGroup>
Note: similarly, if you use modifiers like `z.optional()` you'll need to help TypeScript along:
@@ -378,6 +386,7 @@ const Person = co.map({
}
});
```
</CodeGroup>
### Helper methods
@@ -417,3 +426,4 @@ const fullName = getPersonFullName(person);
const age = getPersonAgeAsOf(person, new Date());
```
</CodeGroup>
```

View File

@@ -306,6 +306,88 @@ project.coordinator = undefined; // Remove the reference
```
</CodeGroup>
## Running migrations on CoMaps
Migrations are functions that run when a CoMap is loaded, allowing you to update existing data to match new schema versions. Use them when you need to modify the structure of CoMaps that already exist in your app. Unlike [Account migrations](/docs/schemas/accounts-and-migrations#when-migrations-run), CoMap migrations are not run when a CoMap is created.
**Note:** Migrations are run synchronously and cannot be run asynchronously.
Here's an example of a migration that adds the `priority` field to the `Task` CoMap:
<CodeGroup>
```ts twoslash
import { co, z } from "jazz-tools";
// ---cut---
const Task = co
.map({
done: z.boolean(),
text: co.plainText(),
version: z.literal([1, 2]),
priority: z.enum(["low", "medium", "high"]), // new field
})
.withMigration((task) => {
if (task.version === 1) {
task.priority = "medium";
// Upgrade the version so the migration won't run again
task.version = 2;
}
});
```
</CodeGroup>
### Migration best practices
Design your schema changes to be compatible with existing data:
- **Add, don't change:** Only add new fields; avoid renaming or changing types of existing fields
- **Make new fields optional:** This prevents errors when loading older data
- **Use version fields:** Track schema versions to run migrations only when needed
### Migration & reader permissions
Migrations need write access to modify CoMaps. If some users only have read permissions, they can't run migrations on those CoMaps.
**Forward-compatible schemas** (where new fields are optional) handle this gracefully - users can still use the app even if migrations haven't run.
**Non-compatible changes** require handling both schema versions in your app code using discriminated unions.
When you can't guarantee all users can run migrations, handle multiple schema versions explicitly:
<CodeGroup>
```ts twoslash
import { co, z } from "jazz-tools";
// ---cut---
const TaskV1 = co.map({
version: z.literal(1),
done: z.boolean(),
text: z.string(),
});
const TaskV2 = co.map({
// We need to be more strict about the version to make the
// discriminated union work
version: z.literal(2),
done: z.boolean(),
text: z.string(),
priority: z.enum(["low", "medium", "high"]),
}).withMigration((task) => {
// @ts-expect-error - check if we need to run the migration
if (task.version === 1) {
task.version = 2;
task.priority = "medium";
}
});
// Export the discriminated union; because some users might
// not be able to run the migration
export const Task = z.discriminatedUnion("version", [
TaskV1,
TaskV2,
]);
```
</CodeGroup>
## Best Practices
### Structuring Data

View File

@@ -1,267 +0,0 @@
import { CodeGroup } from "@/components/forMdx";
# History & time-travel
One of Jazz's most powerful features is that every CoValue automatically tracks its complete edit history. This means you can see who changed what and when, examine the state of your data at any point in time, and build features like audit logs, activity feeds, and undo/redo functionality. This page explores how to access and work with the rich metadata that comes with every CoValue.
## Understanding Edit History
Every CoValue in Jazz maintains a full history of all changes made to it. This edit history is accessible through two main APIs:
`CoValue._edits` provides a structured, field-by-field view of a CoValue's edit history. It organizes edits by property name and makes them easily accessible. For each field:
- `_edits.fieldName` gives you the most recent edit
- `_edits.fieldName.all` provides all historical edits as an array
- `_edits.fieldName.madeAt` gives you the timestamp of the last edit
- Each edit contains the value, who made the change, and when it happened
`CoValue._raw` gives you access to the internal state and lower-level operations on a CoValue. As this is an internal API, it should be used with caution. If you find yourself using `_raw`, consider letting us know so we can consider adding a public API for your use case.
## Working with Edit History Metadata
CoValues track who made each change and when. Every edit has metadata attached to it, including the author, timestamp, value, and transaction ID. This metadata enables you to build powerful audit and history features without having to implement your own tracking system.
<CodeGroup>
```ts
class Task extends CoMap {
title = coField.string;
description = coField.string;
status = coField.literal("todo", "in-progress", "completed");
priority = coField.literal("low", "medium", "high");
subtasks = coField.optional.ref(ListOfTasks);
}
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
const task = Task.create({
title: "Plant spring vegetables",
description: "Plant peas, carrots, and lettuce in the south garden bed",
status: "todo",
priority: "medium",
});
// Change the status
task.status = "in-progress";
// Get the latest edit for a field
console.log("Latest edit:", task._edits.status);
// { value: "in-progress", by: Account, madeAt: Date, ... }
// Get when a field was last edited (timestamp)
const lastEditTime = task._edits.status.madeAt;
console.log(`Status was last changed at: ${lastEditTime?.toLocaleString()}`);
// Get the full edit history for a field
for (const edit of task._edits.status.all) {
console.log({
author: edit.by, // Account that made the change
timestamp: edit.madeAt, // When the change happened
value: edit.value, // Value of the change
});
}
```
</CodeGroup>
### Common Patterns
With knowledge of the edit history, you can build all sorts of useful features that enhance your application's user experience and administrative capabilities. Here are some common patterns that leverage CoValue metadata.
#### Audit Log
Getting all the changes to a CoValue in order allows you to build an audit log. This is especially useful for tracking important changes in collaborative environments or for compliance purposes:
<CodeGroup>
```ts
function getAuditLog(task: Task) {
const changes = [];
for (const field of Object.keys(task)) {
// Check if the field has edits to avoid accessing non-existent properties
if (task._edits[field as keyof typeof task._edits]) {
for (const edit of task._edits[field as keyof typeof task._edits].all) {
changes.push({
field,
...edit,
timestamp: edit.madeAt,
at: edit.madeAt,
by: edit.by,
});
}
}
}
// Sort by timestamp
return changes.sort((a, b) => b.at.getTime() - a.at.getTime());
}
// Example usage
const auditLog = getAuditLog(task);
auditLog.forEach((entry) => {
console.log(
`${entry.timestamp} - ${entry.field} changed to "${entry.value}" by ${entry.by?.id}`,
);
});
```
</CodeGroup>
#### Activity Feeds
Activity feeds are a great way to see recent changes to a CoValue, helping users understand what's happening in a collaborative workspace. They can show who did what and when, creating transparency in team environments:
<CodeGroup>
```ts
function getRecentActivity(project: Project) {
const activity = [];
const hourAgo = new Date(Date.now() - 3600000);
for (const field of Object.keys(project)) {
// Skip if the field doesn't have edits
if (!project._edits[field as keyof typeof project._edits]) continue;
for (const edit of project._edits[field as keyof typeof project._edits].all) {
if (edit.madeAt > hourAgo) {
activity.push({
field,
value: edit.value,
by: edit.by,
at: edit.madeAt
});
}
}
}
return activity.sort((a, b) => b.at.getTime() - a.at.getTime());
}
// Example usage
const recentActivity = getRecentActivity(gardenProject);
console.log("Recent Garden Activity:");
recentActivity.forEach(activity => {
console.log(`${activity.at.toLocaleString()} - ${activity.field} updated by ${activity.by?.id}`);
});
```
</CodeGroup>
## Edit History & Time Travel
CoValues track their entire history of changes, creating a timeline you can explore. You can see who changed what and when, or even view past states of the data. This capability enables powerful debugging tools and user-facing features like history browsing and restoration of previous versions:
<CodeGroup>
```ts
class Task extends CoMap {
title = coField.string;
description = coField.string;
status = coField.literal("todo", "in-progress", "completed");
priority = coField.literal("low", "medium", "high");
}
// Create a new task
const task = Task.create({
title: "Plant spring vegetables",
description: "Plant peas, carrots, and lettuce in the south garden bed",
status: "todo",
priority: "medium",
});
// Make some changes
task.status = "in-progress";
task.priority = "high";
// See all edits for a field
for (const edit of task._edits.status.all) {
console.log(
`${edit.madeAt.toISOString()}: Status changed to "${edit.value}" by ${edit.by?.id}`,
);
}
// Get the initial value
const initialStatus = task._edits.status.all[0]?.value;
console.log(`Original status: ${initialStatus}`);
// Get a specific edit by index
const previousEdit = task._edits.status.all[1]; // Second edit
console.log(`Previous status: ${previousEdit?.value}`);
// Check who made the most recent change
const latestEdit = task._edits.status;
console.log(`Latest change made by: ${latestEdit?.by?.id}`);
```
</CodeGroup>
## Time Travel
The ability to view a CoValue as it existed at any point in time is one of Jazz's most powerful features. Looking into the past can help you understand how things changed - perfect for audit logs, debugging, or showing user activity. You can reconstruct the exact state of any CoValue at any moment in its history:
<CodeGroup>
```ts
class Project extends CoMap {
name = coField.string;
status = coField.literal("planning", "active", "completed");
lastUpdate = coField.Date;
}
// See when a project was started
function findStatusChange(project: Project, targetStatus: string) {
// Get all the edits for the status field
const statusEdits = project._edits.status.all;
for (const edit of statusEdits) {
if (edit.value === targetStatus) {
console.log({
changeTime: edit.madeAt,
lastUpdate: project.lastUpdate,
changedBy: edit.by,
});
}
}
}
// Example usage
findStatusChange(gardenProject, "active");
```
</CodeGroup>
### Common Use Cases
The time travel capabilities of CoValues enable several practical use cases that would otherwise require complex custom implementations. Here are some examples of how you can use time travel in your applications:
<CodeGroup>
```ts
// Track task progress over time
function getTaskStatusHistory(task: Task, days: number = 7) {
const statusHistory = [];
const dayInMs = 86400000;
// Check every day for the past week
for (let day = 0; day < days; day++) {
const timePoint = new Date(Date.now() - day * dayInMs);
// Using the internal _raw API to get state at a specific point in time
const state = task._raw.atTime(timePoint);
statusHistory.push({
date: timePoint.toLocaleDateString(),
status: state.status,
priority: state.priority
});
}
return statusHistory;
}
// Example usage
const history = getTaskStatusHistory(plantingTask);
history.forEach(entry => {
console.log(`${entry.date}: Status was "${entry.status}" with ${entry.priority} priority`);
});
```
</CodeGroup>
### Best Practices
- Check field existence before accessing edits (`if (task._edits.fieldName)`)
- Access the most recent edit directly with `_edits.fieldName` instead of using any `.latest` property
- Cache historical queries if you're displaying them in UI
- Be specific about time ranges you care about
- Remember that accessing history requires loading the CoValue
- Consider using timestamps from your data rather than scanning all edits
Time travel is great for understanding how you got here, but keep queries focused on the range of time that matters to your use case.

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