Compare commits

...

114 Commits

Author SHA1 Message Date
Guido D'Orsi
5a00fe0862 perf: re-introducing linked lists on PriorityBasedMessageQueue 2025-03-28 12:54:44 +01:00
Guido D'Orsi
3db07f541f Merge pull request #1746 from garden-co/feat/upgrade-typedoc
fix(homepage): upgrade typedoc to v0.27 and ts v5.7
2025-03-28 12:12:04 +01:00
Guido D'Orsi
0db2e60d09 fix(homepage): upgrade typedoc to v0.27 and ts v5.7 2025-03-28 12:06:36 +01:00
Guido D'Orsi
f122147f03 Merge pull request #1745 from garden-co/changeset-release/main
Version Packages
2025-03-28 11:06:11 +01:00
github-actions[bot]
4e1bcde8b2 Version Packages 2025-03-28 10:02:02 +00:00
Guido D'Orsi
eaef418151 Merge pull request #1642 from garden-co/0-12-0
Jazz 0.12.0 - A clearer syntax for deep loading
2025-03-28 10:59:18 +01:00
Guido D'Orsi
8d17b192d0 Merge pull request #1743 from garden-co/improve-link-accounts
fix: make the linkAccounts test utility wait for the accounts coValues to be synced
2025-03-28 10:04:29 +01:00
Trisha Lim
9a56bb3d25 fix missing icon (#1744) 2025-03-28 14:08:32 +07:00
Guido D'Orsi
b6c6a0ae64 fix: make the linkAccounts test utility wait for the accounts coValues to be synced 2025-03-27 22:24:28 +01:00
Guido D'Orsi
e000774b3b Merge pull request #1739 from garden-co/changeset-release/main
Version Packages
2025-03-27 18:45:09 +01:00
github-actions[bot]
6f6cf23bc8 Version Packages 2025-03-27 17:38:35 +00:00
Guido D'Orsi
77a718656c Merge pull request #1741 from garden-co/issue-1373
fix: fixes expected header to be sent in first message error
2025-03-27 18:35:27 +01:00
Guido D'Orsi
6c86c4f7ee fix: fixes expected header to be sent in first message error 2025-03-27 18:34:39 +01:00
Guido D'Orsi
72508332fb Merge pull request #1728 from garden-co/gio/update-otel-dep
chore: update @opentelemetry/api dependency
2025-03-27 18:29:38 +01:00
Guido D'Orsi
0ac88b4c80 test: repro for expected header to be sent in first message 2025-03-27 17:41:01 +01:00
pax-k
11460b6f9f fix(cursor): refactored docs to include changes for Jazz v0.12.0 - Deeply resolved data 2025-03-27 18:34:03 +02:00
Trisha Lim
71b93909e6 fix(inspector): install clsx, remove lucide-react (#1737)
* install clsx

* remove lucide-react

* add changeset
2025-03-27 21:02:06 +07:00
Guido D'Orsi
26646cde0c chore: migrate code to the new resolve spec after merging with main 2025-03-27 12:02:06 +01:00
Guido D'Orsi
4033e95a50 Merge remote-tracking branch 'origin/main' into 0-12-0 2025-03-27 11:52:15 +01:00
Guido D'Orsi
f379fcc176 Merge pull request #1730 from garden-co/changeset-release/main
Version Packages
2025-03-27 11:49:13 +01:00
Guido D'Orsi
66d59b31d5 Merge pull request #1732 from garden-co/docs/loading-errors
docs: document loading errors
2025-03-27 11:48:23 +01:00
Guido D'Orsi
1e6da19d5e fix: The .load function now returns null on error 2025-03-27 11:48:12 +01:00
github-actions[bot]
d6ea4d4662 Version Packages 2025-03-27 10:37:27 +00:00
Guido D'Orsi
84b5dd8a0b Merge pull request #1719 from garden-co/feat/react-create-image
feat: re-export createImage on jazz-react
2025-03-27 11:35:02 +01:00
Guido D'Orsi
c730016572 Merge pull request #1726 from garden-co/fix/inspector-covalue-types
fix(inspector): CoFeeds and FileStreams are showing as "CoStream"
2025-03-27 11:32:53 +01:00
Guido D'Orsi
7677ca5240 Merge pull request #1735 from garden-co/feat/optimize-subscription-updates
fix: trigger a single update when loading a locally available list of items
2025-03-27 11:25:22 +01:00
Guido D'Orsi
cffe482f75 fix: apply the sync resolution on the ref access only during fullfillDepth to avoid issues with Svelte 2025-03-27 10:51:34 +01:00
Guido D'Orsi
a140f555ba fix: trigger a single update when loading a locally available list of items 2025-03-26 19:02:31 +01:00
Guido D'Orsi
10de4b6fc9 docs: document loading errors 2025-03-26 11:01:35 +01:00
Guido D'Orsi
2433344778 test: fix autoload test 2025-03-26 10:56:34 +01:00
Guido D'Orsi
4c01459942 fix(vue): fix types compilation for useAccount 2025-03-26 10:38:57 +01:00
Guido D'Orsi
8dacdd6e2f Merge pull request #1681 from garden-co/1656-document-loading-and-subscription
1656 Document loading and subscriptions
2025-03-25 19:16:39 +01:00
Guido D'Orsi
5b0580bfda docs: fix a broken vanilla example 2025-03-25 19:05:07 +01:00
Guido D'Orsi
2bed7e845d docs: complete the migration of the loading docs to twoslash 2025-03-25 18:55:25 +01:00
Anselm
76976026b7 Remove incorredct / unhelpful sections 2025-03-25 18:32:48 +01:00
Anselm
10ea8fbf88 Typecheck more of the subscribe and load docs, remove history docs again for now 2025-03-25 18:32:48 +01:00
Anselm
bd86b159b9 Fully type upgrade guide 2025-03-25 18:32:48 +01:00
Anselm
c4f5241818 More typechecking in upgrade guide 2025-03-25 18:32:48 +01:00
Anselm
181f433477 Fix Highlight component 2025-03-25 18:32:48 +01:00
Anselm
3897a7e137 Fix darkmode diff colours 2025-03-25 18:32:48 +01:00
Anselm
5082ecef3f Reintroduce Jazz colors 2025-03-25 18:32:47 +01:00
Anselm
268e433870 Typing in docs working 2025-03-25 18:32:47 +01:00
Anselm
6c185160c5 First attempt to make twoslash work 2025-03-25 18:32:47 +01:00
Anselm
d18323b74a Upgrade shiki and use built-in transformers for diffs 2025-03-25 18:32:47 +01:00
Anselm
edd91791c9 More details in deep loading 2025-03-25 18:32:47 +01:00
Anselm
958b13c050 Divide upgrade guide into breaking / new features 2025-03-25 18:32:47 +01:00
Anselm
bbe140f7be Remove incorrect stuff 2025-03-25 18:32:47 +01:00
Anselm
1625f82ab7 Clean up manual subscription & hooks 2025-03-25 18:32:47 +01:00
Anselm
843f729a62 Include current version of history & time travel 2025-03-25 18:32:47 +01:00
Anselm
cc4631bb42 "loading depth" -> "resolve query" 2025-03-25 18:32:47 +01:00
Anselm
3665ef0088 Container-like -> collections 2025-03-25 18:32:47 +01:00
Trisha Lim
e13039818e fix coming soon TOC 2025-03-25 18:32:44 +01:00
Benjamin S. Leveritt
2e79487982 Change to markdown + format
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:32:10 +01:00
Benjamin S. Leveritt
fc2c045a8d Fix ‘for example’
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:58 +01:00
Anselm
69bb94be06 Missing green line 2025-03-25 18:31:58 +01:00
Anselm
228c8fa796 Upgrade guide improvments 2025-03-25 18:31:58 +01:00
Benjamin S. Leveritt
a34b850824 Update CoMap.Record resolve example
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:45 +01:00
Benjamin S. Leveritt
96d518bb97 Remove auto-loading section
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:45 +01:00
Benjamin S. Leveritt
8355f5674d Add Vanilla examples
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
5c1d04ee88 Tweak copy
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
2ef98d01b0 Fix permissions in lists comment
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
15a86a3014 Move Framework detail to just under the fold
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
9c49704cf9 Update Subs and Loading docs
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
44f0d8d5c7 Update subs doc
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
d7af97d63f Fix version and date
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:41 +01:00
Giordano Ricci
9d0c9dc6ea chore: update @opentelemetry/api dependency 2025-03-25 15:20:34 +00:00
Trisha Lim
2c3761c8e8 add changeset 2025-03-25 18:52:16 +07:00
Trisha Lim
c91bcf9745 inspector: show CoStream as CoFeed 2025-03-25 18:32:37 +07:00
Trisha Lim
c1db6e087a reuse use-resolve-covalue 2025-03-25 18:31:14 +07:00
Trisha Lim
9d8cc194e0 inspector: show files as FileStream instead of CoStream 2025-03-25 18:30:45 +07:00
Guido D'Orsi
3b189e4def Merge pull request #1725 from garden-co/feat/increase-depth-limit
feat: increase depth limit to 10
2025-03-25 12:13:48 +01:00
Guido D'Orsi
7fe50922cc docs: update the version on the 0.12 upgrade guide 2025-03-25 11:05:09 +01:00
Guido D'Orsi
b04e2be665 feat: increase depth limit to 10 2025-03-25 11:03:23 +01:00
Guido D'Orsi
80b1535cdf Merge remote-tracking branch 'origin/main' into 0-12-0 2025-03-24 18:36:48 +01:00
Guido D'Orsi
3d882f0442 fix: update resolve in the new music player action 2025-03-14 15:25:23 +01:00
Guido D'Orsi
f61d568c9d Merge remote-tracking branch 'origin/main' into 0-12-0 2025-03-14 15:21:09 +01:00
Guido D'Orsi
6dd02d289c chore: fix a type error in the tests 2025-03-11 17:22:26 +01:00
Guido D'Orsi
33a4944ba3 Merge remote-tracking branch 'origin/jazz-581-add-docs' into 0-12-0 2025-03-11 17:17:26 +01:00
Guido D'Orsi
e367b6056d Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-03-11 17:14:38 +01:00
Guido D'Orsi
f3f56b9be0 docs: clarifications 2025-03-06 14:42:30 +01:00
Guido D'Orsi
4cae6bad34 Merge 2025-03-06 14:38:01 +01:00
Guido D'Orsi
17f2ef57de docs: bump the upgrade version 2025-03-06 14:37:19 +01:00
Guido D'Orsi
3a4d111a37 Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-03-06 14:33:18 +01:00
Guido D'Orsi
1e18c7f5fc Merge remote-tracking branch 'origin/0-11-0' into jazz-581-rfc-new-deep-loading-api 2025-02-28 14:58:32 +01:00
Guido D'Orsi
8c7a6b27ed docs: refine the examples and align the feature descripted with the implementation 2025-02-26 18:23:02 +01:00
Guido D'Orsi
91f96e1188 Merge branch 'jazz-581-rfc-new-deep-loading-api' into jazz-581-add-docs 2025-02-26 18:12:56 +01:00
Guido D'Orsi
28dac10723 Merge pull request #1517 from garden-co/fix/optional-fields-acl
feat(deepLoading): return undefined when an optional field is not accessible
2025-02-26 14:58:27 +01:00
Guido D'Orsi
9cb11e38dd feat(deepLoading): return undefined when an optional field is not accessible 2025-02-26 12:56:06 +01:00
Guido D'Orsi
f3e4bacb33 Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-02-25 17:46:22 +01:00
Guido D'Orsi
626d43f07b Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-02-21 18:27:14 +01:00
Benjamin S. Leveritt
1f5d073035 Update homepage/homepage/app/(docs)/docs/[framework]/[...slug]/upgrade/0-11-0.mdx
Co-authored-by: Guido D'Orsi <guido@float.com>
2025-02-13 17:34:20 +00:00
Benjamin S. Leveritt
a3b607e799 Update homepage/homepage/app/(docs)/docs/[framework]/[...slug]/upgrade/0-11-0.mdx
Co-authored-by: Guido D'Orsi <guido@float.com>
2025-02-13 17:34:06 +00:00
Benjamin S. Leveritt
8fb93502af Update homepage/homepage/app/(docs)/docs/[framework]/[...slug]/upgrade/0-11-0.mdx
Co-authored-by: Guido D'Orsi <guido@float.com>
2025-02-13 17:33:49 +00:00
Benjamin S. Leveritt
36774122e0 Updates react guide for new resolve API
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-02-13 16:08:52 +00:00
Benjamin S. Leveritt
a6923128c1 Adds upgrade guide
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-02-13 15:56:11 +00:00
Guido D'Orsi
706ca62feb Merge pull request #1363 from garden-co/unauthorized-deep-loading
fix: check CoValue permissions when loading/subscribing
2025-02-13 09:55:16 +01:00
Guido D'Orsi
01523dcca3 fix: check CoValue permissions when loading/subscribing 2025-02-13 09:19:19 +01:00
Guido D'Orsi
77f039b561 Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-02-13 09:18:47 +01:00
Guido D'Orsi
d661ba77be chore: improve pre-release comment output 2025-02-12 11:32:05 +01:00
Guido D'Orsi
f8fbc59b6f Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-02-11 16:26:12 +01:00
Guido D'Orsi
cce0d22007 fix: update resolve property 2025-02-11 15:15:44 +01:00
Guido D'Orsi
e3ff76e9cb Merge remote-tracking branch 'origin/authv2' into jazz-581-rfc-new-deep-loading-api 2025-02-11 15:12:51 +01:00
Guido D'Orsi
4cbf71bff7 Merge pull request #1338 from garden-co/new-deep-loading-extra-props-fix
fix: disallow extra props in the resolve type
2025-02-11 14:38:43 +01:00
Guido D'Orsi
ceb060243a fix: disallow extra props in the resolve type 2025-02-10 20:04:32 +01:00
Anselm
a70bebb96a Clean up new deep-loading API 2025-01-29 14:39:16 +00:00
Anselm
b3b2507c35 Merge branch 'main' into jazz-581-rfc-new-deep-loading-api 2025-01-27 11:36:08 +00:00
Anselm
6a8fa16b49 Fix form and chat-rn-clerk examples 2024-12-16 15:56:48 +00:00
Anselm
1f08807701 Merge branch 'main' into jazz-581-rfc-new-deep-loading-api 2024-12-16 15:37:39 +00:00
Anselm
ba4a7f6170 Remove temp vite config 2024-12-16 15:35:06 +00:00
Anselm
a2854e3602 Upgrade to minor version change 2024-12-16 11:25:00 +00:00
Anselm
4ea87dc494 Add changeset 2024-12-16 10:55:51 +00:00
Anselm
d8c87c5314 Use $each instead of each 2024-12-16 10:54:25 +00:00
Anselm
46f624a12e Replace 'items' with 'each' 2024-12-13 16:28:40 +00:00
Anselm
86ce770f38 Implement clearer syntax for deep loading 2024-12-13 15:12:42 +00:00
258 changed files with 6404 additions and 3117 deletions

View File

@@ -0,0 +1,5 @@
---
"cojson": patch
---
Re-introducing linked lists on PriorityBasedMessageQueue

View File

@@ -1,5 +0,0 @@
---
"cojson": patch
---
Performance: optimize Group.roleOf getter and made the transactions validation incremental for CoMap and CoFeed

View File

@@ -1,5 +0,0 @@
---
"jazz-react": patch
---
Re-export createImage from jazz-browser-media-images

View File

@@ -1,5 +0,0 @@
---
"cojson": patch
---
Throw an error when the user tries to load an invalid or undefined id

View File

@@ -1,5 +0,0 @@
---
"jazz-tools": patch
---
Export CoFeedEntry type

View File

@@ -1,5 +1,38 @@
# chat-rn-clerk
## 1.0.90
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react-native@0.12.0
- jazz-react-native-auth-clerk@0.12.0
- jazz-react-native-media-images@0.12.0
## 1.0.89
### Patch Changes
- jazz-react-native@0.11.8
- jazz-react-native-auth-clerk@0.11.8
- jazz-tools@0.11.8
- jazz-react-native-media-images@0.11.8
## 1.0.88
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react-native@0.11.7
- jazz-react-native-auth-clerk@0.11.7
- jazz-react-native-media-images@0.11.7
## 1.0.87
### Patch Changes

View File

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

View File

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

View File

@@ -1,5 +1,32 @@
# chat-rn
## 1.0.86
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react-native@0.12.0
## 1.0.85
### Patch Changes
- jazz-react-native@0.11.8
- jazz-tools@0.11.8
## 1.0.84
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react-native@0.11.7
## 1.0.83
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.83",
"version": "1.0.86",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",

View File

@@ -20,7 +20,7 @@ import { Chat, Message } from "./schema";
export default function ChatScreen({ navigation }: { navigation: any }) {
const { me, logOut } = useAccount();
const [chatId, setChatId] = useState<ID<Chat>>();
const loadedChat = useCoState(Chat, chatId, [{}]);
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});

View File

@@ -1,5 +1,36 @@
# chat-vue
## 0.0.71
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [4c01459]
- jazz-tools@0.12.0
- jazz-vue@0.12.0
- jazz-browser@0.12.0
## 0.0.70
### Patch Changes
- jazz-browser@0.11.8
- jazz-tools@0.11.8
- jazz-vue@0.11.8
## 0.0.69
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-browser@0.11.7
- jazz-vue@0.11.7
## 0.0.68
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.68",
"version": "0.0.71",
"private": true,
"type": "module",
"scripts": {

View File

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

View File

@@ -1,5 +1,39 @@
# jazz-example-chat
## 0.0.168
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [9a56bb3]
- jazz-tools@0.12.0
- jazz-inspector@0.12.0
- jazz-react@0.12.0
## 0.0.167
### Patch Changes
- Updated dependencies [71b9390]
- jazz-inspector@0.11.8
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.166
### Patch Changes
- Updated dependencies [2c3761c]
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-inspector@0.11.7
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.165
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.165",
"version": "0.0.168",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -16,8 +16,8 @@ import {
} from "./ui.tsx";
export function ChatScreen(props: { chatID: ID<Chat> }) {
const chat = useCoState(Chat, props.chatID, { resolve: { $each: true } });
const account = useAccount();
const chat = useCoState(Chat, props.chatID, [{}]);
const [showNLastMessages, setShowNLastMessages] = useState(30);
if (!chat)

View File

@@ -1,5 +1,36 @@
# minimal-auth-clerk
## 0.0.67
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
- jazz-react-auth-clerk@0.12.0
## 0.0.66
### Patch Changes
- jazz-react@0.11.8
- jazz-react-auth-clerk@0.11.8
- jazz-tools@0.11.8
## 0.0.65
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
- jazz-react-auth-clerk@0.11.7
## 0.0.64
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.64",
"version": "0.0.67",
"type": "module",
"scripts": {
"dev": "vite",
@@ -13,7 +13,7 @@
"dependencies": {
"@clerk/clerk-react": "^5.4.1",
"jazz-react": "workspace:*",
"jazz-react-auth-clerk": "workspace:0.11.6",
"jazz-react-auth-clerk": "workspace:0.12.0",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"

View File

@@ -1,5 +1,32 @@
# file-share-svelte
## 0.0.51
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-svelte@0.12.0
## 0.0.50
### Patch Changes
- jazz-svelte@0.11.8
- jazz-tools@0.11.8
## 0.0.49
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-svelte@0.11.7
## 0.0.48
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.48",
"version": "0.0.51",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,33 @@
# jazz-tailwind-demo-auth-starter
## 0.0.7
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.6
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.5
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.4
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "filestream",
"private": true,
"version": "0.0.4",
"version": "0.0.7",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,33 @@
# form
## 0.1.9
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.1.8
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.1.7
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.1.6
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.1.6",
"version": "0.1.9",
"type": "module",
"scripts": {
"dev": "vite",

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,33 @@
# image-upload
## 0.0.65
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.64
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.63
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.62
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.62",
"version": "0.0.65",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,39 @@
# jazz-example-inspector
## 0.0.118
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [01523dc]
- Updated dependencies [9a56bb3]
- cojson@0.12.0
- jazz-inspector@0.12.0
- cojson-transport-ws@0.12.0
## 0.0.117
### Patch Changes
- Updated dependencies [71b9390]
- Updated dependencies [6c86c4f]
- Updated dependencies [9d0c9dc]
- jazz-inspector@0.11.8
- cojson@0.11.8
- cojson-transport-ws@0.11.8
## 0.0.116
### Patch Changes
- 2c3761c: fix: CoFeed and FileStream are showing as CoStream
- Updated dependencies [2c3761c]
- Updated dependencies [2b94bc8]
- Updated dependencies [2957362]
- jazz-inspector@0.11.7
- cojson@0.11.7
- cojson-transport-ws@0.11.7
## 0.0.115
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector-app",
"private": true,
"version": "0.0.115",
"version": "0.0.118",
"type": "module",
"scripts": {
"dev": "vite",
@@ -13,8 +13,8 @@
"dependencies": {
"jazz-inspector": "workspace:*",
"clsx": "^2.0.0",
"cojson": "workspace:0.11.6",
"cojson-transport-ws": "workspace:0.11.6",
"cojson": "workspace:0.12.0",
"cojson-transport-ws": "workspace:0.12.0",
"hash-slash": "workspace:0.2.2",
"lucide-react": "^0.274.0",
"react": "^18.3.1",

View File

@@ -17,9 +17,9 @@ import {
PageStack,
Select,
} from "jazz-inspector";
import { resolveCoValue, useResolvedCoValue } from "jazz-inspector";
import React, { useState, useEffect } from "react";
import { usePagePath } from "./use-page-path";
import { resolveCoValue, useResolvedCoValue } from "./use-resolve-covalue";
interface Account {
id: CoID<RawAccount>;

View File

@@ -1,216 +0,0 @@
import { CoID, LocalNode, RawBinaryCoStream, RawCoValue } from "cojson";
import { useEffect, useState } from "react";
export type CoJsonType = "comap" | "costream" | "colist";
export type ExtendedCoJsonType = "image" | "record" | "account" | "group";
type JSON = string | number | boolean | null | JSON[] | { [key: string]: JSON };
type JSONObject = { [key: string]: JSON };
type ResolvedImageDefinition = {
originalSize: [number, number];
placeholderDataURL?: string;
[res: `${number}x${number}`]: RawBinaryCoStream["id"];
};
// Type guard for browser image
export const isBrowserImage = (
coValue: JSONObject,
): coValue is ResolvedImageDefinition => {
return "originalSize" in coValue && "placeholderDataURL" in coValue;
};
export type ResolvedGroup = {
readKey: string;
[key: string]: JSON;
};
export const isGroup = (coValue: JSONObject): coValue is ResolvedGroup => {
return "readKey" in coValue;
};
export type ResolvedAccount = {
profile: {
name: string;
};
[key: string]: JSON;
};
export const isAccount = (coValue: JSONObject): coValue is ResolvedAccount => {
return isGroup(coValue) && "profile" in coValue;
};
export async function resolveCoValue(
coValueId: CoID<RawCoValue>,
node: LocalNode,
): Promise<
| {
value: RawCoValue;
snapshot: JSONObject;
type: CoJsonType | null;
extendedType: ExtendedCoJsonType | undefined;
}
| {
value: undefined;
snapshot: "unavailable";
type: null;
extendedType: undefined;
}
> {
const value = await node.load(coValueId);
if (value === "unavailable") {
return {
value: undefined,
snapshot: "unavailable",
type: null,
extendedType: undefined,
};
}
const snapshot = value.toJSON() as JSONObject;
const type = value.type as CoJsonType;
// Determine extended type
let extendedType: ExtendedCoJsonType | undefined;
if (type === "comap") {
if (isBrowserImage(snapshot)) {
extendedType = "image";
} else if (isAccount(snapshot)) {
extendedType = "account";
} else if (isGroup(snapshot)) {
extendedType = "group";
} else {
// This check is a bit of a hack
// There might be a better way to do this
const children = Object.values(snapshot).slice(0, 10);
if (
children.every((c) => typeof c === "string" && c.startsWith("co_")) &&
children.length > 3
) {
extendedType = "record";
}
}
}
return {
value,
snapshot,
type,
extendedType,
};
}
function subscribeToCoValue(
coValueId: CoID<RawCoValue>,
node: LocalNode,
callback: (result: Awaited<ReturnType<typeof resolveCoValue>>) => void,
) {
return node.subscribe(coValueId, (value) => {
if (value === "unavailable") {
callback({
value: undefined,
snapshot: "unavailable",
type: null,
extendedType: undefined,
});
} else {
const snapshot = value.toJSON() as JSONObject;
const type = value.type as CoJsonType;
let extendedType: ExtendedCoJsonType | undefined;
if (type === "comap") {
if (isBrowserImage(snapshot)) {
extendedType = "image";
} else if (isAccount(snapshot)) {
extendedType = "account";
} else if (isGroup(snapshot)) {
extendedType = "group";
} else {
const children = Object.values(snapshot).slice(0, 10);
if (
children.every(
(c) => typeof c === "string" && c.startsWith("co_"),
) &&
children.length > 3
) {
extendedType = "record";
}
}
}
callback({
value,
snapshot,
type,
extendedType,
});
}
});
}
export function useResolvedCoValue(
coValueId: CoID<RawCoValue>,
node: LocalNode,
) {
const [result, setResult] =
useState<Awaited<ReturnType<typeof resolveCoValue>>>();
useEffect(() => {
let isMounted = true;
const unsubscribe = subscribeToCoValue(coValueId, node, (newResult) => {
if (isMounted) {
setResult(newResult);
}
});
return () => {
isMounted = false;
unsubscribe();
};
}, [coValueId, node]);
return (
result || {
value: undefined,
snapshot: undefined,
type: undefined,
extendedType: undefined,
}
);
}
export function useResolvedCoValues(
coValueIds: CoID<RawCoValue>[],
node: LocalNode,
) {
const [results, setResults] = useState<
Awaited<ReturnType<typeof resolveCoValue>>[]
>([]);
useEffect(() => {
let isMounted = true;
const unsubscribes: (() => void)[] = [];
coValueIds.forEach((coValueId, index) => {
const unsubscribe = subscribeToCoValue(coValueId, node, (newResult) => {
if (isMounted) {
setResults((prevResults) => {
const newResults = [...prevResults];
newResults[index] = newResult;
return newResults;
});
}
});
unsubscribes.push(unsubscribe);
});
return () => {
isMounted = false;
unsubscribes.forEach((unsubscribe) => unsubscribe());
};
}, [coValueIds, node]);
return results;
}

View File

@@ -0,0 +1,29 @@
# multi-cursors
## 0.0.61
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.60
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.59
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7

View File

@@ -1,7 +1,7 @@
{
"name": "multi-cursors",
"private": true,
"version": "0.0.58",
"version": "0.0.61",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -7,7 +7,7 @@ import Canvas from "./Canvas";
/** A higher order component that wraps the canvas. */
function Container({ cursorFeedID }: { cursorFeedID: ID<CursorFeed> }) {
const { me } = useAccount();
const cursors = useCoState(CursorFeed, cursorFeedID, []);
const cursors = useCoState(CursorFeed, cursorFeedID, { resolve: true });
return (
<Canvas

View File

@@ -3,7 +3,7 @@ import { CursorContainer, CursorFeed } from "../schema";
export async function loadGroup(me: Account, groupID: ID<Group>) {
const group = await Group.load(groupID, {});
if (group === undefined) {
if (group === null) {
const group = Group.create({
owner: me,
});
@@ -35,15 +35,16 @@ export async function loadCursorContainer(
group?.id as ID<Group>,
);
const cursorContainer = await CursorContainer.load(cursorContainerID, {
cursorFeed: [],
resolve: {
cursorFeed: true,
},
});
if (cursorContainer === undefined) {
if (cursorContainer === null) {
console.log("Global cursors does not exist, creating...");
const cursorContainer = CursorContainer.create(
{
cursorFeed: CursorFeed.create([], {
owner: group,
}),
cursorFeed: CursorFeed.create([], group),
},
{
owner: group,

View File

@@ -1,5 +1,36 @@
# multiauth
## 0.0.8
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
- jazz-react-auth-clerk@0.12.0
## 0.0.7
### Patch Changes
- jazz-react@0.11.8
- jazz-react-auth-clerk@0.11.8
- jazz-tools@0.11.8
## 0.0.6
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
- jazz-react-auth-clerk@0.11.7
## 0.0.5
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "multiauth",
"private": true,
"version": "0.0.5",
"version": "0.0.8",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,39 @@
# jazz-example-musicplayer
## 0.0.89
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [9a56bb3]
- jazz-tools@0.12.0
- jazz-inspector@0.12.0
- jazz-react@0.12.0
## 0.0.88
### Patch Changes
- Updated dependencies [71b9390]
- jazz-inspector@0.11.8
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.87
### Patch Changes
- Updated dependencies [2c3761c]
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-inspector@0.11.7
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.86
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.86",
"version": "0.0.89",
"type": "module",
"scripts": {
"dev": "vite",
@@ -22,8 +22,8 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-inspector": "workspace:*",
"jazz-react": "workspace:0.11.6",
"jazz-tools": "workspace:0.11.6",
"jazz-react": "workspace:0.12.0",
"jazz-tools": "workspace:0.12.0",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",

View File

@@ -24,10 +24,7 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
* access rights to CoValues. We get it from the top-level provider `<WithJazz/>`.
*/
const { me } = useAccount({
root: {
rootPlaylist: {},
playlists: [],
},
resolve: { root: { rootPlaylist: true, playlists: true } },
});
const navigate = useNavigate();
@@ -51,8 +48,9 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
const params = useParams<{ playlistId: ID<Playlist> }>();
const playlistId = params.playlistId ?? me?.root._refs.rootPlaylist.id;
const playlist = useCoState(Playlist, playlistId, {
tracks: [],
resolve: { tracks: true },
});
const isRootPlaylist = !params.playlistId;

View File

@@ -27,9 +27,11 @@ export async function uploadMusicTracks(
isExampleTrack: boolean = false,
) {
const { root } = await MusicaAccount.getMe().ensureLoaded({
root: {
rootPlaylist: {
tracks: [],
resolve: {
root: {
rootPlaylist: {
tracks: true,
},
},
},
});
@@ -65,8 +67,10 @@ export async function uploadMusicTracks(
export async function createNewPlaylist() {
const { root } = await MusicaAccount.getMe().ensureLoaded({
root: {
playlists: [],
resolve: {
root: {
playlists: true,
},
},
});
@@ -149,9 +153,11 @@ export async function updateMusicTrackTitle(track: MusicTrack, title: string) {
export async function updateActivePlaylist(playlist?: Playlist) {
const { root } = await MusicaAccount.getMe().ensureLoaded({
root: {
activePlaylist: {},
rootPlaylist: {},
resolve: {
root: {
activePlaylist: true,
rootPlaylist: true,
},
},
});
@@ -160,7 +166,9 @@ export async function updateActivePlaylist(playlist?: Playlist) {
export async function updateActiveTrack(track: MusicTrack) {
const { root } = await MusicaAccount.getMe().ensureLoaded({
root: {},
resolve: {
root: {},
},
});
root.activeTrack = track;
@@ -170,17 +178,23 @@ export async function onAnonymousAccountDiscarded(
anonymousAccount: MusicaAccount,
) {
const { root: anonymousAccountRoot } = await anonymousAccount.ensureLoaded({
root: {
rootPlaylist: {
tracks: [{}],
resolve: {
root: {
rootPlaylist: {
tracks: {
$each: true,
},
},
},
},
});
const me = await MusicaAccount.getMe().ensureLoaded({
root: {
rootPlaylist: {
tracks: [],
resolve: {
root: {
rootPlaylist: {
tracks: true,
},
},
},
});
@@ -197,8 +211,10 @@ export async function onAnonymousAccountDiscarded(
export async function deletePlaylist(playlistId: string) {
const { root } = await MusicaAccount.getMe().ensureLoaded({
root: {
playlists: [],
resolve: {
root: {
playlists: true,
},
},
});

View File

@@ -9,7 +9,7 @@ import { getNextTrack, getPrevTrack } from "./lib/getters";
export function useMediaPlayer() {
const { me } = useAccount({
root: {},
resolve: { root: true },
});
const playState = usePlayState();

View File

@@ -16,8 +16,10 @@ export function InvitePage() {
const playlist = await Playlist.load(playlistId, {});
const me = await MusicaAccount.getMe().ensureLoaded({
root: {
playlists: [],
resolve: {
root: {
playlists: true,
},
},
});

View File

@@ -22,9 +22,13 @@ export function AuthModal({ open, onOpenChange }: AuthModalProps) {
const [error, setError] = useState<string | null>(null);
const { me } = useAccount({
root: {
rootPlaylist: {
tracks: [{}],
resolve: {
root: {
rootPlaylist: {
tracks: {
$each: true,
},
},
},
},
});

View File

@@ -30,9 +30,7 @@ export function MusicTrackRow({
const track = useCoState(MusicTrack, trackId);
const { me } = useAccount({
root: {
playlists: [{}],
},
resolve: { root: { playlists: { $each: true } } },
});
const playlists = me?.root.playlists ?? [];

View File

@@ -12,9 +12,7 @@ export function PlayerControls({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
const isPlaying = playState.value === "play";
const activePlaylist = useAccount({
root: {
activePlaylist: {},
},
resolve: { root: { activePlaylist: true } },
}).me?.root.activePlaylist;
useMediaEndListener(mediaPlayer.playNextTrack);
@@ -25,7 +23,7 @@ export function PlayerControls({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
});
const activeTrack = useCoState(MusicTrack, mediaPlayer.activeTrackId, {
waveform: {},
resolve: { waveform: true },
});
if (!activeTrack) return null;

View File

@@ -8,9 +8,7 @@ export function SidePanel() {
const { playlistId } = useParams();
const navigate = useNavigate();
const { me } = useAccount({
root: {
playlists: [{}],
},
resolve: { root: { playlists: { $each: true } } },
});
function handleAllTracksClick(evt: React.MouseEvent<HTMLAnchorElement>) {

View File

@@ -8,7 +8,6 @@ export function Waveform(props: { track: MusicTrack; height: number }) {
const waveformData = useCoState(
MusicTrackWaveform,
track._refs.waveform.id,
{},
)?.data;
const duration = track.duration;

View File

@@ -2,9 +2,11 @@ import { MusicaAccount } from "../1_schema";
export async function getNextTrack() {
const me = await MusicaAccount.getMe().ensureLoaded({
root: {
activePlaylist: {
tracks: [],
resolve: {
root: {
activePlaylist: {
tracks: true,
},
},
},
});
@@ -21,9 +23,11 @@ export async function getNextTrack() {
export async function getPrevTrack() {
const me = await MusicaAccount.getMe().ensureLoaded({
root: {
activePlaylist: {
tracks: [],
resolve: {
root: {
activePlaylist: {
tracks: true,
},
},
},
});

View File

@@ -13,7 +13,7 @@ export function useUploadExampleData() {
async function uploadOnboardingData() {
const me = await MusicaAccount.getMe().ensureLoaded({
root: {},
resolve: { root: true },
});
if (me.root.exampleDataLoaded) return;

View File

@@ -1,5 +1,33 @@
# organization
## 0.0.61
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.60
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.59
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.58
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "organization",
"private": true,
"version": "0.0.58",
"version": "0.0.61",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -5,11 +5,11 @@ import { Organization } from "./schema.ts";
export function AcceptInvitePage() {
const navigate = useNavigate();
const { me } = useAccount({ root: { organizations: [] } });
const { me } = useAccount({ resolve: { root: { organizations: true } } });
const onAccept = (organizationId: ID<Organization>) => {
if (me?.root?.organizations) {
Organization.load(organizationId, me, []).then((organization) => {
Organization.load(organizationId).then((organization) => {
if (organization) {
// avoid duplicates
const ids = me.root.organizations.map(

View File

@@ -5,7 +5,7 @@ import { Heading } from "./components/Heading.tsx";
export function HomePage() {
const { me } = useAccount({
root: { organizations: [{}] },
resolve: { root: { organizations: true } },
});
if (!me?.root.organizations) return;

View File

@@ -3,7 +3,7 @@ import { UserIcon } from "lucide-react";
export function Layout({ children }: { children: React.ReactNode }) {
const { me, logOut } = useAccount({
root: { draftOrganization: {} },
resolve: { root: { draftOrganization: true } },
});
return (

View File

@@ -13,7 +13,7 @@ export function OrganizationPage() {
.organizationId;
const organization = useCoState(Organization, paramOrganizationId, {
projects: [],
resolve: { projects: true },
});
if (!organization) return <p>Loading organization...</p>;

View File

@@ -8,7 +8,7 @@ import { OrganizationForm } from "./OrganizationForm.tsx";
export function CreateOrganization() {
const { me } = useAccount({
root: { draftOrganization: {}, organizations: [] },
resolve: { root: { draftOrganization: true, organizations: true } },
});
const [errors, setErrors] = useState<string[]>([]);
const navigate = useNavigate();

View File

@@ -7,7 +7,7 @@ import { Organization } from "../schema.ts";
export function OrganizationSelector({ className }: { className?: string }) {
const { me } = useAccount({
root: { organizations: [{}] },
resolve: { root: { organizations: { $each: true } } },
});
const navigate = useNavigate();

View File

@@ -1,5 +1,23 @@
# passkey-svelte
## 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

View File

@@ -1,6 +1,6 @@
{
"name": "passkey-svelte",
"version": "0.0.52",
"version": "0.0.55",
"type": "module",
"private": true,
"scripts": {

View File

@@ -1,5 +1,33 @@
# minimal-auth-passkey
## 0.0.66
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.65
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.64
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.63
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "passkey",
"private": true,
"version": "0.0.63",
"version": "0.0.66",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,33 @@
# passphrase
## 0.0.63
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.62
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.61
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.60
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "passphrase",
"private": true,
"version": "0.0.60",
"version": "0.0.63",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,33 @@
# jazz-password-manager
## 0.0.87
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.86
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.85
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.84
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.84",
"version": "0.0.87",
"type": "module",
"scripts": {
"dev": "vite",
@@ -12,8 +12,8 @@
"clean-install": "rm -rf node_modules pnpm-lock.yaml && pnpm install"
},
"dependencies": {
"jazz-react": "workspace:0.11.6",
"jazz-tools": "workspace:0.11.6",
"jazz-react": "workspace:0.12.0",
"jazz-tools": "workspace:0.12.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.41.5",

View File

@@ -43,9 +43,11 @@ const VaultPage: React.FC = () => {
(item): item is Exclude<typeof item, null> => !!item,
) || [],
);
const folders = useCoState(FolderList, me.root?._refs.folders?.id, [
{ items: [{}] },
]);
const folders = useCoState(FolderList, me.root?._refs.folders?.id, {
resolve: {
$each: { items: { $each: true } },
},
});
const [selectedFolder, setSelectedFolder] = useState<Folder | undefined>();
const [isNewItemModalOpen, setIsNewItemModalOpen] = useState(false);

View File

@@ -60,11 +60,9 @@ export async function addSharedFolder(
me: PasswordManagerAccount,
) {
const [sharedFolder, account] = await Promise.all([
Folder.load(sharedFolderId, me, {}),
PasswordManagerAccount.load(me.id, me, {
root: {
folders: [],
},
Folder.load(sharedFolderId),
PasswordManagerAccount.load(me.id, {
resolve: { root: { folders: true } },
}),
]);

View File

@@ -1,5 +1,33 @@
# jazz-example-pets
## 0.0.185
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.184
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.183
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.182
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.182",
"version": "0.0.185",
"type": "module",
"scripts": {
"dev": "vite",
@@ -19,8 +19,8 @@
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-react": "workspace:0.11.6",
"jazz-tools": "workspace:0.11.6",
"jazz-react": "workspace:0.12.0",
"jazz-tools": "workspace:0.12.0",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.3.1",
@@ -40,7 +40,7 @@
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"is-ci": "^3.0.1",
"jazz-run": "workspace:0.11.6",
"jazz-run": "workspace:0.12.0",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2",

View File

@@ -1,5 +1,33 @@
# reactions
## 0.0.65
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.64
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.63
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.62
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "reactions",
"private": true,
"version": "0.0.62",
"version": "0.0.65",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -14,7 +14,7 @@ const reactionEmojiMap: {
};
export function ReactionsScreen(props: { id: ID<Reactions> }) {
const reactions = useCoState(Reactions, props.id, []);
const reactions = useCoState(Reactions, props.id);
if (!reactions) return;

View File

@@ -1,5 +1,36 @@
# todo-vue
## 0.0.69
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [4c01459]
- jazz-tools@0.12.0
- jazz-vue@0.12.0
- jazz-browser@0.12.0
## 0.0.68
### Patch Changes
- jazz-browser@0.11.8
- jazz-tools@0.11.8
- jazz-vue@0.11.8
## 0.0.67
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-browser@0.11.7
- jazz-vue@0.11.7
## 0.0.66
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "todo-vue",
"version": "0.0.66",
"version": "0.0.69",
"private": true,
"type": "module",
"scripts": {

View File

@@ -4,15 +4,15 @@
<div class="section-header">
<h2>Folders</h2>
<div class="new-folder">
<input
v-model="newFolderName"
placeholder="New folder name"
<input
v-model="newFolderName"
placeholder="New folder name"
class="input"
/>
<button class="btn btn-primary" @click="createFolder">Create</button>
</div>
</div>
<div class="folder-list">
<div
v-for="folder in folders"
@@ -32,9 +32,9 @@
<div class="section-header">
<h2>{{ selectedFolder?.name }}</h2>
<div class="new-todo">
<input
v-model="newTodoTitle"
placeholder="Add a new task"
<input
v-model="newTodoTitle"
placeholder="Add a new task"
class="input"
/>
<button class="btn btn-primary" @click="createTodo">Add</button>
@@ -72,7 +72,9 @@ import { Folder, FolderList, ToDoItem, ToDoList } from "../schema";
const { me } = useAccount();
const computedFoldersId = computed(() => me.value?.root?.folders?.id);
const folders = useCoState(FolderList, computedFoldersId, [{ items: [{}] }]);
const folders = useCoState(FolderList, computedFoldersId, {
resolve: { $each: { items: true } },
});
const selectedFolder = ref<Folder>();
const newFolderName = ref("");

View File

@@ -1,5 +1,33 @@
# jazz-example-todo
## 0.0.184
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react@0.12.0
## 0.0.183
### Patch Changes
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.182
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.181
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.181",
"version": "0.0.184",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,8 +16,8 @@
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-react": "workspace:0.11.6",
"jazz-tools": "workspace:0.11.6",
"jazz-react": "workspace:0.12.0",
"jazz-tools": "workspace:0.12.0",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.3.1",

View File

@@ -121,7 +121,7 @@ export default function App() {
function HomeScreen() {
const { me } = useAccount({
root: { projects: [{}] },
resolve: { root: { projects: { $each: true } } },
});
const navigate = useNavigate();

View File

@@ -1,5 +1,39 @@
# version-history
## 0.0.62
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [9a56bb3]
- jazz-tools@0.12.0
- jazz-inspector@0.12.0
- jazz-react@0.12.0
## 0.0.61
### Patch Changes
- Updated dependencies [71b9390]
- jazz-inspector@0.11.8
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.60
### Patch Changes
- Updated dependencies [2c3761c]
- Updated dependencies [a140f55]
- Updated dependencies [4019918]
- Updated dependencies [2b0d1b0]
- jazz-inspector@0.11.7
- jazz-tools@0.11.7
- jazz-react@0.11.7
## 0.0.59
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "version-history",
"private": true,
"version": "0.0.59",
"version": "0.0.62",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -4,7 +4,9 @@ import { ID } from "jazz-tools";
import { IssueComponent } from "./Issue.tsx";
import { Issue, Project } from "./schema.ts";
export function ProjectComponent({ projectID }: { projectID: ID<Project> }) {
const project = useCoState(Project, projectID, { issues: [{}] });
const project = useCoState(Project, projectID, {
resolve: { issues: { $each: true } },
});
if (!project) return;

View File

@@ -2,6 +2,7 @@ import { clsx } from "clsx";
import Link from "next/link";
import { forwardRef } from "react";
import { Icon } from "./Icon";
import type { IconName } from "./Icon";
import { Spinner } from "./Spinner";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
@@ -9,7 +10,7 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
size?: "sm" | "md" | "lg";
href?: string;
newTab?: boolean;
icon?: string;
icon?: IconName;
loading?: boolean;
loadingText?: string;
children?: React.ReactNode;

View File

@@ -113,6 +113,8 @@ const strokeWidths = {
"9xl": 1,
};
export type IconName = keyof typeof icons;
export function Icon({
name,
icon,
@@ -120,7 +122,7 @@ export function Icon({
className,
...svgProps
}: {
name?: string;
name?: IconName;
icon?: LucideIcon;
size?: keyof typeof sizes;
className?: string;

View File

@@ -1,6 +1,6 @@
import clsx from "clsx";
import { Card } from "../atoms/Card";
import { Icon } from "../atoms/Icon";
import { Icon, IconName } from "../atoms/Icon";
import { Prose } from "./Prose";
export function FeatureCard({
@@ -11,7 +11,7 @@ export function FeatureCard({
className,
}: {
label: React.ReactNode;
icon?: string;
icon?: IconName;
explanation?: React.ReactNode;
children?: React.ReactNode;
className?: string;

View File

@@ -13,12 +13,13 @@ import { usePathname } from "next/navigation";
import { ComponentType, ReactNode, useEffect, useState } from "react";
import { isActive } from "../../utils/nav";
import { Icon } from "../atoms/Icon";
import type { IconName } from "../atoms/Icon";
import { BreadCrumb } from "../molecules/Breadcrumb";
import { SocialLinks, SocialLinksProps } from "./SocialLinks";
type NavItemProps = {
href: string;
icon?: string;
icon?: IconName;
title: string;
firstOnRight?: boolean;
newTab?: boolean;
@@ -38,7 +39,7 @@ type NavProps = {
export type NavSection = {
name: string;
content: ReactNode;
icon: string;
icon: IconName;
};
function NavItem({
@@ -134,7 +135,11 @@ export function MobileNav({
sections,
themeToggle: ThemeToggle,
}: NavProps) {
const primarySection = {
const primarySection: {
name: string;
icon: IconName;
content: ReactNode;
} = {
name: "Menu",
icon: "menu",
content: (
@@ -254,7 +259,7 @@ export function MobileNav({
onClick={() => toggle(section.name)}
key={section.name}
>
<Icon name={section.icon} size="xs" />
{section.icon && <Icon name={section.icon} size="xs" />}
{section.name}
</button>
),

View File

@@ -49,7 +49,7 @@ function highlightPlugin() {
token.content.includes("// old"),
);
const isBinnedLine = line.some((token) =>
token.content.includes("// *bin*"),
token.content.includes("// [!code --]"),
);
const isHighlighted = line.some((token) =>
token.content.includes("// *highlight*"),
@@ -70,7 +70,7 @@ function highlightPlugin() {
line
.map((token) => {
let color = isHighlighted ? "currentColor" : token.color;
return `<span style="color: ${color};${isSubduedLine ? "opacity: 0.4;" : ""}">${escape(token.content.replace("// old", "").replace("// *bin*", "").replace("// *highlight*", ""))}</span>`;
return `<span style="color: ${color};${isSubduedLine ? "opacity: 0.4;" : ""}">${escape(token.content.replace("// old", "").replace("// [!code --]", "").replace("// *highlight*", ""))}</span>`;
})
.join("") +
"</span>"

View File

@@ -331,7 +331,7 @@ This works because CoValues
<CodeGroup>
```ts
const unsub = issue.subscribe([], (updatedIssue) => console.log(updatedIssue));
const unsub = issue.subscribe({ resolve: true }, (updatedIssue) => console.log(updatedIssue));
```
</CodeGroup>
@@ -339,7 +339,7 @@ This works because CoValues
<CodeGroup>
```ts
const unsub = Issue.subscribe(issueID, me, [], (updatedIssue) => {
const unsub = Issue.subscribe(issueID, me, { resolve: true }, (updatedIssue) => {
console.log(updatedIssue);
});
```
@@ -358,7 +358,7 @@ This works because CoValues
function useCoState<V extends CoValue>(Schema: CoValueClass<V>, id?: ID<V>): V | undefined {
const [value, setValue] = useState<V>();
useEffect(() => Schema.subscribe(id, [], setValue), [id]);
useEffect(() => Schema.subscribe(id, { resolve: true }, setValue), [id]);
return value;
}
@@ -454,7 +454,7 @@ function App() { // old
const issue = useCoState(Issue, issueID); // old
// old
const createIssue = () => { // old
const group = Group.create({ owner: me });
const group = Group.create();
group.addMember("everyone", "writer");
// old
const newIssue = Issue.create( // old
@@ -543,7 +543,7 @@ function App() { // old
(window.location.search?.replace("?project=", "") || undefined) as ID<Project> | undefined
);
// old
const issue = useCoState(Issue, issueID); // *bin*
const issue = useCoState(Issue, issueID); // [!code --]
// old
const createProject = () => {
const group = Group.create();
@@ -605,6 +605,8 @@ export function ProjectComponent({ projectID }: { projectID: ID<Project> }) {
<button onClick={createAndAddIssue}>Create Issue</button>
</div>
</div>
) : project === null ? (
<div>Project not found or access denied</div>
) : (
<div>Loading project...</div>
);
@@ -620,7 +622,7 @@ Two things to note here:
- We only need to use `useCoState` on the Project, and the nested `ListOfIssues` and each `Issue` will be **automatically loaded and subscribed to when we access them.**
- However, because either the `Project`, `ListOfIssues`, or each `Issue` might not be loaded yet, we have to check for them being defined.
### Precise loading depths
### Precise resolve queries
The load-and-subscribe-on-access is a convenient way to have your rendering drive data loading (including in nested components!) and lets you quickly chuck UIs together without worrying too much about the shape of all data you'll need.
@@ -635,7 +637,7 @@ import { IssueComponent } from "./Issue.tsx"; // old
import { useCoState } from "jazz-react"; // old
// old
export function ProjectComponent({ projectID }: { projectID: ID<Project> }) {// old
const project = useCoState(Project, projectID, { issues: [{}] });
const project = useCoState(Project, projectID, { resolve: { issues: { $each: true } } });
const createAndAddIssue = () => {// old
project?.issues.push(Issue.create({
@@ -663,7 +665,7 @@ export function ProjectComponent({ projectID }: { projectID: ID<Project> }) {//
```
</CodeGroup>
The loading-depth spec `{ issues: [{}] }` means "in `Project`, load `issues` and load each item in `issues` shallowly". (Since an `Issue` doesn't have any further references, "shallowly" actually means all its properties will be available).
The resolve query `{ resolve: { issues: { $each: true } } }` means "in `Project`, load `issues` and load each item in `issues` deeply". (Since an `Issue` doesn't have any further references, "deeply" actually means all its properties will be available).
- Now, we can get rid of a lot of conditional accesses because we know that once `project` is loaded, `project.issues` and each `Issue` in it will be loaded as well.
- This also results in only one rerender and visual update when everything is loaded, which is faster (especially for long lists) and gives you more control over the loading UX.
@@ -710,7 +712,7 @@ function App() { // old
// old
const createProject = () => { // old
const group = Group.create(); // old
group.addMember("everyone", "writer"); // *bin*
group.addMember("everyone", "writer"); // [!code --]
// old
const newProject = Project.create( // old
{ // old
@@ -747,7 +749,7 @@ import { createInviteLink } from "jazz-react";
// old
export function ProjectComponent({ projectID }: { projectID: ID<Project> }) {// old
const project = useCoState(Project, projectID, { issues: [{}] }); // old
const project = useCoState(Project, projectID, { resolve: { issues: { $each: true } } }); // old
const { me } = useAccount();

View File

@@ -112,7 +112,7 @@ declare module "jazz-react" {// old
## Resolving CoValues starting at `profile` or `root`
<ContentByFramework framework="react">
To use per-user data in your app, you typically use `useAccount` somewhere in a high-level component, specifying which references to resolve using a depth-spec (see [Subscribing & deep loading](/docs/using-covalues/subscription-and-loading)).
To use per-user data in your app, you typically use `useAccount` somewhere in a high-level component, specifying which references to resolve using a resolve query (see [Subscribing & deep loading](/docs/using-covalues/subscription-and-loading)).
<CodeGroup>
{/* prettier-ignore */}
@@ -163,12 +163,12 @@ export class MyAppAccount extends Account {
profile = co.ref(MyAppProfile);
async migrate(this: MyAppAccount, creationProps?: { name: string }) {
// we specifically need to check for undefined,
// we specifically need to check for undefined,
// because the root might simply be not loaded (`null`) yet
if (this.root === undefined) {
this.root = MyAppRoot.create({
// Using a group to set the owner is always a good idea.
// This way if in the future we want to share
// This way if in the future we want to share
// this coValue we can do so easily.
myChats: ListOfChats.create([], Group.create()),
myContacts: ListOfAccounts.create([], Group.create())
@@ -218,8 +218,8 @@ export class MyAppAccount extends Account {
root: {},
});
// we specifically need to check for undefined,
// because myBookmarks might simply be not loaded (`null`) yet
// we specifically need to check for undefined,
// because myBookmarks might simply be not loaded (`null`) yet
if (root.myBookmarks === undefined) {
root.myBookmarks = ListOfBookmarks.create([], Group.create());
}
@@ -228,9 +228,9 @@ export class MyAppAccount extends Account {
```
</CodeGroup>
{/*
TODO: Add best practice: only ever add fields
{/*
TODO: Add best practice: only ever add fields
Note: explain and reassure that there will be more guardrails in the future
Note: explain and reassure that there will be more guardrails in the future
https://github.com/garden-co/jazz/issues/1160
*/}

View File

@@ -29,9 +29,9 @@ Here is what's changed in this release:
{/* prettier-ignore */}
```tsx
<JazzProvider
auth={authMethod} // removed // *bin*
peer="wss://cloud.jazz.tools/?key=you@example.com" // moved into sync // *bin*
sync={{ peer: "wss://cloud.jazz.tools/?key=you@example.com" }} // *add*
auth={authMethod} // removed // [!code --]
peer="wss://cloud.jazz.tools/?key=you@example.com" // moved into sync // [!code --]
sync={{ peer: "wss://cloud.jazz.tools/?key=you@example.com" }} // [!code ++]
>
<App />
</JazzProvider>

View File

@@ -0,0 +1,299 @@
import { CodeGroup } from '@/components/forMdx'
export const metadata = { title: "Jazz 0.12.0 - Deeply resolved data" };
# Jazz 0.12.0 - Deeply resolved data
Jazz 0.12.0 makes it easier and safer to load nested data. You can now specify exactly which nested data you want to load, and Jazz will check permissions and handle missing data gracefully. This helps catch errors earlier during development and makes your code more reliable.
## What's new?
- New resolve API for a more type-safe deep loading
- A single, consistent load option for all loading methods
- Improved permission checks on deep loading
- Easier type safety with the `Resolved` type helper
## Breaking changes
### New Resolve API
We're introducing a new resolve API for deep loading, more friendly to TypeScript, IDE autocompletion and LLMs.
**Major changes:**
1. Functions and hooks for loading now take the resolve query as an explicit nested `resolve` prop
2. Shallowly loading a collection is now done with `true` instead of `[]` or `{}`
<CodeGroup>
```tsx twoslash
// @noErrors: 2451
import { CoMap, CoList, co, Account } from "jazz-tools";
import { useAccount } from "jazz-react";
class AccountRoot extends CoMap { friends = co.ref(ListOfAccounts); }
class ListOfAccounts extends CoList.Of(co.ref(Account)) {}
class MyAppAccount extends Account { root = co.ref(AccountRoot);}
declare module "jazz-react" { interface Register { Account: MyAppAccount; } }
// ---cut-before---
// Before
// @ts-expect-error
const { me } = useAccount({ root: { friends: [] } }); // [!code --]
// After
const { me } = useAccount({ // [!code ++]
resolve: { root: { friends: true } } // [!code ++]
}); // [!code ++]
```
</CodeGroup>
3. For collections, resolving items deeply is now done with a special `$each` key.
For a `CoList`:
<CodeGroup>
```tsx twoslash
// @noErrors: 2451
import { CoList, co, ID, CoMap } from "jazz-tools";
import { useCoState } from "jazz-react";
// ---cut-before---
class Task extends CoMap { }
class ListOfTasks extends CoList.Of(co.ref(Task)) {}
const id = "co_123" as ID<Task>;
// Before
// @ts-expect-error
const tasks = useCoState(ListOfTasks, id, [{}]); // [!code --]
// After
const tasks = useCoState(ListOfTasks, id, { resolve: { $each: true } }); // [!code ++]
```
</CodeGroup>
For a `CoMap.Record`:
<CodeGroup>
```tsx twoslash
// @noErrors: 2451
import { CoMap, co, Account, ID } from "jazz-tools";
import { useCoState } from "jazz-react";
class MyAppAccount extends Account {}
const id = "co_123" as ID<UsersByUsername>;
// ---cut-before---
class UsersByUsername extends CoMap.Record(co.ref(MyAppAccount)) {}
// Before
// @ts-expect-error
const usersByUsername = useCoState(UsersByUsername, id, [{}]); // [!code --]
// After
const usersByUsername = useCoState(UsersByUsername, id, { // [!code ++]
resolve: { $each: true } // [!code ++]
}); // [!code ++]
```
</CodeGroup>
Nested loading &mdash; note how it's now less terse, but more readable:
<CodeGroup>
```tsx twoslash
// @noErrors: 2451
import { CoList, CoMap, co, Account, ID } from "jazz-tools";
import { useCoState } from "jazz-react";
const id = "co_123" as ID<ListOfTasks>;
// ---cut-before---
class Org extends CoMap {
name = co.string;
}
class Assignee extends CoMap {
name = co.string;
org = co.ref(Org);
}
class ListOfAssignees extends CoList.Of(co.ref(Assignee)) {}
class Task extends CoMap {
content = co.string;
assignees = co.ref(ListOfAssignees);
}
class ListOfTasks extends CoList.Of(co.ref(Task)) {}
// Before
// @ts-expect-error
const tasksWithAssigneesAndTheirOrgs = useCoState(ListOfTasks, id, [{ // [!code --]
assignees: [{ org: {}}]} // [!code --]
]); // [!code --]
// After
const tasksWithAssigneesAndTheirOrgs = useCoState(ListOfTasks, id, { // [!code ++]
resolve: { // [!code ++]
$each: { // [!code ++]
assignees: { // [!code ++]
$each: { org: true } // [!code ++]
} // [!code ++]
} // [!code ++]
} // [!code ++]
}); // [!code ++]
```
</CodeGroup>
It's also a lot more auto-complete friendly:
<CodeGroup>
```tsx twoslash
// @noErrors: 2451 2353 2581
import { CoList, CoMap, co, ID } from "jazz-tools";
import { useCoState } from "jazz-react";
class Org extends CoMap { name = co.string; }
class Assignee extends CoMap { org = co.ref(Org); }
class ListOfAssignees extends CoList.Of(co.ref(Assignee)) {}
class Task extends CoMap { assignees = co.ref(ListOfAssignees); }
class ListOfTasks extends CoList.Of(co.ref(Task)) {}
const id = "co_123" as ID<ListOfTasks>;
// ---cut-before---
const tasksWithAssigneesAndTheirOrgs = useCoState(ListOfTasks, id, {
resolve: {
$each: {
assignees: {
$
// ^|
}
}
}
});
```
</CodeGroup>
### A single, consistent load option
The new API works across all loading methods, and separating out the resolve query means
other options with default values are easier to manage, for example: loading a value as a specific account instead of using the implicit current account:
<CodeGroup>
```ts twoslash
// @noErrors: 2451
import { co, Account, CoMap, CoList, ID } from "jazz-tools";
class Track extends CoMap {}
class ListOfTracks extends CoList.Of(co.ref(Track)) {}
class Playlist extends CoMap { tracks = co.ref(ListOfTracks); }
const id = "co_123" as ID<Playlist>;
const otherAccount = {} as Account;
// ---cut-before---
// Before
// @ts-expect-error
Playlist.load(id, otherAccount, { // [!code --]
tracks: [], // [!code --]
}); // [!code --]
// After
Playlist.load(id, { // [!code ++]
loadAs: otherAccount, // [!code ++]
resolve: { tracks: true } // [!code ++]
}); // [!code ++]
```
</CodeGroup>
### Improved permission checks on deep loading
Now `useCoState` will return `null` when the current user lacks permissions to load requested data.
Previously, `useCoState` would return `undefined` if the current user lacked permissions, making it hard to tell if the value is loading or if it's missing.
Now `undefined` means that the value is definitely loading, and `null` means that the value is temporarily missing.
We also have implemented a more granular permission checking, where if an *optional* CoValue cannot be accessed, `useCoState` will return the data stripped of that CoValue.
**Note:** The state handling around loading and error states will become more detailed and easy-to-handle in future releases, so this is just a small step towards consistency.
<CodeGroup>
{/* prettier-ignore */}
```tsx twoslash
// @noErrors: 2451
import React from "react";
import { CoList, CoMap, co, ID } from "jazz-tools";
import { useCoState } from "jazz-react";
class Track extends CoMap {}
function TrackComponent({ track }: { track: Track }) {return ""}
// ---cut-before---
class ListOfTracks extends CoList.Of(co.optional.ref(Track)) {}
function TrackListComponent({ id }: { id: ID<ListOfTracks> }) {
// Before (ambiguous states)
// @ts-expect-error
const tracks = useCoState(ListOfTracks, id, [{}]); // [!code --]
if (tracks === undefined) return <div>Loading or access denied</div>; // [!code --]
if (tracks === null) return <div>Not found</div>; // [!code --]
// After
const tracks = useCoState(ListOfTracks, id, { resolve: { $each: true } }); // [!code ++]
if (tracks === undefined) return <div>Loading...</div>; // [!code ++]
if (tracks === null) return <div>Not found or access denied</div>; // [!code ++]
// This will only show tracks that we have access to and that are loaded.
return tracks.map(track => track && <TrackComponent track={track} />);
}
```
</CodeGroup>
The same change is applied to the load function, so now it returns `null` instead of `undefined` when the value is missing.
<CodeGroup>
```tsx twoslash
// @noErrors: 2451
import { CoMap, co, ID } from "jazz-tools";
import { useAccount } from "jazz-react";
class MyCoMap extends CoMap {}
const id = "co_123" as ID<MyCoMap>;
// ---cut-before---
// Before
// @ts-expect-error
const map = await MyCoMap.load(id);
if (map === undefined) {
throw new Error("Map not found");
}
// After
const map = await MyCoMap.load(id);
if (map === null) {
throw new Error("Map not found or access denied");
}
```
</CodeGroup>
## New Features
### The `Resolved` type helper
The new `Resolved` type can be used to define what kind of deeply loaded data you expect in your parameters, using the same resolve query syntax as the new loading APIs:
<CodeGroup>
```tsx twoslash
// @noErrors: 2451
import React from "react";
import { Resolved, CoMap, CoList, co } from "jazz-tools";
class Track extends CoMap {}
class ListOfTracks extends CoList.Of(co.ref(Track)) {}
class Playlist extends CoMap { tracks = co.ref(ListOfTracks); }
function TrackComponent({ track }: { track: Track }) {return ""}
// ---cut-before---
type PlaylistResolved = Resolved<Playlist, {
tracks: { $each: true }
}>;
function TrackListComponent({ playlist }: { playlist: PlaylistResolved }) {
// Safe access to resolved tracks
return playlist.tracks.map(track => <TrackComponent track={track} />);
}
```
</CodeGroup>

View File

@@ -25,9 +25,9 @@ So we decided to remove `createJazzRNApp` step and to provide the types through
import { JazzProvider, useDemoAuth, DemoAuthBasicUI } from "jazz-react-native";
import { MyAppAccount } from "./schema";
// Remove these lines // *bin*
const Jazz = createJazzRNApp({ AccountSchema: MyAppAccount }); // *bin*
export const { useAccount, useCoState } = Jazz; // *bin*
// Remove these lines // [!code --]
const Jazz = createJazzRNApp({ AccountSchema: MyAppAccount }); // [!code --]
export const { useAccount, useCoState } = Jazz; // [!code --]
export function JazzAndAuth({ children }: { children: React.ReactNode }) { // old
const [auth, state] = useDemoAuth(); // old
@@ -66,8 +66,8 @@ This change improves IDE intellisense support and simplifies imports:
{/* prettier-ignore */}
```tsx
// Replace local imports with "jazz-react-native" imports
import { useAccount } from "./main"; // *bin*
import { useAccount } from "jazz-react-native"; // *add*
import { useAccount } from "./main"; // [!code --]
import { useAccount } from "jazz-react-native"; // [!code ++]
export function Hello() {
const { me } = useAccount();

View File

@@ -24,9 +24,9 @@ So we decided to remove `createJazzReactApp` step and to provide the types throu
import { JazzProvider, usePasskeyAuth, PasskeyAuthBasicUI } from "jazz-react";
import { MyAppAccount } from "./schema";
// Remove these lines // *bin*
const Jazz = createJazzReactApp({ AccountSchema: MyAppAccount }); // *bin*
export const { useAccount, useCoState } = Jazz; // *bin*
// Remove these lines // [!code --]
const Jazz = createJazzReactApp({ AccountSchema: MyAppAccount }); // [!code --]
export const { useAccount, useCoState } = Jazz; // [!code --]
export function JazzAndAuth({ children }: { children: React.ReactNode }) { // old
const [passkeyAuth, passKeyState] = usePasskeyAuth({ appName }); // old
@@ -37,7 +37,7 @@ So we decided to remove `createJazzReactApp` step and to provide the types throu
<JazzProvider
auth={passkeyAuth} // old
peer="wss://cloud.jazz.tools/?key=you@example.com" // old
AccountSchema={MyAppAccount} {/* The custom Account schema is passed here */} // *add*
AccountSchema={MyAppAccount} {/* The custom Account schema is passed here */} // [!code ++]
>
{children} // old
</JazzProvider>
@@ -47,11 +47,11 @@ So we decided to remove `createJazzReactApp` step and to provide the types throu
}
// Register the Account schema so `useAccount` returns our custom `MyAppAccount`
declare module "jazz-react" { // *add*
interface Register { // *add*
Account: MyAppAccount; // *add*
} // *add*
} // *add*
declare module "jazz-react" { // [!code ++]
interface Register { // [!code ++]
Account: MyAppAccount; // [!code ++]
} // [!code ++]
} // [!code ++]
```
</CodeGroup>
@@ -65,8 +65,8 @@ This change improves IDE intellisense support and simplifies imports:
{/* prettier-ignore */}
```tsx
// Replace local imports with "jazz-react" imports
import { useAccount } from "./main"; // *bin*
import { useAccount } from "jazz-react"; // *add*
import { useAccount } from "./main"; // [!code --]
import { useAccount } from "jazz-react"; // [!code ++]
export function Hello() {
const { me } = useAccount();

View File

@@ -32,7 +32,7 @@ So we decided to remove `createJazzApp` step and to provide the types through na
</script>
<script lang="ts">
import { Provider } from '$lib/jazz'; // *bin*
import { Provider } from '$lib/jazz'; // [!code --]
import { JazzProvider } from 'jazz-svelte';
// Example configuration for authentication and peer connection
@@ -62,8 +62,8 @@ So we decided to remove `createJazzApp` step and to provide the types through na
```svelte
<script lang="ts">
import { useAccount } from '$lib/jazz'; // *bin*
import { useAccount } from 'jazz-svelte'; // *add*
import { useAccount } from '$lib/jazz'; // [!code --]
import { useAccount } from 'jazz-svelte'; // [!code ++]
const { me } = useAccount();
</script>

View File

@@ -28,10 +28,10 @@ import App from "./App.vue"; // old
import router from "./router"; // old
import { ToDoAccount } from "./schema"; // old
// Remove these lines // *bin*
const Jazz = createJazzVueApp<ToDoAccount>({ AccountSchema: ToDoAccount }); // *bin*
export const { useAccount, useCoState } = Jazz; // *bin*
const { JazzProvider } = Jazz; // *bin*
// Remove these lines // [!code --]
const Jazz = createJazzVueApp<ToDoAccount>({ AccountSchema: ToDoAccount }); // [!code --]
export const { useAccount, useCoState } = Jazz; // [!code --]
const { JazzProvider } = Jazz; // [!code --]
const RootComponent = defineComponent({ // old
name: "RootComponent", // old
@@ -86,8 +86,8 @@ This change improves IDE intellisense support and simplifies imports:
<script setup lang="ts">
// Replace local imports with "jazz-vue" imports
import { useAccount } from "./main"; // *bin*
import { useAccount } from "jazz-vue"; // *add*
import { useAccount } from "./main"; // [!code --]
import { useAccount } from "jazz-vue"; // [!code ++]
const { me, logOut } = useAccount();
</script>

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