Compare commits

..

31 Commits

Author SHA1 Message Date
Guido D'Orsi
0088aa8b25 Merge pull request #2292 from garden-co/changeset-release/main
Version Packages
2025-05-20 15:48:40 +02:00
github-actions[bot]
35a66df1e4 Version Packages 2025-05-20 12:52:45 +00:00
Guido D'Orsi
3b2fa64a82 Merge pull request #2291 from garden-co/fix/test
fix: restore custom AccountSchema support in testing utils
2025-05-20 14:46:22 +02:00
Guido D'Orsi
3d1027f278 chore: changeset 2025-05-20 14:46:04 +02:00
Guido D'Orsi
cc78386163 Merge pull request #2290 from garden-co/feat/extand-parent
feat: make possible to extend a group without having access to it
2025-05-20 14:17:56 +02:00
Guido D'Orsi
c240eed6a4 fix: Fix custom AccountSchema support in testing utils 2025-05-20 13:19:59 +02:00
Guido D'Orsi
2a9b7f5d52 test: more tests on group extend 2025-05-20 12:44:31 +02:00
Guido D'Orsi
f2fbd29de5 feat: make possible to extend a group without having access to it 2025-05-20 11:54:11 +02:00
Benjamin S. Leveritt
c960176a2a Merge pull request #2285 from garden-co/update-subscriptions-and-loading-for-zod
Update subscriptions and loading docs for 0.14
2025-05-20 06:43:46 +01:00
Benjamin S. Leveritt
fd4bae4cc1 Replace Resolved with Loaded 2025-05-19 22:16:41 +01:00
Benjamin S. Leveritt
ae32b7c19b Updates code expamples 2025-05-19 22:07:55 +01:00
Guido D'Orsi
83986c6699 Merge pull request #2270 from garden-co/changeset-release/main
Version Packages
2025-05-19 21:39:10 +02:00
github-actions[bot]
59a4e2cee3 Version Packages 2025-05-19 19:32:13 +00:00
Trisha Lim
d2a971c86c fix: update plaintext init to zod (#2283) 2025-05-19 20:29:15 +01:00
Trisha Lim
aae9ef49da improvement: org design pattern docs (#2253) 2025-05-19 19:38:05 +01:00
Trisha Lim
58c5ee5c73 form design pattern docs: emphasize not having a save button (#2241)
* form design pattern docs: emphasize not having a save button

* rewording to follow diataxis

* fix: instructions field shows undefined
2025-05-19 19:37:40 +01:00
Trisha Lim
f1d6097ee6 fix: twoslash breaks page scroll (#2267) 2025-05-19 17:37:35 +01:00
Anselm
3172a61543 Explain Loaded 2025-05-19 16:47:40 +01:00
Anselm
25324c28d9 Mention RN issue 2025-05-19 16:26:28 +01:00
Anselm
f74cb4885a Upgrade guide progress 2025-05-19 15:59:53 +01:00
Guido D'Orsi
4130213d82 Merge pull request #2271 from garden-co/fix/account-profile
fix: force sync of the group after acceptInvite
2025-05-19 15:35:04 +02:00
Guido D'Orsi
c36a26e669 test: update sync snapshots 2025-05-19 15:22:45 +02:00
Guido D'Orsi
c8b33ad7f1 fix: force sync of the group after acceptInvite 2025-05-19 15:14:41 +02:00
Benjamin S. Leveritt
a79489683e Merge pull request #2246 from joeinnes/2245-svelte-provider
add Svelte provider documentation and metadata
2025-05-19 14:09:08 +01:00
Guido D'Orsi
1251fb89b1 Merge pull request #2269 from garden-co/fix/account-profile
fix: make the profile access on Group members trigger updates correctly
2025-05-19 15:07:13 +02:00
Guido D'Orsi
cdfc10557a fix: make the profile access on Group members trigger updates correctly 2025-05-19 15:01:30 +02:00
Anselm
6e0481114c Fix homepage type errors 2025-05-19 13:50:40 +01:00
Anselm
f7e157d2f5 Make docNavigationItems js again 2025-05-19 13:35:10 +01:00
Anselm
ce83f101c7 More skeleton for the upgrade guide 2025-05-19 13:01:24 +01:00
Joe Innes
6efdfef386 Merge remote-tracking branch 'upstream/main' into 2245-svelte-provider 2025-05-15 17:03:55 +02:00
Joe Innes
6528d350ec add Svelte provider documentation and metadata 2025-05-15 17:02:40 +02:00
138 changed files with 2125 additions and 561 deletions

View File

@@ -1,5 +1,30 @@
# betterauth
## 0.1.7
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-betterauth-server-plugin@0.14.2
- jazz-inspector@0.14.2
- jazz-react@0.14.2
- jazz-react-auth-betterauth@0.14.2
- jazz-betterauth-client-plugin@0.14.2
## 0.1.6
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-betterauth-server-plugin@0.14.1
- jazz-inspector@0.14.1
- jazz-react@0.14.1
- jazz-react-auth-betterauth@0.14.1
- jazz-betterauth-client-plugin@0.14.1
## 0.1.5
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# chat-rn-expo-clerk
## 1.0.126
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-expo@0.14.2
- jazz-react-native-media-images@0.14.2
## 1.0.125
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-expo@0.14.1
- jazz-react-native-media-images@0.14.1
## 1.0.124
### Patch Changes

View File

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

View File

@@ -1,5 +1,22 @@
# chat-rn-expo
## 1.0.113
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-expo@0.14.2
## 1.0.112
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-expo@0.14.1
## 1.0.111
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn-expo",
"version": "1.0.111",
"version": "1.0.113",
"main": "index.js",
"scripts": {
"build": "tsc --noEmit && expo export -p ios",

View File

@@ -1,5 +1,25 @@
# chat-rn
## 1.0.121
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react-native@0.14.2
## 1.0.120
### Patch Changes
- Updated dependencies [c8b33ad]
- Updated dependencies [cdfc105]
- cojson@0.14.1
- jazz-tools@0.14.1
- cojson-transport-ws@0.14.1
- jazz-react-native@0.14.1
## 1.0.119
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# chat-vue
## 0.0.104
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-browser@0.14.2
- jazz-vue@0.14.2
## 0.0.103
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-browser@0.14.1
- jazz-vue@0.14.1
## 0.0.102
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# jazz-example-chat
## 0.0.202
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-inspector@0.14.2
- jazz-react@0.14.2
## 0.0.201
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-inspector@0.14.1
- jazz-react@0.14.1
## 0.0.200
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# minimal-auth-clerk
## 0.0.101
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
- jazz-react-auth-clerk@0.14.2
## 0.0.100
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
- jazz-react-auth-clerk@0.14.1
## 0.0.99
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.99",
"version": "0.0.101",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,24 @@
# file-share-svelte
## 0.0.85
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-inspector-element@0.14.2
- jazz-svelte@0.14.2
## 0.0.84
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-svelte@0.14.1
- jazz-inspector-element@0.14.1
## 0.0.83
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# jazz-tailwind-demo-auth-starter
## 0.0.41
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-inspector@0.14.2
- jazz-react@0.14.2
## 0.0.40
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-inspector@0.14.1
- jazz-react@0.14.1
## 0.0.39
### Patch Changes

View File

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

View File

@@ -1,5 +1,22 @@
# form
## 0.1.42
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.1.41
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.1.40
### Patch Changes

View File

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

View File

@@ -80,6 +80,7 @@ export const JazzAccount = co
const draft = DraftBubbleTeaOrder.create(
{
addOns: ListOfBubbleTeaAddOns.create([], account),
instructions: co.plainText().create("", account),
},
account,
);

View File

@@ -1,5 +1,22 @@
# image-upload
## 0.0.98
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.97
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.96
### Patch Changes

View File

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

View File

@@ -1,5 +1,20 @@
# jazz-example-inspector
## 0.0.151
### Patch Changes
- jazz-inspector@0.14.2
## 0.0.150
### Patch Changes
- Updated dependencies [c8b33ad]
- cojson@0.14.1
- cojson-transport-ws@0.14.1
- jazz-inspector@0.14.1
## 0.0.149
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector-app",
"private": true,
"version": "0.0.149",
"version": "0.0.151",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,22 @@
# multi-cursors
## 0.0.94
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.93
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.92
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# multiauth
## 0.0.42
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
- jazz-react-auth-clerk@0.14.2
## 0.0.41
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
- jazz-react-auth-clerk@0.14.1
## 0.0.40
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# jazz-example-musicplayer
## 0.0.123
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-inspector@0.14.2
- jazz-react@0.14.2
## 0.0.122
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-inspector@0.14.1
- jazz-react@0.14.1
## 0.0.121
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.121",
"version": "0.0.123",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,22 @@
# organization
## 0.0.94
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.93
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.92
### Patch Changes

View File

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

View File

@@ -1,5 +1,5 @@
import { useAccount, useCoState } from "jazz-react";
import { Account, Group, ID, Loaded } from "jazz-tools";
import { useAccount } from "jazz-react";
import { Account, Group, Loaded } from "jazz-tools";
import { Organization } from "../schema.ts";
export function OrganizationMembers({
@@ -12,7 +12,7 @@ export function OrganizationMembers({
{group.members.map((member) => (
<MemberItem
key={member.id}
accountId={member.account.id}
account={member.account}
role={member.role}
group={group}
/>
@@ -22,18 +22,13 @@ export function OrganizationMembers({
}
function MemberItem({
accountId,
account,
role,
group,
}: { accountId: ID<Account>; role: string; group: Group }) {
const account = useCoState(Account, accountId, {
resolve: {
profile: true,
},
});
}: { account: Account; role: string; group: Group }) {
const { me } = useAccount();
const canRemoveMember = group.myRole() === "admin" && accountId !== me?.id;
const canRemoveMember = group.myRole() === "admin" && account.id !== me?.id;
function handleRemoveMember() {
if (canRemoveMember && account) {
@@ -44,7 +39,7 @@ function MemberItem({
return (
<div className="px-4 py-5 sm:px-6 flex justify-between items-center">
<div>
<strong className="font-medium">{account?.profile.name}</strong> ({role}
<strong className="font-medium">{account.profile?.name}</strong> ({role}
)
</div>
{canRemoveMember && (

View File

@@ -1,5 +1,22 @@
# passkey-svelte
## 0.0.89
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-svelte@0.14.2
## 0.0.88
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-svelte@0.14.1
## 0.0.87
### Patch Changes

View File

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

View File

@@ -1,5 +1,22 @@
# minimal-auth-passkey
## 0.0.99
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.98
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.97
### Patch Changes

View File

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

View File

@@ -1,5 +1,22 @@
# passphrase
## 0.0.96
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.95
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.94
### Patch Changes

View File

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

View File

@@ -1,5 +1,22 @@
# jazz-password-manager
## 0.0.120
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.119
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.118
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.118",
"version": "0.0.120",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,22 @@
# jazz-example-pets
## 0.0.218
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.217
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.216
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.216",
"version": "0.0.218",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,22 @@
# reactions
## 0.0.98
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.97
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.96
### Patch Changes

View File

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

View File

@@ -1,5 +1,24 @@
# richtext-tiptap
## 0.1.11
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
- jazz-richtext-tiptap@0.1.11
## 0.1.10
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
- jazz-richtext-tiptap@0.1.10
## 0.1.9
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "richtext-tiptap",
"private": true,
"version": "0.1.9",
"version": "0.1.11",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,24 @@
# richtext
## 0.0.88
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
- jazz-richtext-prosemirror@0.1.22
## 0.0.87
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
- jazz-richtext-prosemirror@0.1.21
## 0.0.86
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "richtext",
"private": true,
"version": "0.0.86",
"version": "0.0.88",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,24 @@
# todo-vue
## 0.0.102
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-browser@0.14.2
- jazz-vue@0.14.2
## 0.0.101
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-browser@0.14.1
- jazz-vue@0.14.1
## 0.0.100
### Patch Changes

View File

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

View File

@@ -1,5 +1,22 @@
# jazz-example-todo
## 0.0.217
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react@0.14.2
## 0.0.216
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-react@0.14.1
## 0.0.215
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.215",
"version": "0.0.217",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,24 @@
# version-history
## 0.0.96
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-inspector@0.14.2
- jazz-react@0.14.2
## 0.0.95
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-inspector@0.14.1
- jazz-react@0.14.1
## 0.0.94
### Patch Changes

View File

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

View File

@@ -87,3 +87,14 @@ html.dark {
}
@import "@shikijs/twoslash/style-rich.css";
/* fix for https://github.com/garden-co/jazz/issues/2257*/
.twoslash .twoslash-popup-container {
display: none;
}
.twoslash .twoslash-hover:hover .twoslash-popup-container,
.twoslash .twoslash-error-hover:hover .twoslash-popup-container,
.twoslash .twoslash-query-presisted .twoslash-popup-container,
.twoslash .twoslash-query-line .twoslash-popup-container {
display: inline-flex;
}

View File

@@ -4,12 +4,13 @@ import { SideNav, SideNavBody, SideNavHeader } from "@/components/SideNav";
import { SideNavSection } from "@/components/SideNavSection";
import { FrameworkSelect } from "@/components/docs/FrameworkSelect";
import { docNavigationItems } from "@/content/docs/docNavigationItems";
import { DocNavigationSection } from "@/content/docs/docNavigationItemsTypes";
import { useFramework } from "@/lib/use-framework";
import React from "react";
export function DocNav() {
const framework = useFramework();
const items = docNavigationItems.map((headerItem) => {
const items = (docNavigationItems as DocNavigationSection[]).map((headerItem) => {
return {
...headerItem,
items: headerItem.items

View File

@@ -2,6 +2,7 @@ import {
docNavigationItems,
flatItemsWithNavLinks,
} from "@/content/docs/docNavigationItems";
import { DocNavigationItem } from "@/content/docs/docNavigationItemsTypes";
import { Icon } from "@garden-co/design-system/src/components/atoms/Icon";
import { Separator } from "@garden-co/design-system/src/components/atoms/Separator";
import Link from "next/link";
@@ -18,7 +19,7 @@ export function PreviousNextLinks({ slug, framework }: PreviousNextLinksProps) {
? `/docs/${framework}/${slug.join("/")}`
: `/docs/${framework}`;
return currentPath === itemPath;
});
}) as DocNavigationItem;
if (
currentItem?.excludeFromNavigation ||

View File

@@ -4,22 +4,22 @@ export const metadata = {
import { CodeGroup } from "@/components/forMdx";
# Creating and updating CoValues in a form
# How to write autosaving forms to create and update CoValues
Normally, we implement forms using
[the onSubmit handler](https://react.dev/reference/react-dom/components/form#handle-form-submission-on-the-client),
or by making [a controlled form with useState](https://christinakozanian.medium.com/building-controlled-forms-with-usestate-in-react-f9053ad255a0),
or by using special libraries like [react-hook-form](https://www.react-hook-form.com).
This guide shows you a simple and powerful way to implement forms for creating and updating CoValues.
In Jazz, we can do something simpler and more powerful, because CoValues give us reactive,
persisted state which we can use to directly edit live objects, and represent auto-saved drafts.
We'll build:
1. An update form that saves changes as you make them, removing the need for a save button.
2. A create form that autosaves your changes into a draft, so you can come back to it later.
[See the full example here.](https://github.com/garden-co/jazz/tree/main/examples/form)
**Note**: If you do need a save button on your update form, this guide is not for you. Another option
is to use [react-hook-form](https://www.react-hook-form.com), which you can see in [this example](https://github.com/garden-co/jazz/tree/main/examples/password-manager).
## Updating a CoValue
To update a CoValue, we simply assign the new value directly as changes happen. These changes are synced to the server, so
we don't need to handle form submissions either.
To update a CoValue, we simply assign the new value directly as changes happen. These changes are synced to the server.
<CodeGroup>
```tsx
@@ -31,7 +31,7 @@ we don't need to handle form submissions either.
```
</CodeGroup>
This means we can write update forms in fewer lines of code.
It's that simple!
## Creating a CoValue

View File

@@ -4,10 +4,9 @@ export const metadata = {
import { CodeGroup } from "@/components/forMdx";
# Sharing data through Organizations
# How to share data between users through Organizations
Organizations are a way to share a set of data between users.
Different apps have different names for this concept, such as "teams" or "workspaces".
This guide shows you how to share a set of CoValues between users. Different apps have different names for this concept, such as "teams" or "workspaces".
We'll use the term Organization.
@@ -104,12 +103,16 @@ This schema now allows users to create `Organization`s and add `Project`s to the
[See the schema for the example app here.](https://github.com/garden-co/jazz/blob/main/examples/organization/src/schema.ts)
## Adding other users to an Organization
## Adding members to an Organization
To give users access to an `Organization`, you can either send them an invite link, or
add their `Account` manually.
Here are different ways to add members to an `Organization`.
### Adding users through invite links
- Send users an invite link.
- [The user requests to join.](/docs/groups/sharing#requesting-invites)
This guide and the example app show you the first method.
### Adding members through invite links
Here's how you can generate an [invite link](/docs/groups/sharing#invites).
@@ -180,6 +183,7 @@ export function AcceptInvitePage() {
```
</CodeGroup>
### Adding users through their Account ID
## Further reading
...more on this coming soon
- [Allowing users to request an invite to join a Group](/docs/groups/sharing#requesting-invites)
- [Groups as permission scopes](/docs/groups/intro#adding-group-members-by-id)

View File

@@ -1,27 +1,5 @@
import { Framework } from "../framework";
export type DoneStatus =
| number // represents percentage done
| Partial<Record<Framework, number>>;
export type DocNavigationItem = {
name: string;
href: string;
done: DoneStatus;
framework?: Framework;
next?: DocNavigationItem | null;
previous?: DocNavigationItem | null;
excludeFromNavigation?: boolean;
};
export type DocNavigationSection = {
name: string;
items: DocNavigationItem[];
collapse?: boolean;
prefix?: string;
};
export const docNavigationItems: DocNavigationSection[] = [
/** @satisfies {DocNavigationSection[]} */
export const docNavigationItems = [
{
// welcome to jazz
name: "Getting started",
@@ -81,6 +59,7 @@ export const docNavigationItems: DocNavigationSection[] = [
react: 100,
"react-native": 100,
"react-native-expo": 100,
svelte: 100,
},
},
],
@@ -159,7 +138,7 @@ export const docNavigationItems: DocNavigationSection[] = [
name: "0.9.2 - Local persistence on React Native Expo",
href: "/docs/upgrade/react-native-local-persistence",
done: 100,
framework: Framework.ReactNativeExpo,
framework: "react-native-expo",
excludeFromNavigation: true,
},
// {
@@ -308,7 +287,7 @@ export const docNavigationItems: DocNavigationSection[] = [
name: "Design patterns",
items: [
{
name: "Form",
name: "Autosaving forms",
href: "/docs/design-patterns/form",
done: 100,
},

View File

@@ -0,0 +1,22 @@
import { Framework } from "../framework";
export type DoneStatus =
| number // represents percentage done
| Partial<Record<Framework, number>>;
export type DocNavigationItem = {
name: string;
href: string;
done: DoneStatus;
framework?: Framework;
next?: DocNavigationItem | null;
previous?: DocNavigationItem | null;
excludeFromNavigation?: boolean;
};
export type DocNavigationSection = {
name: string;
items: DocNavigationItem[];
collapse?: boolean;
prefix?: string;
};

View File

@@ -0,0 +1,162 @@
export const metadata = {
description:
"Configure your JazzProvider - the core component that connects your app to Jazz, handling sync, storage, account schema, and auth.",
};
import { CodeGroup } from "@/components/forMdx";
# Providers
`<JazzProvider />` is the core component that connects your Svelte application to Jazz. It handles:
- **Data Synchronization**: Manages connections to peers and the Jazz cloud
- **Local Storage**: Persists data locally between app sessions
- **Schema Types**: Provides APIs for the [AccountSchema](/docs/schemas/accounts-and-migrations)
- **Authentication**: Connects your authentication system to Jazz
Our [File Share example app](https://github.com/garden-co/jazz/blob/main/examples/file-share-svelte/src/routes/%2Blayout.svelte) provides an implementation of JazzProvider with authentication and real-time data sync.
## Setting up the Provider
The `<JazzProvider />` accepts several configuration options:
<CodeGroup>
```svelte
<!-- src/routes/+layout.svelte -->
<script lang="ts" module>
// Register the Account schema so `useAccount` returns our custom `MyAppAccount`
declare module 'jazz-svelte' {
interface Register {
Account: MyAppAccount;
}
}
</script>
<script lang="ts">
import { JazzProvider } from "jazz-svelte";
import { MyAppAccount } from "$lib/schema";
let { children } = $props();
</script>
<JazzProvider
sync={{
peer: "wss://cloud.jazz.tools/?key=your-api-key",
when: "always" // When to sync: "always", "never", or "signedUp"
}}
AccountSchema={MyAppAccount}
>
{@render children()}
</JazzProvider>
```
</CodeGroup>
## Provider Options
### Sync Options
The `sync` property configures how your application connects to the Jazz network:
<CodeGroup>
```ts twoslash
// @filename: src/routes/layout.svelte
// ---cut---
import { type SyncConfig } from "jazz-tools";
const syncConfig: SyncConfig = {
// Connection to Jazz Cloud or your own sync server
peer: "wss://cloud.jazz.tools/?key=your-api-key",
// When to sync: "always" (default), "never", or "signedUp"
when: "always",
}
```
</CodeGroup>
See [Authentication States](/docs/authentication/authentication-states#controlling-sync-for-different-authentication-states) for more details on how the `when` property affects synchronization based on authentication state.
### Account Schema
The `AccountSchema` property defines your application's account structure:
<CodeGroup>
```svelte
<!-- src/routes/+layout.svelte -->>
<script lang="ts" module>
// Register the Account schema so `useAccount` returns our custom `MyAppAccount`
declare module 'jazz-svelte' {
interface Register {
Account: MyAppAccount;
}
}
</script>
<script lang="ts">
import { JazzProvider } from "jazz-svelte";
import { MyAppAccount } from "$lib/schema";
let { children } = $props();
</script>
<JazzProvider
sync={syncConfig}
AccountSchema={MyAppAccount}
>
{@render children()}
</JazzProvider>
```
</CodeGroup>
### Additional Options
The provider accepts these additional options:
<CodeGroup>
```svelte
<!-- src/routes/+layout.svelte -->
<script lang="ts">
import { JazzProvider } from "jazz-svelte";
import { syncConfig } from "$lib/syncConfig";
let { children } = $props();
// Enable guest mode for account-less access
const guestMode = false;
// Default name for new user profiles
const defaultProfileName = "New User";
// Handle user logout
const onLogOut = () => {
console.log("User logged out");
};
// Handle anonymous account data when user logs in to existing account
const onAnonymousAccountDiscarded = (account) => {
console.log("Anonymous account discarded", account.id);
// Migrate data here
return Promise.resolve();
};
</script>
<JazzProvider
sync={syncConfig}
{guestMode}
{defaultProfileName}
{onLogOut}
{onAnonymousAccountDiscarded}
>
{@render children}
</JazzProvider>
```
</CodeGroup>
See [Authentication States](/docs/authentication/authentication-states) for more information on authentication states, guest mode, and handling anonymous accounts.
## Authentication
`<JazzProvider />` works with various authentication methods to enable users to access their data across multiple devices. For a complete guide to authentication, see our [Authentication Overview](/docs/authentication/overview).
## Need Help?
If you have questions about configuring the Jazz Provider for your specific use case, [join our Discord community](https://discord.gg/utDMjHYg42) for help.

View File

@@ -1,19 +1,207 @@
import { ContentByFramework } from '@/components/forMdx'
import { ContentByFramework, CodeGroup } from '@/components/forMdx'
# Jazz 0.14.0 Introducing Zod-based schemas
**Note:** This is a huge release with many breaking changes.
We're excited to move from our own schema syntax to using Zod v4.
This is the first step in a series of releases to make Jazz more familiar and to make CoValues look more like regular data structures.
**Note: This is a huge release that we're still cleaning up and documenting.**
<small className="leading-tight">
We're still in the process of:
- updating all our docs
- double-checking all our framework bindings
- particularly React Native might still have issues
- completing all the details of this upgrade guide
</small>
Thanks for your patience!
**Note: React Native is currently broken based on an [underlying Zod v4 issue](https://github.com/colinhacks/zod/issues/4148).**
If you see something broken, please let us know on [Discord](https://discord.gg/utDMjHYg42) and check back in a couple hours.
Thanks for your patience!
## Overview:
TODO (check back in a couple minutes)
So far, Jazz has relied on our own idiosyncratic schema definition syntax where you had to extend classes and be careful to use `co.ref` for references.
<CodeGroup>
```ts
// BEFORE
import { co, CoMap, CoList, CoPlainText, ImageDefinition } from "jazz-tools";
export class Message extends CoMap {
text = co.ref(CoPlainText);
image = co.optional.ref(ImageDefinition);
important = co.boolean;
}
export class Chat extends CoList.Of(co.ref(Message)) {}
```
</CodeGroup>
While this had certain ergonomic benefits it relied on unclean hacks to work.
In addition, many of our adopters expressed a preference for avoiding class syntax, and LLMs consistently expected to be able to use Zod.
For this reason, we completely overhauled how you define and use CoValue schemas:
<CodeGroup>
```ts twoslash
// AFTER
import { co, z } from "jazz-tools";
export const Message = co.map({
text: co.plainText(),
image: z.optional(co.image()),
important: z.boolean(),
});
export const Chat = co.list(Message);
```
</CodeGroup>
## Major breaking changes
### Schema definitions
You now define CoValue schemas using two new exports from `jazz-tools`:
- a new `co` definer that mirrors Zod's object/record/array syntax to define CoValue types
- `co.map()`, `co.record()`, `co.list()`, `co.feed()`
- `co.account()`, `co.profile()`
- `co.plainText()`, `co.richText()`,
- `co.fileStream()`, `co.image()`
- see the updated [Defining CoValue Schemas](/docs/schemas/covalues)
- `z` re-exported from Zod v4
- primitives like `z.string()`, `z.number()`, `z.literal()`
- **note**: additional constraints like `z.min()` and `z.max()` are not yet enforced, we'll add validation in future releases
- complex types like `z.object()` and `z.array()` to define JSON-like fields without internal collaboration
- combinators like `z.optional()` and `z.discriminatedUnion()`
- these also work on CoValue types!
- see the updated [Docs on Primitive Fields](/docs/schemas/covalues#primitive-fields),
[Docs on Optional References](/docs/schemas/covalues#optional-references)
and [Docs on Unions of CoMaps](/docs/schemas/covalues#unions-of-comaps-declaration)
Similar to Zod v4's new object syntax, recursive and mutually recursive types are now [much easier to express](/docs/react/schemas/covalues#recursive-references).
### How to pass loaded CoValues
Calls to `useCoState()` work just the same, but they return a slightly different type than before.
And while you can still read from the type just as before...
<CodeGroup>
```tsx twoslash
import React from "react";
// ---cut---
import { z, co } from "jazz-tools";
import { useCoState } from "jazz-react";
const Pet = co.map({
name: z.string(),
age: z.number(),
});
const Person = co.map({
name: z.string(),
age: z.number(),
pets: co.list(Pet),
});
function MyComponent({ id }: { id: string }) {
const person = useCoState(Person, id);
return person && <div>{person.name}</div>;
}
```
</CodeGroup>
...you now need to specify the type differently **when passing CoValues as a parameter** or
**whenever you need to refer to the type of a loaded CoValue instance:**
<CodeGroup>
```tsx twoslash
import React from "react";
// ---cut---
import { z, co, Loaded } from "jazz-tools"; // [!code ++]
import { useCoState } from "jazz-react";
const Pet = co.map({
name: z.string(),
age: z.number(),
});
const Person = co.map({
name: z.string(),
age: z.number(),
pets: co.list(Pet),
});
function MyComponent({ id }: { id: string }) {
const person = useCoState(Person, id);
return person && <PersonName person={person} />;
}
function PersonName({ person }: { person: Loaded<typeof Person> }) { // [!code ++]
return <div>{person.name}</div>;
}
```
</CodeGroup>
`Loaded` can also take a second argument to specify the loading depth of the expected CoValue, mirroring the `resolve` options for `useCoState`, `load`, `subscribe`, etc.
<CodeGroup>
```tsx twoslash
import React from "react";
// ---cut---
import { z, co, Loaded } from "jazz-tools";
import { useCoState } from "jazz-react";
const Pet = co.map({
name: z.string(),
age: z.number(),
});
const Person = co.map({
name: z.string(),
age: z.number(),
pets: co.list(Pet),
});
function MyComponent({ id }: { id: string }) {
const personWithPets = useCoState(Person, id, {
resolve: { pets: { $each: true } } // [!code ++]
});
return personWithPets && <PersonAndFirstPetName person={personWithPets} />;
}
function PersonAndFirstPetName({ person }: {
person: Loaded<typeof Person, { pets: { $each: true } }> // [!code ++]
}) {
return <div>{person.name} & {person.pets[0].name}</div>;
}
```
</CodeGroup>
### Defining migrations
TODO
### Defining Schema helper methods
TODO
### Removing AccountSchema registration
TODO
## Minor breaking changes
### `_refs` and `_edits` are now potentially null
TODO
### `members` and `by` now return basic `Account`s

View File

@@ -1,6 +1,6 @@
import { CodeGroup, ContentByFramework } from "@/components/forMdx";
export const metadata = {
export const metadata = {
description: "Learn how to subscribe to CoValues, specify loading depths, and handle loading states and inaccessible data."
};
@@ -26,27 +26,26 @@ If you're using React in your project, check out our [React hooks](/docs/react/u
<CodeGroup>
```ts twoslash
import { ID, CoMap, coField } from "jazz-tools";
const taskId = "co_123" as ID<Task>;
import { co, z } from "jazz-tools";
const taskId = "co_123";
// ---cut-before---
class Task extends CoMap {
title = coField.string;
description = coField.string;
status = coField.literal("todo", "in-progress", "completed");
assignedTo = coField.optional.string;
}
const Task = co.map({
title: z.string(),
description: z.string(),
status: z.literal(["todo", "in-progress", "completed"]),
assignedTo: z.optional(z.string()),
});
// ...
// Subscribe to a Task by ID
const unsubscribe = Task.subscribe(taskId, (updatedTask) => {
const unsubscribe = Task.subscribe(taskId, {}, (updatedTask) => {
console.log("Task updated:", updatedTask.title);
console.log("New status:", updatedTask.status);
});
// Clean up when you're done
unsubscribe();
```
</CodeGroup>
@@ -54,14 +53,14 @@ If you already have a CoValue instance, you can subscribe to it by calling its `
<CodeGroup>
```ts twoslash
import { ID, CoMap, coField } from "jazz-tools";
import { co, z } from "jazz-tools";
class Task extends CoMap {
title = coField.string;
description = coField.string;
status = coField.literal("todo", "in-progress", "completed");
assignedTo = coField.optional.string;
}
const Task = co.map({
title: z.string(),
description: z.string(),
status: z.literal(["todo", "in-progress", "completed"]),
assignedTo: z.optional(z.string()),
});
const otherProps = {} as any;
// ---cut-before---
const task = Task.create({
@@ -88,22 +87,20 @@ Jazz provides a `useCoState` hook that provides a convenient way to subscribe to
<CodeGroup>
```tsx twoslash
import React from "react";
import { ID, CoMap, coField, CoList } from "jazz-tools";
class Task extends CoMap {
title = coField.string;
status = coField.literal("todo", "in-progress", "completed");
}
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
}
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
import { co, z, ID, Loaded } from "jazz-tools";
const Task = co.map({
title: z.string(),
status: z.literal(["todo", "in-progress", "completed"]),
});
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
});
// ---cut-before---
import { useCoState } from "jazz-react";
function GardenPlanner({ projectId }: { projectId: ID<Project> }) {
function GardenPlanner({ projectId }: { projectId: string }) {
// Subscribe to a project and its tasks
const project = useCoState(Project, projectId, {
resolve: {
@@ -125,7 +122,7 @@ function GardenPlanner({ projectId }: { projectId: ID<Project> }) {
);
}
function TaskList({ tasks }: { tasks: Task[] }) {
function TaskList({ tasks }: { tasks: Loaded<typeof Task>[] }) {
return (
<ul>
{tasks.map((task) => (
@@ -152,37 +149,38 @@ Like `useCoState`, you can specify a resolve query to also subscribe to CoValues
<CodeGroup>
```tsx twoslash
import React from "react";
import { ID, CoMap, coField, CoList, Account } from "jazz-tools";
class Task extends CoMap {
title = coField.string;
}
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
}
class ListOfProjects extends CoList.Of(coField.ref(Project)) {}
import { co, z } from "jazz-tools";
const Task = co.map({
title: z.string(),
});
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
});
const AccountRoot = co.map({
myProjects: co.list(Project),
});
const MyAppAccount = co.account({
root: AccountRoot,
profile: co.profile(),
});
class AccountRoot extends CoMap {
myProjects = coField.ref(ListOfProjects);
}
class MyAppAccount extends Account {
root = coField.ref(AccountRoot);
}
declare module "jazz-react" { interface Register { Account: MyAppAccount; } }
// ---cut-before---
import { useAccount } from "jazz-react";
function ProjectList() {
const { me } = useAccount({
const { me } = useAccount(MyAppAccount, {
resolve: {
profile: true,
root: {
myProjects: {
$each: {
tasks: true
}
}
tasks: true,
},
},
},
},
});
@@ -191,17 +189,20 @@ function ProjectList() {
return <div>Loading...</div>;
}
return <div>
<h1>{me.profile.name}'s projects</h1>
<ul>
{me.root.myProjects.map(project => (
<li key={project.id}>
{project.name} ({project.tasks.length} tasks)
</li>
))}
</ul>
</div>
return (
<div>
<h1>{me.profile.name}'s projects</h1>
<ul>
{me.root.myProjects.map((project) => (
<li key={project.id}>
{project.name} ({project.tasks.length} tasks)
</li>
))}
</ul>
</div>
);
}
```
</CodeGroup>
@@ -219,14 +220,14 @@ This allows you to handle loading, error, and success states in your application
<CodeGroup>
```ts twoslash
import { ID, CoMap, coField } from "jazz-tools";
class Task extends CoMap {
title = coField.string;
}
import { co, z, Loaded } from "jazz-tools";
const Task = co.map({
title: z.string(),
});
const taskId = "co_123" as ID<Task>;
const taskId = "co_123";
// ---cut-before---
Task.subscribe(taskId, (task) => {
Task.subscribe(taskId, {}, (task: Loaded<typeof Task>) => {
if (task === undefined) {
console.log("Task is loading...");
} else if (task === null) {
@@ -248,27 +249,25 @@ Resolve queries let you declare exactly which references to load and how deep to
<CodeGroup>
```ts twoslash
import { ID, CoMap, coField, CoList } from "jazz-tools";
const projectId = "co_123" as ID<Project>;
import { co, z, CoListSchema } from "jazz-tools";
const projectId = "co_123";
// ---cut-before---
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
owner = coField.ref(TeamMember);
}
const TeamMember = co.map({
name: z.string(),
});
class Task extends CoMap {
title = coField.string;
subtasks = coField.ref(ListOfTasks);
assignee = coField.optional.ref(TeamMember);
}
const Task = co.map({
title: z.string(),
assignee: z.optional(TeamMember),
get subtasks(): CoListSchema<typeof Task> { return co.list(Task) },
});
class TeamMember extends CoMap {
name = coField.string;
}
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
owner: TeamMember,
});
// Load just the project, not its references
const project = await Project.load(projectId);
@@ -349,28 +348,26 @@ When loading data with references, the load operation will fail if one of the re
When a user tries to load a reference they don't have access to:
<CodeGroup>
```typescript twoslash
import { ID, CoMap, coField, CoList } from "jazz-tools";
```ts twoslash
import { co, z, CoListSchema } from "jazz-tools";
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
owner = coField.ref(TeamMember);
}
const TeamMember = co.map({
name: z.string(),
});
class Task extends CoMap {
title = coField.string;
subtasks = coField.ref(ListOfTasks);
assignee = coField.optional.ref(TeamMember);
}
const Task = co.map({
title: z.string(),
assignee: z.optional(TeamMember),
get subtasks(): CoListSchema<typeof Task> { return co.list(Task) },
});
class TeamMember extends CoMap {
name = coField.string;
}
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
owner: TeamMember,
});
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
const taskId = "co_123" as ID<Task>;
const taskId = "co_123";
// ---cut-before---
// If assignee is not accessible to the user:
@@ -390,28 +387,26 @@ The behavior is the same for optional and required references.
When a list contains references to items the user can't access:
<CodeGroup>
```typescript twoslash
import { ID, CoMap, coField, CoList } from "jazz-tools";
```ts twoslash
import { co, z, CoListSchema } from "jazz-tools";
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
owner = coField.ref(TeamMember);
}
const TeamMember = co.map({
name: z.string(),
});
class Task extends CoMap {
title = coField.string;
subtasks = coField.ref(ListOfTasks);
assignee = coField.optional.ref(TeamMember);
}
const Task = co.map({
title: z.string(),
assignee: z.optional(TeamMember),
get subtasks(): CoListSchema<typeof Task> { return co.list(Task) },
});
class TeamMember extends CoMap {
name = coField.string;
}
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
owner: TeamMember,
});
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
const projectId = "co_123" as ID<Project>;
const projectId = "co_123";
// ---cut-before---
// If any item in the list is not accessible:
const project = await Project.load(projectId, {
@@ -428,28 +423,26 @@ If any item in a list is inaccessible to the user, the entire load operation wil
When trying to load an object with an inaccessible reference without directly resolving it:
<CodeGroup>
```typescript twoslash
import { ID, CoMap, coField, CoList } from "jazz-tools";
```ts twoslash
import { co, z, CoListSchema } from "jazz-tools";
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
owner = coField.ref(TeamMember);
}
const TeamMember = co.map({
name: z.string(),
});
class Task extends CoMap {
title = coField.string;
subtasks = coField.ref(ListOfTasks);
assignee = coField.optional.ref(TeamMember);
}
const Task = co.map({
title: z.string(),
assignee: z.optional(TeamMember),
get subtasks(): CoListSchema<typeof Task> { return co.list(Task) },
});
class TeamMember extends CoMap {
name = coField.string;
}
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
owner: TeamMember,
});
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
const projectId = "co_123" as ID<Project>;
const projectId = "co_123";
// ---cut-before---
const project = await Project.load(projectId, {
resolve: true
@@ -474,21 +467,24 @@ This is especially useful when in your app access to these items might be revoke
This way the inaccessible items are replaced with `null` in the returned list.
<CodeGroup>
```typescript twoslash
import { ID, CoMap, CoList, co, Group, Account } from "jazz-tools";
import { assert } from "vitest";
```ts twoslash
import { co, z, CoListSchema, Group } from "jazz-tools";
import { createJazzTestAccount } from "jazz-tools/testing";
class Person extends CoMap {
name = co.string;
}
class Friends extends CoList.Of(co.ref(Person)) {}
const me = await createJazzTestAccount();
const account2 = await createJazzTestAccount();
const privateGroup = Group.create();
const publicGroup = Group.create();
const me = {} as unknown as Account;
const Person = co.map({
name: z.string(),
});
const Friends = co.list(Person);
const privateGroup = Group.create({ owner: account2 });
const publicGroup = Group.create({ owner: me });
// ---cut-before---
const source = Friends.create(
const source = co.list(Person).create(
[
Person.create(
{
@@ -506,7 +502,7 @@ const source = Friends.create(
publicGroup,
);
const friends = await Friends.load(source.id, {
const friends = await co.list(Person).load(source.id, {
resolve: {
$each: { $onError: null }
},
@@ -515,47 +511,47 @@ const friends = await Friends.load(source.id, {
// Thanks to $onError catching the errors, the list is loaded
// because we have access to friends
friends // => Friends
assert(friends);
console.log(friends); // Person[]
// Jane is null because we lack access rights
// and we have used $onError to catch the error on the list items
friends[0] // => null
console.log(friends?.[0]); // null
// Alice is not null because we have access
// the type is nullable because we have used $onError
friends[1] // => Person
console.log(friends?.[1]); // Person
```
</CodeGroup>
The `$onError` works as a "catch" clause option to block any error in the resolved childs.
The `$onError` works as a "catch" clause option to block any error in the resolved children.
<CodeGroup>
```typescript twoslash
import { ID, CoMap, CoList, co, Group, Account } from "jazz-tools";
import { assert } from "vitest";
```ts twoslash
import { createJazzTestAccount } from "jazz-tools/testing";
const me = await createJazzTestAccount();
const account2 = await createJazzTestAccount();
class Person extends CoMap {
name = co.string;
dog = co.ref(Dog);
}
class Dog extends CoMap {
name = co.string;
}
class Friends extends CoList.Of(co.ref(Person)) {}
import { Group, co, z } from "jazz-tools";
class User extends CoMap {
name = co.string;
friends = co.ref(Friends);
}
const Dog = co.map({
name: z.string(),
});
const privateGroup = Group.create();
const publicGroup = Group.create();
const me = {} as unknown as Account;
const Person = co.map({
name: z.string(),
dog: Dog,
});
const User = co.map({
name: z.string(),
friends: co.list(Person),
});
const privateGroup = Group.create({ owner: account2 });
const publicGroup = Group.create({ owner: me });
// ---cut-before---
const source = Friends.create(
const source = co.list(Person).create(
[
Person.create(
{
@@ -571,47 +567,47 @@ const source = Friends.create(
publicGroup,
);
const friends = await Friends.load(source.id, {
const friends = await co.list(Person).load(source.id, {
resolve: {
$each: { dog: true, $onError: null }
},
loadAs: me,
});
assert(friends);
// Jane is null because we don't have access to Rex
// and we have used $onError to catch the error on the list items
friends[0] // => null
console.log(friends?.[0]); // null
```
</CodeGroup>
We can actually use `$onError` everywhere in the resolve query, so we can use it to catch the error on dog:
<CodeGroup>
```typescript twoslash
import { ID, CoMap, CoList, co, Group, Account } from "jazz-tools";
import { assert } from "vitest";
```ts twoslash
import { createJazzTestAccount } from "jazz-tools/testing";
const me = await createJazzTestAccount();
const account2 = await createJazzTestAccount();
class Person extends CoMap {
name = co.string;
dog = co.ref(Dog);
}
class Dog extends CoMap {
name = co.string;
}
class Friends extends CoList.Of(co.ref(Person)) {}
import { co, z, Group } from "jazz-tools";
class User extends CoMap {
name = co.string;
friends = co.ref(Friends);
}
const Dog = co.map({
name: z.string(),
});
const privateGroup = Group.create();
const publicGroup = Group.create();
const me = {} as unknown as Account;
const Person = co.map({
name: z.string(),
dog: Dog,
});
const source = Friends.create(
const User = co.map({
name: z.string(),
friends: co.list(Person),
});
const privateGroup = Group.create({ owner: account2 });
const publicGroup = Group.create({ owner: me });
const source = co.list(Person).create(
[
Person.create(
{
@@ -628,71 +624,71 @@ const source = Friends.create(
);
// ---cut-before---
const friends = await Friends.load(source.id, {
const friends = await co.list(Person).load(source.id, {
resolve: {
$each: { dog: { $onError: null } }
},
loadAs: me,
});
assert(friends);
// Jane now is not-nullable at type level because
// we have moved $onError down to the dog field
//
// This also means that if we don't have access to Jane
// the entire friends list will be null
friends[0] // => Person
console.log(friends?.[0]); // => Person
// Jane's dog is null because we don't have access to Rex
// and we have used $onError to catch the error
friends[0].dog // => null
console.log(friends?.[0]?.dog); // => null
```
</CodeGroup>
## Type Safety with Resolved Type
## Type Safety with Loaded Type
Jazz provides the `Resolved` type to help you define and enforce the structure of deeply loaded data in your application. This makes it easier to ensure that components receive the data they expect with proper TypeScript validation.
Jazz provides the `Loaded` type to help you define and enforce the structure of deeply loaded data in your application. This makes it easier to ensure that components receive the data they expect with proper TypeScript validation.
The `Resolved` type is especially useful when passing data between components, as it guarantees that all necessary nested data has been loaded:
The `Loaded` type is especially useful when passing data between components, as it guarantees that all necessary nested data has been loaded:
<ContentByFramework framework="react">
<CodeGroup>
```tsx twoslash
import { CoListSchema, Loaded, co, z } from "jazz-tools";
import React from "react";
import { ID, CoMap, coField, CoList, Resolved } from "jazz-tools";
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
owner = coField.ref(TeamMember);
}
const TeamMember = co.map({
name: z.string(),
});
class Task extends CoMap {
title = coField.string;
subtasks = coField.ref(ListOfTasks);
assignee = coField.optional.ref(TeamMember);
}
class TeamMember extends CoMap {
name = coField.string;
}
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
const Task = co.map({
title: z.string(),
assignee: z.optional(TeamMember),
get subtasks(): CoListSchema<typeof Task> {
return co.list(Task);
},
});
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
owner: TeamMember,
});
// ---cut-before---
// Define a type that includes resolved nested data
type ProjectWithTasks = Resolved<Project, {
tasks: { $each: true }
}>;
// Define a type that includes loaded nested data
type ProjectWithTasks = Loaded<
typeof Project,
{
tasks: { $each: true };
}
>;
// Component that expects a fully resolved project
// Component that expects a fully loaded project
function TaskList({ project }: { project: ProjectWithTasks }) {
// TypeScript knows tasks are loaded, so this is type-safe
return (
<ul>
{project.tasks.map(task => (
{project.tasks.map((task) => (
<li key={task.id}>{task.title}</li>
))}
</ul>
@@ -700,26 +696,30 @@ function TaskList({ project }: { project: ProjectWithTasks }) {
}
// For more complex resolutions
type FullyLoadedProject = Resolved<Project, {
tasks: {
$each: {
subtasks: true,
assignee: true
}
},
owner: true
}>;
type FullyLoadedProject = Loaded<
typeof Project,
{
tasks: {
$each: {
subtasks: true;
assignee: true;
};
};
owner: true;
}
>;
// Function that requires deeply resolved data
// Function that requires deeply loaded data
function processProject(project: FullyLoadedProject) {
// Safe access to all resolved properties
// Safe access to all loaded properties
console.log(`Project ${project.name} owned by ${project.owner.name}`);
project.tasks.forEach(task => {
project.tasks.forEach((task) => {
console.log(`Task: ${task.title}, Assigned to: ${task.assignee?.name}`);
console.log(`Subtasks: ${task.subtasks.length}`);
});
}
```
</CodeGroup>
</ContentByFramework>
@@ -727,59 +727,62 @@ function processProject(project: FullyLoadedProject) {
<ContentByFramework framework="vanilla">
<CodeGroup>
```ts twoslash
import { ID, CoMap, coField, CoList, Resolved } from "jazz-tools";
import { CoListSchema, Loaded, co, z } from "jazz-tools";
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
owner = coField.ref(TeamMember);
}
const TeamMember = co.map({
name: z.string(),
});
class Task extends CoMap {
title = coField.string;
subtasks = coField.ref(ListOfTasks);
assignee = coField.optional.ref(TeamMember);
}
class TeamMember extends CoMap {
name = coField.string;
}
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
const Task = co.map({
title: z.string(),
assignee: z.optional(TeamMember),
get subtasks(): CoListSchema<typeof Task> {
return co.list(Task);
},
});
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
owner: TeamMember,
});
// ---cut-before---
// Define a type that includes resolved nested data
type ProjectWithTasks = Resolved<Project, {
tasks: { $each: true }
}>;
// Define a type that includes loaded nested data
type ProjectWithTasks = Loaded<
typeof Project,
{
tasks: { $each: true };
}
>;
// Function that expects resolved data
async function taskList({project}: {project: ProjectWithTasks}) {
// Function that expects loaded data
async function taskList({ project }: { project: ProjectWithTasks }) {
// TypeScript knows tasks are loaded, so this is type-safe
return project.tasks
.map(task => task.title)
.join(`\n - `);
return project.tasks.map((task) => task.title).join(`\n - `);
}
// For more complex resolutions
type FullyLoadedProject = Resolved<Project, {
tasks: {
$each: {
title: true,
subtasks: true,
assignee: true
}
},
owner: true
}>;
type FullyLoadedProject = Loaded<
typeof Project,
{
tasks: {
$each: {
title: true;
subtasks: true;
assignee: true;
};
};
owner: true;
}
>;
// Function that requires deeply resolved data
// Function that requires deeply loaded data
function processProject(project: FullyLoadedProject) {
// Safe access to all resolved properties
// Safe access to all loaded properties
console.log(`Project ${project.name} owned by ${project.owner.name}`);
project.tasks.forEach(task => {
project.tasks.forEach((task) => {
console.log(`Task: ${task.title}, Assigned to: ${task.assignee?.name}`);
console.log(`Subtasks: ${task.subtasks.length}`);
});
@@ -788,7 +791,7 @@ function processProject(project: FullyLoadedProject) {
</CodeGroup>
</ContentByFramework>
Using the `Resolved` type helps catch errors at compile time rather than runtime, ensuring that your components and functions receive data with the proper resolution depth. This is especially useful for larger applications where data is passed between many components.
Using the `Loaded` type helps catch errors at compile time rather than runtime, ensuring that your components and functions receive data with the proper resolution depth. This is especially useful for larger applications where data is passed between many components.
## Ensuring Data is Loaded
@@ -796,29 +799,29 @@ Sometimes you need to make sure data is loaded before proceeding with an operati
<CodeGroup>
```ts twoslash
import { ID, CoMap, coField, CoList, Resolved } from "jazz-tools";
import { CoListSchema, Loaded, co, z } from "jazz-tools";
class Project extends CoMap {
name = coField.string;
tasks = coField.ref(ListOfTasks);
owner = coField.ref(TeamMember);
}
const TeamMember = co.map({
name: z.string(),
});
class Task extends CoMap {
title = coField.string;
status = coField.literal("todo", "in-progress", "completed");
subtasks = coField.ref(ListOfTasks);
assignee = coField.optional.ref(TeamMember);
}
const Task = co.map({
title: z.string(),
status: z.literal(["todo", "in-progress", "completed"]),
assignee: z.string().optional(),
get subtasks(): CoListSchema<typeof Task> {
return co.list(Task);
},
});
class TeamMember extends CoMap {
name = coField.string;
}
class ListOfTasks extends CoList.Of(coField.ref(Task)) {}
const Project = co.map({
name: z.string(),
tasks: co.list(Task),
owner: TeamMember,
});
// ---cut-before---
async function completeAllTasks(projectId: ID<Project>) {
async function completeAllTasks(projectId: string) {
// Ensure the project is loaded
const project = await Project.load(projectId, { resolve: true });
if (!project) return;
@@ -827,13 +830,13 @@ async function completeAllTasks(projectId: ID<Project>) {
const loadedProject = await project.ensureLoaded({
resolve: {
tasks: {
$each: true
}
}
$each: true,
},
},
});
// Now we can safely access and modify tasks
loadedProject.tasks.forEach(task => {
loadedProject.tasks.forEach((task) => {
task.status = "completed";
});
}
@@ -848,4 +851,4 @@ async function completeAllTasks(projectId: ID<Project>) {
2. **Use framework integrations**: They handle subscription lifecycle automatically
3. **Clean up subscriptions**: Always store and call the unsubscribe function when you're done
4. **Handle all loading states**: Check for undefined (loading), null (not found), and success states
5. **Use the Resolved type**: Add compile-time type safety for components that require specific resolution patterns
5. **Use the Loaded type**: Add compile-time type safety for components that require specific resolution patterns

View File

@@ -1,4 +1,4 @@
import { docNavigationItems } from "../../content/docs/docNavigationItems.ts";
import { docNavigationItems } from "../../content/docs/docNavigationItems.js";
// Transform docNavigationItems into the format we need
function transformNavItems() {

View File

@@ -1,5 +1,13 @@
# cojson-storage-indexeddb
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- cojson@0.14.1
- cojson-storage@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "cojson-storage-indexeddb",
"version": "0.14.0",
"version": "0.14.1",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",

View File

@@ -1,5 +1,13 @@
# cojson-storage-sqlite
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- cojson@0.14.1
- cojson-storage@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,13 +1,13 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.14.0",
"version": "0.14.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",
"dependencies": {
"better-sqlite3": "^11.7.0",
"cojson": "workspace:0.14.0",
"cojson": "workspace:0.14.1",
"cojson-storage": "workspace:*"
},
"devDependencies": {

View File

@@ -1,5 +1,12 @@
# cojson-storage
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- cojson@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "cojson-storage",
"version": "0.14.0",
"version": "0.14.1",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",

View File

@@ -1,5 +1,12 @@
# cojson-transport-nodejs-ws
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- cojson@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-transport-ws",
"type": "module",
"version": "0.14.0",
"version": "0.14.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",

View File

@@ -1,5 +1,11 @@
# cojson
## 0.14.1
### Patch Changes
- c8b33ad: Force sync of the group after acceptInvite
## 0.14.0
### Minor Changes

View File

@@ -25,7 +25,7 @@
},
"type": "module",
"license": "MIT",
"version": "0.14.0",
"version": "0.14.1",
"devDependencies": {
"@opentelemetry/sdk-metrics": "^2.0.0",
"typescript": "catalog:"

View File

@@ -451,7 +451,9 @@ export class RawGroup<
}
getCurrentReadKeyId() {
if (this.myRole() === "writeOnly") {
const myRole = this.myRole();
if (myRole === "writeOnly") {
const accountId = this.core.node.getCurrentAgent().id;
const key = this.get(`writeKeyFor_${accountId}`) as KeyID;
@@ -469,6 +471,16 @@ export class RawGroup<
return key;
}
if (!myRole) {
const accountId = this.core.node.getCurrentAgent().id;
const key = this.get(`writeKeyFor_${accountId}`) as KeyID;
if (key) {
return key;
}
}
return this.get("readKey");
}
@@ -670,22 +682,24 @@ export class RawGroup<
);
}
const value = role === "inherit" ? "extend" : role;
this.set(`parent_${parent.id}`, value, "trusting");
parent.set(`child_${this.id}`, "extend", "trusting");
if (
parent.myRole() !== "admin" &&
parent.myRole() !== "writer" &&
parent.myRole() !== "reader" &&
parent.myRole() !== "writeOnly"
) {
throw new Error(
"To extend a group, the current account must be a member of the parent group",
// Create a writeOnly key in the parent group to be able to reveal the current child key to the parent group
parent.internalCreateWriteOnlyKeyForMember(
this.core.node.getCurrentAgent().id,
this.core.node.getCurrentAgent().currentAgentID(),
);
}
const value = role === "inherit" ? "extend" : role;
this.set(`parent_${parent.id}`, value, "trusting");
parent.set(`child_${this.id}`, "extend", "trusting");
const { id: parentReadKeyID, secret: parentReadKeySecret } =
parent.core.getCurrentReadKey();
if (!parentReadKeySecret) {

View File

@@ -548,6 +548,7 @@ export class LocalNode {
group.processNewTransactions();
group.core.notifyUpdate("immediate");
this.syncManager.requestCoValueSync(group.core);
}
/** @internal */

View File

@@ -345,18 +345,6 @@ function determineValidTransactionsForGroup(
validTransactions.push({ txID: { sessionID, txIndex }, tx });
continue;
} else if (isChildExtension(change.key)) {
if (
memberState[transactor] !== "admin" &&
memberState[transactor] !== "writer" &&
memberState[transactor] !== "reader" &&
memberState[transactor] !== "writeOnly"
) {
logPermissionError(
"Only admins, writers, readers and writeOnly can set child extensions",
);
continue;
}
validTransactions.push({ txID: { sessionID, txIndex }, tx });
continue;
} else if (isWriteKeyForMember(change.key)) {

View File

@@ -157,6 +157,29 @@ describe("extend", () => {
expect(childGroup.roleOf(node2.accountID)).toEqual(undefined);
});
test("should be possible to extend a group without having membership in the parent group", async () => {
const { node1, node2, node3 } = await createThreeConnectedNodes(
"server",
"server",
"server",
);
const parentGroup = node1.node.createGroup();
const childGroup = node2.node.createGroup();
const alice = await loadCoValueOrFail(node1.node, node3.accountID);
parentGroup.addMember(alice, "writer");
const parentGroupOnNode2 = await loadCoValueOrFail(
node2.node,
parentGroup.id,
);
childGroup.extend(parentGroupOnNode2);
expect(childGroup.roleOf(alice.id)).toBe("writer");
});
});
describe("unextend", () => {
@@ -191,6 +214,78 @@ describe("unextend", () => {
expect(childGroup.roleOf(alice.id)).toBe(undefined);
});
test("should work when the account has no access to the parent group but owns the writeKey", async () => {
const { node1, node2, node3 } = await createThreeConnectedNodes(
"server",
"server",
"server",
);
const parentGroup = node1.node.createGroup();
const childGroup = node2.node.createGroup();
const alice = await loadCoValueOrFail(node1.node, node3.accountID);
parentGroup.addMember(alice, "writer");
const parentGroupOnNode2 = await loadCoValueOrFail(
node2.node,
parentGroup.id,
);
childGroup.extend(parentGroupOnNode2);
expect(childGroup.roleOf(alice.id)).toBe("writer");
// `childGroup` no longer has `parentGroup`'s members
await childGroup.revokeExtend(parentGroup);
expect(childGroup.roleOf(alice.id)).toBe(undefined);
const map = childGroup.createMap();
map.set("test", "Hello!");
const mapOnAlice = await loadCoValueOrFail(node3.node, map.id);
expect(mapOnAlice.get("test")).toEqual(undefined);
});
test("should work when the account has no access to the parent group and not owns the writeKey", async () => {
const {
node1: bobNode,
node2: johnNode,
node3: aliceNode,
} = await createThreeConnectedNodes("server", "server", "server");
const parentGroup = bobNode.node.createGroup();
const childGroup = johnNode.node.createGroup();
const parentGroupOnJohn = await loadCoValueOrFail(
johnNode.node,
parentGroup.id,
);
childGroup.extend(parentGroupOnJohn);
const bob = await loadCoValueOrFail(johnNode.node, bobNode.accountID);
const alice = await loadCoValueOrFail(johnNode.node, aliceNode.accountID);
childGroup.addMember(alice, "admin");
const childGroupOnAlice = await loadCoValueOrFail(
aliceNode.node,
childGroup.id,
);
// `childGroup` no longer has `parentGroup`'s members
await childGroupOnAlice.revokeExtend(parentGroup);
expect(childGroupOnAlice.roleOf(bob.id)).toBe(undefined);
const map = childGroupOnAlice.createMap();
map.set("test", "Hello!");
const mapOnBob = await loadCoValueOrFail(bobNode.node, map.id);
expect(mapOnBob.get("test")).toEqual(undefined);
});
test("should do nothing if applied to a group that is not extended", async () => {
const { node1, node2, node3 } = await createThreeConnectedNodes(
"server",

View File

@@ -323,6 +323,10 @@ describe("Group invites", () => {
expect(groupOnMemberNode.roleOf(member.accountID)).toEqual("reader");
await waitFor(() => {
expect(group.roleOf(member.accountID)).toEqual("reader");
});
// Verify read access is restored
const personOnMemberNode = await loadCoValueOrFail(member.node, person.id);
expect(personOnMemberNode.get("name")).toEqual("John Doe");

View File

@@ -1982,40 +1982,6 @@ test("Writers, readers and writeOnly can set child extensions", () => {
expect(groupAsReader.get(`child_${childGroup.id}`)).toEqual("extend");
});
test("Invitees can not set child extensions", () => {
const { group, node } = newGroupHighLevel();
const childGroup = node.createGroup();
const adminInvite = createAccountInNode(node);
const writerInvite = createAccountInNode(node);
const readerInvite = createAccountInNode(node);
group.addMember(adminInvite, "adminInvite");
group.addMember(writerInvite, "writerInvite");
group.addMember(readerInvite, "readerInvite");
const groupAsAdminInvite = expectGroup(
group.core.contentInClonedNodeWithDifferentAccount(adminInvite),
);
groupAsAdminInvite.set(`child_${childGroup.id}`, "extend", "trusting");
expect(groupAsAdminInvite.get(`child_${childGroup.id}`)).toBeUndefined();
const groupAsWriterInvite = expectGroup(
group.core.contentInClonedNodeWithDifferentAccount(writerInvite),
);
groupAsWriterInvite.set(`child_${childGroup.id}`, "extend", "trusting");
expect(groupAsWriterInvite.get(`child_${childGroup.id}`)).toBeUndefined();
const groupAsReaderInvite = expectGroup(
group.core.contentInClonedNodeWithDifferentAccount(readerInvite),
);
groupAsReaderInvite.set(`child_${childGroup.id}`, "extend", "trusting");
expect(groupAsReaderInvite.get(`child_${childGroup.id}`)).toBeUndefined();
});
test("Member roles are inherited by child groups (except invites)", () => {
const { group, node, admin } = newGroupHighLevel();
const parentGroup = node.createGroup();

View File

@@ -56,6 +56,10 @@ describe("invitations sync", () => {
"invite-consumer -> server | KNOWN Group sessions: header/5",
"server -> invite-consumer | CONTENT Map header: true new: After: 0 New: 1",
"invite-consumer -> server | KNOWN Map sessions: header/1",
"invite-consumer -> server | CONTENT Group header: false new: After: 0 New: 2",
"server -> invite-consumer | KNOWN Group sessions: header/7",
"server -> invite-provider | CONTENT Group header: false new: After: 0 New: 2",
"invite-provider -> server | KNOWN Group sessions: header/7",
]
`);
});
@@ -104,6 +108,10 @@ describe("invitations sync", () => {
"invite-consumer -> server | KNOWN Group sessions: header/7",
"server -> invite-consumer | CONTENT Map header: true new: After: 0 New: 1",
"invite-consumer -> server | KNOWN Map sessions: header/1",
"invite-consumer -> server | CONTENT Group header: false new: After: 0 New: 2",
"server -> invite-consumer | KNOWN Group sessions: header/9",
"server -> invite-provider | CONTENT Group header: false new: After: 0 New: 2",
"invite-provider -> server | KNOWN Group sessions: header/9",
]
`);
});
@@ -148,15 +156,15 @@ describe("invitations sync", () => {
"invite-consumer -> server | LOAD ParentGroup sessions: empty",
"server -> invite-consumer | CONTENT ParentGroup header: true new: After: 0 New: 6",
"invite-consumer -> server | KNOWN ParentGroup sessions: header/6",
"invite-consumer -> server | LOAD Map sessions: empty",
"server -> invite-consumer | CONTENT Group header: true new: After: 0 New: 5",
"invite-consumer -> server | KNOWN Group sessions: header/5",
"server -> invite-consumer | CONTENT Map header: true new: After: 0 New: 1",
"invite-consumer -> server | CONTENT ParentGroup header: false new: After: 0 New: 2",
"server -> invite-consumer | KNOWN ParentGroup sessions: header/8",
"server -> invite-provider | CONTENT ParentGroup header: false new: After: 0 New: 2",
"invite-consumer -> server | KNOWN Map sessions: header/1",
"invite-consumer -> server | LOAD Map sessions: empty",
"invite-provider -> server | KNOWN ParentGroup sessions: header/8",
"server -> invite-consumer | CONTENT Group header: true new: After: 0 New: 5",
"invite-consumer -> server | KNOWN Group sessions: header/5",
"server -> invite-consumer | CONTENT Map header: true new: After: 0 New: 1",
"invite-consumer -> server | KNOWN Map sessions: header/1",
]
`);
});

View File

@@ -1,5 +1,26 @@
# jazz-auth-betterauth
## 0.14.2
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-browser@0.14.2
- jazz-betterauth-client-plugin@0.14.2
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- Updated dependencies [cdfc105]
- cojson@0.14.1
- jazz-tools@0.14.1
- jazz-browser@0.14.1
- jazz-betterauth-client-plugin@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-auth-betterauth",
"version": "0.14.0",
"version": "0.14.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,24 @@
# jazz-auth-clerk
## 0.14.2
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-browser@0.14.2
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- Updated dependencies [cdfc105]
- cojson@0.14.1
- jazz-tools@0.14.1
- jazz-browser@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,14 +1,14 @@
{
"name": "jazz-auth-clerk",
"version": "0.14.0",
"version": "0.14.2",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:0.14.0",
"jazz-browser": "workspace:0.14.0",
"jazz-tools": "workspace:0.14.0"
"cojson": "workspace:0.14.1",
"jazz-browser": "workspace:0.14.2",
"jazz-tools": "workspace:0.14.2"
},
"scripts": {
"format-and-lint": "biome check .",

View File

@@ -1,5 +1,17 @@
# jazz-betterauth-client-plugin
## 0.14.2
### Patch Changes
- jazz-betterauth-server-plugin@0.14.2
## 0.14.1
### Patch Changes
- jazz-betterauth-server-plugin@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-betterauth-client-plugin",
"version": "0.14.0",
"version": "0.14.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,24 @@
# jazz-betterauth-server-plugin
## 0.14.2
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-browser@0.14.2
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- Updated dependencies [cdfc105]
- cojson@0.14.1
- jazz-tools@0.14.1
- jazz-browser@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-betterauth-server-plugin",
"version": "0.14.0",
"version": "0.14.2",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,22 @@
# jazz-browser-media-images
## 0.14.2
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-browser@0.14.2
## 0.14.1
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-browser@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser-media-images",
"version": "0.14.0",
"version": "0.14.2",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -8,8 +8,8 @@
"dependencies": {
"@types/image-blob-reduce": "^4.1.1",
"image-blob-reduce": "^4.1.0",
"jazz-browser": "workspace:0.14.0",
"jazz-tools": "workspace:0.14.0",
"jazz-browser": "workspace:0.14.2",
"jazz-tools": "workspace:0.14.2",
"pica": "^9.0.1"
},
"scripts": {

View File

@@ -1,5 +1,24 @@
# jazz-browser
## 0.14.2
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- Updated dependencies [cdfc105]
- cojson@0.14.1
- jazz-tools@0.14.1
- cojson-storage-indexeddb@0.14.1
- cojson-transport-ws@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser",
"version": "0.14.0",
"version": "0.14.2",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@@ -1,5 +1,29 @@
# jazz-browser
## 0.14.2
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-auth-clerk@0.14.2
- jazz-react-core@0.14.2
- jazz-react-native-core@0.14.2
## 0.14.1
### Patch Changes
- Updated dependencies [c8b33ad]
- Updated dependencies [cdfc105]
- cojson@0.14.1
- jazz-tools@0.14.1
- cojson-transport-ws@0.14.1
- jazz-auth-clerk@0.14.1
- jazz-react-core@0.14.1
- jazz-react-native-core@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-expo",
"version": "0.14.0",
"version": "0.14.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",

View File

@@ -1,5 +1,22 @@
# jazz-inspector-element
## 0.14.2
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-inspector@0.14.2
## 0.14.1
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-inspector@0.14.1
## 0.14.0
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-inspector-element",
"version": "0.14.0",
"version": "0.14.2",
"type": "module",
"main": "./dist/main.js",
"types": "./dist/main.d.ts",

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