Compare commits

..

10 Commits

Author SHA1 Message Date
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
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
f379fcc176 Merge pull request #1730 from garden-co/changeset-release/main
Version Packages
2025-03-27 11:49:13 +01:00
github-actions[bot]
d6ea4d4662 Version Packages 2025-03-27 10:37:27 +00:00
Giordano Ricci
9d0c9dc6ea chore: update @opentelemetry/api dependency 2025-03-25 15:20:34 +00:00
236 changed files with 3813 additions and 4301 deletions

View File

@@ -1,6 +0,0 @@
---
"jazz-tools": minor
"cojson": minor
---
Check CoValue access permissions when loading

View File

@@ -1,6 +0,0 @@
---
"jazz-inspector": patch
"jazz-inspector-app": patch
---
fix: CoFeed and FileStream are showing as CoStream

View File

@@ -1,5 +0,0 @@
---
"jazz-tools": minor
---
Implement new API for deep loading

View File

@@ -1,6 +0,0 @@
---
"jazz-react-core": patch
"jazz-tools": patch
---
Bugfix: Trigger a single update when loading a locally available list of items

View File

@@ -1,5 +0,0 @@
---
"jazz-tools": minor
---
The .load function now returns `null` on error

View File

@@ -1,5 +0,0 @@
---
"cojson": minor
---
Return the EVERYONE role if the account is not direct a member of the group

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 +0,0 @@
---
"jazz-vue": patch
---
Fix types compilation for useAccount

View File

@@ -1,5 +1,25 @@
# chat-rn-clerk
## 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, { resolve: { $each: true } });
const loadedChat = useCoState(Chat, chat?.id, [{}]);
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.89",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",

View File

@@ -1,5 +1,21 @@
# chat-rn
## 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.85",
"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, { resolve: { $each: true } });
const loadedChat = useCoState(Chat, chatId, [{}]);
const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});

View File

@@ -1,5 +1,23 @@
# chat-vue
## 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.70",
"private": true,
"type": "module",
"scripts": {

View File

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

View File

@@ -1,5 +1,26 @@
# jazz-example-chat
## 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.167",
"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,24 @@
# minimal-auth-clerk
## 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.66",
"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.11.8",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"

View File

@@ -1,5 +1,21 @@
# file-share-svelte
## 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.50",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,22 @@
# jazz-tailwind-demo-auth-starter
## 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.6",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,22 @@
# form
## 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.8",
"type": "module",
"scripts": {
"dev": "vite",

View File

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

View File

@@ -2,7 +2,7 @@ import { useAccount } from "jazz-react";
export function DraftIndicator() {
const { me } = useAccount({
resolve: { root: { draft: true } },
root: { draft: {} },
});
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({
resolve: { root: { orders: true } },
root: { orders: [] },
});
return (

View File

@@ -1,5 +1,22 @@
# image-upload
## 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.64",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,28 @@
# jazz-example-inspector
## 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.117",
"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.11.8",
"cojson-transport-ws": "workspace:0.11.8",
"hash-slash": "workspace:0.2.2",
"lucide-react": "^0.274.0",
"react": "^18.3.1",

View File

@@ -0,0 +1,18 @@
# multi-cursors
## 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.60",
"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, { resolve: true });
const cursors = useCoState(CursorFeed, cursorFeedID, []);
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 === null) {
if (group === undefined) {
const group = Group.create({
owner: me,
});
@@ -35,16 +35,15 @@ export async function loadCursorContainer(
group?.id as ID<Group>,
);
const cursorContainer = await CursorContainer.load(cursorContainerID, {
resolve: {
cursorFeed: true,
},
cursorFeed: [],
});
if (cursorContainer === null) {
if (cursorContainer === undefined) {
console.log("Global cursors does not exist, creating...");
const cursorContainer = CursorContainer.create(
{
cursorFeed: CursorFeed.create([], group),
cursorFeed: CursorFeed.create([], {
owner: group,
}),
},
{
owner: group,

View File

@@ -1,5 +1,24 @@
# multiauth
## 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.7",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,26 @@
# jazz-example-musicplayer
## 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.88",
"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.11.8",
"jazz-tools": "workspace:0.11.8",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,22 @@
# organization
## 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.60",
"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({ resolve: { root: { organizations: true } } });
const { me } = useAccount({ root: { organizations: [] } });
const onAccept = (organizationId: ID<Organization>) => {
if (me?.root?.organizations) {
Organization.load(organizationId).then((organization) => {
Organization.load(organizationId, me, []).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({
resolve: { root: { organizations: true } },
root: { organizations: [{}] },
});
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({
resolve: { root: { draftOrganization: true } },
root: { draftOrganization: {} },
});
return (

View File

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

View File

@@ -8,7 +8,7 @@ import { OrganizationForm } from "./OrganizationForm.tsx";
export function CreateOrganization() {
const { me } = useAccount({
resolve: { root: { draftOrganization: true, organizations: true } },
root: { draftOrganization: {}, organizations: [] },
});
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({
resolve: { root: { organizations: { $each: true } } },
root: { organizations: [{}] },
});
const navigate = useNavigate();

View File

@@ -1,5 +1,17 @@
# passkey-svelte
## 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.54",
"type": "module",
"private": true,
"scripts": {

View File

@@ -1,5 +1,22 @@
# minimal-auth-passkey
## 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.65",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,22 @@
# passphrase
## 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.62",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,22 @@
# jazz-password-manager
## 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.86",
"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.11.8",
"jazz-tools": "workspace:0.11.8",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.41.5",

View File

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

View File

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

View File

@@ -1,5 +1,22 @@
# jazz-example-pets
## 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.184",
"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.11.8",
"jazz-tools": "workspace:0.11.8",
"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.11.8",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2",

View File

@@ -1,5 +1,22 @@
# reactions
## 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.64",
"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,23 @@
# todo-vue
## 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.68",
"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,9 +72,7 @@ import { Folder, FolderList, ToDoItem, ToDoList } from "../schema";
const { me } = useAccount();
const computedFoldersId = computed(() => me.value?.root?.folders?.id);
const folders = useCoState(FolderList, computedFoldersId, {
resolve: { $each: { items: true } },
});
const folders = useCoState(FolderList, computedFoldersId, [{ items: [{}] }]);
const selectedFolder = ref<Folder>();
const newFolderName = ref("");

View File

@@ -1,5 +1,22 @@
# jazz-example-todo
## 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.183",
"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.11.8",
"jazz-tools": "workspace:0.11.8",
"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({
resolve: { root: { projects: { $each: true } } },
root: { projects: [{}] },
});
const navigate = useNavigate();

View File

@@ -1,5 +1,26 @@
# version-history
## 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.61",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -4,9 +4,7 @@ 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, {
resolve: { issues: { $each: true } },
});
const project = useCoState(Project, projectID, { issues: [{}] });
if (!project) return;

View File

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

View File

@@ -331,7 +331,7 @@ This works because CoValues
<CodeGroup>
```ts
const unsub = issue.subscribe({ resolve: true }, (updatedIssue) => console.log(updatedIssue));
const unsub = issue.subscribe([], (updatedIssue) => console.log(updatedIssue));
```
</CodeGroup>
@@ -339,7 +339,7 @@ This works because CoValues
<CodeGroup>
```ts
const unsub = Issue.subscribe(issueID, me, { resolve: true }, (updatedIssue) => {
const unsub = Issue.subscribe(issueID, me, [], (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, { resolve: true }, setValue), [id]);
useEffect(() => Schema.subscribe(id, [], 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();
const group = Group.create({ owner: me });
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); // [!code --]
const issue = useCoState(Issue, issueID); // *bin*
// old
const createProject = () => {
const group = Group.create();
@@ -605,8 +605,6 @@ 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>
);
@@ -622,7 +620,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 resolve queries
### Precise loading depths
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.
@@ -637,7 +635,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, { resolve: { issues: { $each: true } } });
const project = useCoState(Project, projectID, { issues: [{}] });
const createAndAddIssue = () => {// old
project?.issues.push(Issue.create({
@@ -665,7 +663,7 @@ export function ProjectComponent({ projectID }: { projectID: ID<Project> }) {//
```
</CodeGroup>
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).
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).
- 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.
@@ -712,7 +710,7 @@ function App() { // old
// old
const createProject = () => { // old
const group = Group.create(); // old
group.addMember("everyone", "writer"); // [!code --]
group.addMember("everyone", "writer"); // *bin*
// old
const newProject = Project.create( // old
{ // old
@@ -749,7 +747,7 @@ import { createInviteLink } from "jazz-react";
// old
export function ProjectComponent({ projectID }: { projectID: ID<Project> }) {// old
const project = useCoState(Project, projectID, { resolve: { issues: { $each: true } } }); // old
const project = useCoState(Project, projectID, { issues: [{}] }); // 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 resolve query (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 depth-spec (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 // [!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 ++]
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*
>
<App />
</JazzProvider>

View File

@@ -1,299 +0,0 @@
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 // [!code --]
const Jazz = createJazzRNApp({ AccountSchema: MyAppAccount }); // [!code --]
export const { useAccount, useCoState } = Jazz; // [!code --]
// Remove these lines // *bin*
const Jazz = createJazzRNApp({ AccountSchema: MyAppAccount }); // *bin*
export const { useAccount, useCoState } = Jazz; // *bin*
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"; // [!code --]
import { useAccount } from "jazz-react-native"; // [!code ++]
import { useAccount } from "./main"; // *bin*
import { useAccount } from "jazz-react-native"; // *add*
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 // [!code --]
const Jazz = createJazzReactApp({ AccountSchema: MyAppAccount }); // [!code --]
export const { useAccount, useCoState } = Jazz; // [!code --]
// Remove these lines // *bin*
const Jazz = createJazzReactApp({ AccountSchema: MyAppAccount }); // *bin*
export const { useAccount, useCoState } = Jazz; // *bin*
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 */} // [!code ++]
AccountSchema={MyAppAccount} {/* The custom Account schema is passed here */} // *add*
>
{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" { // [!code ++]
interface Register { // [!code ++]
Account: MyAppAccount; // [!code ++]
} // [!code ++]
} // [!code ++]
declare module "jazz-react" { // *add*
interface Register { // *add*
Account: MyAppAccount; // *add*
} // *add*
} // *add*
```
</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"; // [!code --]
import { useAccount } from "jazz-react"; // [!code ++]
import { useAccount } from "./main"; // *bin*
import { useAccount } from "jazz-react"; // *add*
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'; // [!code --]
import { Provider } from '$lib/jazz'; // *bin*
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'; // [!code --]
import { useAccount } from 'jazz-svelte'; // [!code ++]
import { useAccount } from '$lib/jazz'; // *bin*
import { useAccount } from 'jazz-svelte'; // *add*
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 // [!code --]
const Jazz = createJazzVueApp<ToDoAccount>({ AccountSchema: ToDoAccount }); // [!code --]
export const { useAccount, useCoState } = Jazz; // [!code --]
const { JazzProvider } = Jazz; // [!code --]
// Remove these lines // *bin*
const Jazz = createJazzVueApp<ToDoAccount>({ AccountSchema: ToDoAccount }); // *bin*
export const { useAccount, useCoState } = Jazz; // *bin*
const { JazzProvider } = Jazz; // *bin*
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"; // [!code --]
import { useAccount } from "jazz-vue"; // [!code ++]
import { useAccount } from "./main"; // *bin*
import { useAccount } from "jazz-vue"; // *add*
const { me, logOut } = useAccount();
</script>

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