jazz-tools 0.19.11 → 0.19.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +51 -51
- package/CHANGELOG.md +22 -0
- package/dist/browser/createBrowserContext.d.ts +1 -5
- package/dist/browser/createBrowserContext.d.ts.map +1 -1
- package/dist/browser/index.js +124 -47
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/provideBrowserLockSession/BrowserSessionProvider.d.ts +12 -0
- package/dist/browser/provideBrowserLockSession/BrowserSessionProvider.d.ts.map +1 -0
- package/dist/browser/provideBrowserLockSession/BrowserSessionProvider.test.d.ts +2 -0
- package/dist/browser/provideBrowserLockSession/BrowserSessionProvider.test.d.ts.map +1 -0
- package/dist/browser/provideBrowserLockSession/SessionIDStorage.d.ts +6 -0
- package/dist/browser/provideBrowserLockSession/SessionIDStorage.d.ts.map +1 -0
- package/dist/browser/provideBrowserLockSession/index.d.ts +4 -0
- package/dist/browser/provideBrowserLockSession/index.d.ts.map +1 -0
- package/dist/{chunk-HX5S6W5E.js → chunk-GAPMDNJY.js} +492 -108
- package/dist/chunk-GAPMDNJY.js.map +1 -0
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/inspector/{chunk-C6BJPHBQ.js → chunk-YQNK5Y7B.js} +47 -35
- package/dist/inspector/chunk-YQNK5Y7B.js.map +1 -0
- package/dist/inspector/{custom-element-GJVBPZES.js → custom-element-KYV64IOC.js} +47 -35
- package/dist/inspector/{custom-element-GJVBPZES.js.map → custom-element-KYV64IOC.js.map} +1 -1
- package/dist/inspector/index.js +1 -1
- package/dist/inspector/register-custom-element.js +1 -1
- package/dist/inspector/standalone.js +1 -1
- package/dist/inspector/tests/utils/transactions-changes.test.d.ts +2 -0
- package/dist/inspector/tests/utils/transactions-changes.test.d.ts.map +1 -0
- package/dist/inspector/utils/transactions-changes.d.ts +13 -13
- package/dist/inspector/utils/transactions-changes.d.ts.map +1 -1
- package/dist/react/index.js +4 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/provider.d.ts.map +1 -1
- package/dist/react-core/index.js +2 -2
- package/dist/react-core/index.js.map +1 -1
- package/dist/react-native/index.js +45 -13
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native-core/ReactNativeSessionProvider.d.ts +11 -0
- package/dist/react-native-core/ReactNativeSessionProvider.d.ts.map +1 -0
- package/dist/react-native-core/index.js +45 -13
- package/dist/react-native-core/index.js.map +1 -1
- package/dist/react-native-core/platform.d.ts +2 -8
- package/dist/react-native-core/platform.d.ts.map +1 -1
- package/dist/react-native-core/provider.d.ts.map +1 -1
- package/dist/react-native-core/tests/ReactNativeSessionProvider.test.d.ts +2 -0
- package/dist/react-native-core/tests/ReactNativeSessionProvider.test.d.ts.map +1 -0
- package/dist/testing.js +4 -3
- package/dist/testing.js.map +1 -1
- package/dist/tools/coValues/account.d.ts.map +1 -1
- package/dist/tools/coValues/coFeed.d.ts +2 -2
- package/dist/tools/coValues/coFeed.d.ts.map +1 -1
- package/dist/tools/coValues/coList.d.ts +1 -2
- package/dist/tools/coValues/coList.d.ts.map +1 -1
- package/dist/tools/coValues/coMap.d.ts.map +1 -1
- package/dist/tools/coValues/coVector.d.ts.map +1 -1
- package/dist/tools/coValues/group.d.ts +5 -1
- package/dist/tools/coValues/group.d.ts.map +1 -1
- package/dist/tools/coValues/interfaces.d.ts +2 -1
- package/dist/tools/coValues/interfaces.d.ts.map +1 -1
- package/dist/tools/exports.d.ts +2 -2
- package/dist/tools/exports.d.ts.map +1 -1
- package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
- package/dist/tools/implementation/createContext.d.ts +21 -11
- package/dist/tools/implementation/createContext.d.ts.map +1 -1
- package/dist/tools/implementation/schema.d.ts +14 -6
- package/dist/tools/implementation/schema.d.ts.map +1 -1
- package/dist/tools/implementation/schemaUtils.d.ts +1 -1
- package/dist/tools/implementation/schemaUtils.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/runtimeConverters/schemaFieldToCoFieldDef.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaPermissions.d.ts +99 -0
- package/dist/tools/implementation/zodSchema/schemaPermissions.d.ts.map +1 -0
- package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +11 -0
- package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +11 -0
- package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +15 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +10 -0
- package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.d.ts +9 -0
- package/dist/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +13 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +10 -0
- package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +6 -0
- package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/unionUtils.d.ts +12 -1
- package/dist/tools/implementation/zodSchema/unionUtils.d.ts.map +1 -1
- package/dist/tools/internal.d.ts +1 -0
- package/dist/tools/internal.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts +3 -6
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/dist/tools/testing.d.ts.map +1 -1
- package/dist/tools/tests/schema.withPermissions.test.d.ts +2 -0
- package/dist/tools/tests/schema.withPermissions.test.d.ts.map +1 -0
- package/dist/worker/index.js +2 -2
- package/dist/worker/index.js.map +1 -1
- package/package.json +4 -4
- package/src/browser/createBrowserContext.ts +3 -62
- package/src/browser/provideBrowserLockSession/BrowserSessionProvider.test.ts +406 -0
- package/src/browser/provideBrowserLockSession/BrowserSessionProvider.ts +132 -0
- package/src/browser/provideBrowserLockSession/SessionIDStorage.ts +33 -0
- package/src/browser/provideBrowserLockSession/index.ts +11 -0
- package/src/inspector/tests/utils/transactions-changes.test.ts +102 -0
- package/src/inspector/ui/icons/add-icon.tsx +3 -3
- package/src/inspector/utils/history.ts +6 -6
- package/src/inspector/utils/transactions-changes.ts +37 -3
- package/src/inspector/viewer/history-view.tsx +13 -13
- package/src/react/provider.tsx +6 -1
- package/src/react-core/hooks.ts +2 -2
- package/src/react-core/tests/useSuspenseCoState.test.tsx +47 -0
- package/src/react-native-core/ReactNativeSessionProvider.ts +52 -0
- package/src/react-native-core/platform.ts +5 -30
- package/src/react-native-core/provider.tsx +6 -1
- package/src/react-native-core/tests/ReactNativeSessionProvider.test.ts +124 -0
- package/src/tools/coValues/account.ts +4 -0
- package/src/tools/coValues/coFeed.ts +8 -3
- package/src/tools/coValues/coList.ts +6 -3
- package/src/tools/coValues/coMap.ts +10 -0
- package/src/tools/coValues/coVector.ts +2 -1
- package/src/tools/coValues/group.ts +6 -4
- package/src/tools/coValues/interfaces.ts +19 -7
- package/src/tools/exports.ts +3 -1
- package/src/tools/implementation/ContextManager.ts +10 -0
- package/src/tools/implementation/createContext.ts +43 -15
- package/src/tools/implementation/schema.ts +23 -13
- package/src/tools/implementation/schemaUtils.ts +1 -1
- package/src/tools/implementation/zodSchema/runtimeConverters/schemaFieldToCoFieldDef.ts +105 -4
- package/src/tools/implementation/zodSchema/schemaPermissions.ts +188 -0
- package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +46 -3
- package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +46 -3
- package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +50 -13
- package/src/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +14 -0
- package/src/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.ts +24 -1
- package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +51 -4
- package/src/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +25 -1
- package/src/tools/implementation/zodSchema/schemaTypes/RichTextSchema.ts +21 -1
- package/src/tools/implementation/zodSchema/unionUtils.ts +72 -20
- package/src/tools/internal.ts +1 -0
- package/src/tools/subscribe/SubscriptionScope.ts +61 -39
- package/src/tools/testing.ts +3 -1
- package/src/tools/tests/ContextManager.test.ts +2 -1
- package/src/tools/tests/coPlainText.test.ts +2 -2
- package/src/tools/tests/createContext.test.ts +79 -1
- package/src/tools/tests/deepLoading.test.ts +25 -2
- package/src/tools/tests/schema.resolved.test.ts +10 -0
- package/src/tools/tests/schema.withPermissions.test.ts +859 -0
- package/src/tools/tests/utils.ts +2 -2
- package/src/worker/index.ts +2 -2
- package/dist/chunk-HX5S6W5E.js.map +0 -1
- package/dist/inspector/chunk-C6BJPHBQ.js.map +0 -1
|
@@ -62,10 +62,10 @@ export function getTransactionChanges(
|
|
|
62
62
|
const firstChange = tx.changes[0]!;
|
|
63
63
|
|
|
64
64
|
if (
|
|
65
|
-
TransactionChanges.isItemAppend(firstChange) &&
|
|
65
|
+
TransactionChanges.isItemAppend(coValue, firstChange) &&
|
|
66
66
|
tx.changes.every(
|
|
67
67
|
(c) =>
|
|
68
|
-
TransactionChanges.isItemAppend(c) &&
|
|
68
|
+
TransactionChanges.isItemAppend(coValue, c) &&
|
|
69
69
|
areSameOpIds(c.after, firstChange.after),
|
|
70
70
|
)
|
|
71
71
|
) {
|
|
@@ -84,10 +84,10 @@ export function getTransactionChanges(
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
if (
|
|
87
|
-
TransactionChanges.isItemPrepend(firstChange) &&
|
|
87
|
+
TransactionChanges.isItemPrepend(coValue, firstChange) &&
|
|
88
88
|
tx.changes.every(
|
|
89
89
|
(c) =>
|
|
90
|
-
TransactionChanges.isItemPrepend(c) &&
|
|
90
|
+
TransactionChanges.isItemPrepend(coValue, c) &&
|
|
91
91
|
areSameOpIds(c.before, firstChange.before),
|
|
92
92
|
)
|
|
93
93
|
) {
|
|
@@ -106,8 +106,8 @@ export function getTransactionChanges(
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
if (
|
|
109
|
-
TransactionChanges.isItemDeletion(firstChange) &&
|
|
110
|
-
tx.changes.every((c) => TransactionChanges.isItemDeletion(c))
|
|
109
|
+
TransactionChanges.isItemDeletion(coValue, firstChange) &&
|
|
110
|
+
tx.changes.every((c) => TransactionChanges.isItemDeletion(coValue, c))
|
|
111
111
|
) {
|
|
112
112
|
const coValueBeforeDeletions = coValue.atTime(tx.madeAt - 1);
|
|
113
113
|
|
|
@@ -14,85 +14,119 @@ import type {
|
|
|
14
14
|
import { isCoId } from "../viewer/types";
|
|
15
15
|
|
|
16
16
|
export const isGroupExtension = (
|
|
17
|
+
coValue: RawCoValue,
|
|
17
18
|
change: any,
|
|
18
19
|
): change is Extract<
|
|
19
20
|
MapOpPayload<`child_${string}`, "extend">,
|
|
20
21
|
{ op: "set" }
|
|
21
22
|
> => {
|
|
23
|
+
if (coValue.core.isGroup() === false) return false;
|
|
22
24
|
return change?.op === "set" && change?.value === "extend";
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
export const isGroupExtendRevocation = (
|
|
28
|
+
coValue: RawCoValue,
|
|
26
29
|
change: any,
|
|
27
30
|
): change is Extract<
|
|
28
31
|
MapOpPayload<`child_${string}`, "revoked">,
|
|
29
32
|
{ op: "set" }
|
|
30
33
|
> => {
|
|
34
|
+
if (coValue.core.isGroup() === false) return false;
|
|
31
35
|
return change?.op === "set" && change?.value === "revoked";
|
|
32
36
|
};
|
|
33
37
|
|
|
34
38
|
export const isGroupPromotion = (
|
|
39
|
+
coValue: RawCoValue,
|
|
35
40
|
change: any,
|
|
36
41
|
): change is Extract<
|
|
37
42
|
MapOpPayload<`parent_co_${string}`, AccountRole>,
|
|
38
43
|
{ op: "set" }
|
|
39
44
|
> => {
|
|
45
|
+
if (coValue.core.isGroup() === false) return false;
|
|
40
46
|
return change?.op === "set" && change?.key.startsWith("parent_co_");
|
|
41
47
|
};
|
|
42
48
|
|
|
43
49
|
export const isUserPromotion = (
|
|
50
|
+
coValue: RawCoValue,
|
|
44
51
|
change: any,
|
|
45
52
|
): change is Extract<MapOpPayload<CoID<RawCoValue>, Role>, { op: "set" }> => {
|
|
53
|
+
if (coValue.core.isGroup() === false) return false;
|
|
46
54
|
return (
|
|
47
55
|
change?.op === "set" && (isCoId(change?.key) || change?.key === "everyone")
|
|
48
56
|
);
|
|
49
57
|
};
|
|
50
58
|
|
|
51
59
|
export const isKeyRevelation = (
|
|
60
|
+
coValue: RawCoValue,
|
|
52
61
|
change: any,
|
|
53
62
|
): change is Extract<
|
|
54
63
|
MapOpPayload<`${string}_for_${string}`, string>,
|
|
55
64
|
{ op: "set" }
|
|
56
65
|
> => {
|
|
66
|
+
if (
|
|
67
|
+
coValue.core.isGroup() === false &&
|
|
68
|
+
coValue.headerMeta?.type !== "account"
|
|
69
|
+
)
|
|
70
|
+
return false;
|
|
57
71
|
return change?.op === "set" && change?.key.includes("_for_");
|
|
58
72
|
};
|
|
59
73
|
|
|
60
74
|
export const isPropertySet = (
|
|
75
|
+
coValue: RawCoValue,
|
|
61
76
|
change: any,
|
|
62
77
|
): change is Extract<MapOpPayload<string, any>, { op: "set" }> => {
|
|
63
78
|
return change?.op === "set" && "key" in change && "value" in change;
|
|
64
79
|
};
|
|
65
80
|
export const isPropertyDeletion = (
|
|
81
|
+
coValue: RawCoValue,
|
|
66
82
|
change: any,
|
|
67
83
|
): change is Extract<MapOpPayload<string, any>, { op: "del" }> => {
|
|
68
84
|
return change?.op === "del" && "key" in change;
|
|
69
85
|
};
|
|
70
86
|
|
|
71
87
|
export const isItemAppend = (
|
|
88
|
+
coValue: RawCoValue,
|
|
72
89
|
change: any,
|
|
73
90
|
): change is Extract<ListOpPayload<any>, { op: "app" }> => {
|
|
91
|
+
if (coValue.type !== "colist" && coValue.type !== "coplaintext") return false;
|
|
74
92
|
return change?.op === "app" && "after" in change && "value" in change;
|
|
75
93
|
};
|
|
76
94
|
export const isItemPrepend = (
|
|
95
|
+
coValue: RawCoValue,
|
|
77
96
|
change: any,
|
|
78
97
|
): change is Extract<ListOpPayload<any>, { op: "pre" }> => {
|
|
98
|
+
if (coValue.type !== "colist" && coValue.type !== "coplaintext") return false;
|
|
79
99
|
return change?.op === "pre" && "before" in change && "value" in change;
|
|
80
100
|
};
|
|
81
101
|
|
|
82
102
|
export const isItemDeletion = (
|
|
103
|
+
coValue: RawCoValue,
|
|
83
104
|
change: any,
|
|
84
105
|
): change is Extract<ListOpPayload<any>, { op: "del" }> => {
|
|
106
|
+
if (coValue.type !== "colist" && coValue.type !== "coplaintext") return false;
|
|
85
107
|
return change?.op === "del" && "insertion" in change;
|
|
86
108
|
};
|
|
87
109
|
|
|
88
|
-
export const isStreamStart = (
|
|
110
|
+
export const isStreamStart = (
|
|
111
|
+
coValue: RawCoValue,
|
|
112
|
+
change: any,
|
|
113
|
+
): change is BinaryStreamStart => {
|
|
114
|
+
if (coValue.type !== "coStream") return false;
|
|
89
115
|
return change?.type === "start" && "mimeType" in change;
|
|
90
116
|
};
|
|
91
117
|
|
|
92
|
-
export const isStreamChunk = (
|
|
118
|
+
export const isStreamChunk = (
|
|
119
|
+
coValue: RawCoValue,
|
|
120
|
+
change: any,
|
|
121
|
+
): change is BinaryStreamChunk => {
|
|
122
|
+
if (coValue.type !== "coStream") return false;
|
|
93
123
|
return change?.type === "chunk" && "chunk" in change;
|
|
94
124
|
};
|
|
95
125
|
|
|
96
|
-
export const isStreamEnd = (
|
|
126
|
+
export const isStreamEnd = (
|
|
127
|
+
coValue: RawCoValue,
|
|
128
|
+
change: any,
|
|
129
|
+
): change is BinaryStreamEnd => {
|
|
130
|
+
if (coValue.type !== "coStream") return false;
|
|
97
131
|
return change?.type === "end";
|
|
98
132
|
};
|
|
@@ -128,7 +128,7 @@ function mapTransactionToAction(
|
|
|
128
128
|
coValue: RawCoValue,
|
|
129
129
|
): string {
|
|
130
130
|
// Group changes
|
|
131
|
-
if (TransactionChanges.isUserPromotion(change)) {
|
|
131
|
+
if (TransactionChanges.isUserPromotion(coValue, change)) {
|
|
132
132
|
if (change.value === "revoked") {
|
|
133
133
|
return `${change.key} has been revoked`;
|
|
134
134
|
}
|
|
@@ -136,28 +136,28 @@ function mapTransactionToAction(
|
|
|
136
136
|
return `${change.key} has been promoted to ${change.value}`;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
if (TransactionChanges.isGroupExtension(change)) {
|
|
139
|
+
if (TransactionChanges.isGroupExtension(coValue, change)) {
|
|
140
140
|
const child = change.key.slice(6);
|
|
141
141
|
return `Group became a member of ${child}`;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
if (TransactionChanges.isGroupExtendRevocation(change)) {
|
|
144
|
+
if (TransactionChanges.isGroupExtendRevocation(coValue, change)) {
|
|
145
145
|
const child = change.key.slice(6);
|
|
146
146
|
return `Group's membership of ${child} has been revoked.`;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
if (TransactionChanges.isGroupPromotion(change)) {
|
|
149
|
+
if (TransactionChanges.isGroupPromotion(coValue, change)) {
|
|
150
150
|
const parent = change.key.slice(7);
|
|
151
151
|
return `Group ${parent} has been promoted to ${change.value}`;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
if (TransactionChanges.isKeyRevelation(change)) {
|
|
154
|
+
if (TransactionChanges.isKeyRevelation(coValue, change)) {
|
|
155
155
|
const [key, target] = change.key.split("_for_");
|
|
156
156
|
return `Key "${key}" has been revealed to "${target}"`;
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
// coList changes
|
|
160
|
-
if (TransactionChanges.isItemAppend(change)) {
|
|
160
|
+
if (TransactionChanges.isItemAppend(coValue, change)) {
|
|
161
161
|
if (change.after === "start") {
|
|
162
162
|
return `"${change.value}" has been appended`;
|
|
163
163
|
}
|
|
@@ -171,7 +171,7 @@ function mapTransactionToAction(
|
|
|
171
171
|
return `"${change.value}" has been inserted after "${(after as any).value}"`;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
if (TransactionChanges.isItemPrepend(change)) {
|
|
174
|
+
if (TransactionChanges.isItemPrepend(coValue, change)) {
|
|
175
175
|
if (change.before === "end") {
|
|
176
176
|
return `"${change.value}" has been prepended`;
|
|
177
177
|
}
|
|
@@ -185,7 +185,7 @@ function mapTransactionToAction(
|
|
|
185
185
|
return `"${change.value}" has been inserted before "${(before as any).value}"`;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
if (TransactionChanges.isItemDeletion(change)) {
|
|
188
|
+
if (TransactionChanges.isItemDeletion(coValue, change)) {
|
|
189
189
|
const insertion = findListChange(change.insertion, coValue);
|
|
190
190
|
if (insertion === undefined) {
|
|
191
191
|
return `An undefined item has been deleted`;
|
|
@@ -195,24 +195,24 @@ function mapTransactionToAction(
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
// coStream changes
|
|
198
|
-
if (TransactionChanges.isStreamStart(change)) {
|
|
198
|
+
if (TransactionChanges.isStreamStart(coValue, change)) {
|
|
199
199
|
return `Stream started with mime type "${change.mimeType}" and file name "${change.fileName}"`;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
if (TransactionChanges.isStreamChunk(change)) {
|
|
202
|
+
if (TransactionChanges.isStreamChunk(coValue, change)) {
|
|
203
203
|
return `Stream chunk added`;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
if (TransactionChanges.isStreamEnd(change)) {
|
|
206
|
+
if (TransactionChanges.isStreamEnd(coValue, change)) {
|
|
207
207
|
return `Stream ended`;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
// coMap changes
|
|
211
|
-
if (TransactionChanges.isPropertySet(change)) {
|
|
211
|
+
if (TransactionChanges.isPropertySet(coValue, change)) {
|
|
212
212
|
return `Property "${change.key}" has been set to ${JSON.stringify(change.value)}`;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
if (TransactionChanges.isPropertyDeletion(change)) {
|
|
215
|
+
if (TransactionChanges.isPropertyDeletion(coValue, change)) {
|
|
216
216
|
return `Property "${change.key}" has been deleted`;
|
|
217
217
|
}
|
|
218
218
|
|
package/src/react/provider.tsx
CHANGED
|
@@ -58,6 +58,9 @@ export function JazzReactProvider<
|
|
|
58
58
|
);
|
|
59
59
|
const logoutReplacementActiveRef = useRef(false);
|
|
60
60
|
logoutReplacementActiveRef.current = Boolean(logOutReplacement);
|
|
61
|
+
const onAnonymousAccountDiscardedEnabled = Boolean(
|
|
62
|
+
onAnonymousAccountDiscarded,
|
|
63
|
+
);
|
|
61
64
|
|
|
62
65
|
const value = React.useSyncExternalStore<
|
|
63
66
|
JazzContextType<InstanceOfSchema<S>> | undefined
|
|
@@ -74,7 +77,9 @@ export function JazzReactProvider<
|
|
|
74
77
|
logOutReplacement: logoutReplacementActiveRef.current
|
|
75
78
|
? logOutReplacementRefCallback
|
|
76
79
|
: undefined,
|
|
77
|
-
onAnonymousAccountDiscarded:
|
|
80
|
+
onAnonymousAccountDiscarded: onAnonymousAccountDiscardedEnabled
|
|
81
|
+
? onAnonymousAccountDiscardedRefCallback
|
|
82
|
+
: undefined,
|
|
78
83
|
} satisfies JazzContextManagerProps<S>;
|
|
79
84
|
|
|
80
85
|
if (contextManager.propsChanged(props)) {
|
package/src/react-core/hooks.ts
CHANGED
|
@@ -489,7 +489,7 @@ export function useSuspenseCoState<
|
|
|
489
489
|
throw new Error("Subscription not found");
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
-
use(subscription.
|
|
492
|
+
use(subscription.getCachedPromise());
|
|
493
493
|
|
|
494
494
|
const getCurrentValue = () => {
|
|
495
495
|
const value = subscription.getCurrentValue();
|
|
@@ -824,7 +824,7 @@ export function useSuspenseAccount<
|
|
|
824
824
|
);
|
|
825
825
|
}
|
|
826
826
|
|
|
827
|
-
use(subscription.
|
|
827
|
+
use(subscription.getCachedPromise());
|
|
828
828
|
|
|
829
829
|
const getCurrentValue = () => {
|
|
830
830
|
const value = subscription.getCurrentValue();
|
|
@@ -370,6 +370,53 @@ describe("useSuspenseCoState", () => {
|
|
|
370
370
|
});
|
|
371
371
|
});
|
|
372
372
|
|
|
373
|
+
it("should throw error when CoValue becomes unauthorized", async () => {
|
|
374
|
+
const TestMap = co.map({
|
|
375
|
+
value: z.string(),
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
const group = Group.create();
|
|
379
|
+
group.addMember("everyone", "reader");
|
|
380
|
+
|
|
381
|
+
// Create CoValue owned by another account without sharing
|
|
382
|
+
const map = TestMap.create(
|
|
383
|
+
{
|
|
384
|
+
value: "123",
|
|
385
|
+
},
|
|
386
|
+
group,
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
await createJazzTestAccount({
|
|
390
|
+
isCurrentActiveAccount: true,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
const TestComponent = () => {
|
|
394
|
+
const value = useSuspenseCoState(TestMap, map.$jazz.id);
|
|
395
|
+
return <div>{value.value}</div>;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const { container } = await act(async () => {
|
|
399
|
+
return render(
|
|
400
|
+
<ErrorBoundary fallback={<div>Error!</div>}>
|
|
401
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
402
|
+
<TestComponent />
|
|
403
|
+
</Suspense>
|
|
404
|
+
</ErrorBoundary>,
|
|
405
|
+
);
|
|
406
|
+
});
|
|
407
|
+
await waitFor(() => {
|
|
408
|
+
expect(container.textContent).toContain("123");
|
|
409
|
+
expect(container.textContent).not.toContain("Loading...");
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
group.removeMember("everyone");
|
|
413
|
+
|
|
414
|
+
// Wait for error to be thrown (unauthorized access)
|
|
415
|
+
await waitFor(() => {
|
|
416
|
+
expect(container.textContent).toContain("Error!");
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
|
|
373
420
|
it("should update value when CoValue changes", async () => {
|
|
374
421
|
const TestMap = co.map({
|
|
375
422
|
value: z.string(),
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CryptoProvider,
|
|
3
|
+
KvStoreContext,
|
|
4
|
+
SessionID,
|
|
5
|
+
SessionProvider,
|
|
6
|
+
} from "jazz-tools";
|
|
7
|
+
import { AgentID, RawAccountID } from "cojson";
|
|
8
|
+
|
|
9
|
+
export class ReactNativeSessionProvider implements SessionProvider {
|
|
10
|
+
async acquireSession(
|
|
11
|
+
accountID: string,
|
|
12
|
+
crypto: CryptoProvider,
|
|
13
|
+
): Promise<{ sessionID: SessionID; sessionDone: () => void }> {
|
|
14
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
|
15
|
+
const existingSession = await kvStore.get(accountID as string);
|
|
16
|
+
|
|
17
|
+
if (existingSession) {
|
|
18
|
+
console.log("Using existing session", existingSession);
|
|
19
|
+
return Promise.resolve({
|
|
20
|
+
sessionID: existingSession as SessionID,
|
|
21
|
+
sessionDone: () => {},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// We need to provide this for backwards compatibility with the old session provider
|
|
26
|
+
// With the current session provider we should never get here because:
|
|
27
|
+
// - New accounts provide their session and go through the persistSession method
|
|
28
|
+
// - Existing accounts should already have a session
|
|
29
|
+
const newSessionID = crypto.newRandomSessionID(
|
|
30
|
+
accountID as RawAccountID | AgentID,
|
|
31
|
+
);
|
|
32
|
+
await kvStore.set(accountID, newSessionID);
|
|
33
|
+
|
|
34
|
+
console.error("Created new session", newSessionID);
|
|
35
|
+
|
|
36
|
+
return Promise.resolve({
|
|
37
|
+
sessionID: newSessionID,
|
|
38
|
+
sessionDone: () => {},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async persistSession(
|
|
43
|
+
accountID: string,
|
|
44
|
+
sessionID: SessionID,
|
|
45
|
+
): Promise<{ sessionDone: () => void }> {
|
|
46
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
|
47
|
+
await kvStore.set(accountID, sessionID);
|
|
48
|
+
return Promise.resolve({
|
|
49
|
+
sessionDone: () => {},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
import NetInfo from "@react-native-community/netinfo";
|
|
2
|
-
import { LocalNode, Peer,
|
|
2
|
+
import { LocalNode, Peer, getSqliteStorageAsync } from "cojson";
|
|
3
3
|
import { PureJSCrypto } from "cojson/dist/crypto/PureJSCrypto"; // Importing from dist to not rely on the exports field
|
|
4
4
|
import {
|
|
5
5
|
Account,
|
|
6
6
|
AccountClass,
|
|
7
|
-
AgentID,
|
|
8
7
|
AnyAccountSchema,
|
|
9
8
|
AuthCredentials,
|
|
10
9
|
AuthSecretStorage,
|
|
11
10
|
CoValue,
|
|
12
11
|
CoValueFromRaw,
|
|
13
|
-
CryptoProvider,
|
|
14
|
-
ID,
|
|
15
12
|
NewAccountProps,
|
|
16
|
-
SessionID,
|
|
17
13
|
SyncConfig,
|
|
18
14
|
createInviteLink as baseCreateInviteLink,
|
|
19
15
|
createAnonymousJazzContext,
|
|
20
16
|
createJazzContext,
|
|
21
17
|
} from "jazz-tools";
|
|
22
18
|
import { KvStore, KvStoreContext } from "./storage/kv-store-context.js";
|
|
19
|
+
import { ReactNativeSessionProvider } from "./ReactNativeSessionProvider.js";
|
|
23
20
|
|
|
24
21
|
import { SQLiteDatabaseDriverAsync } from "cojson";
|
|
25
22
|
import { WebSocketPeerWithReconnection } from "cojson-transport-ws";
|
|
@@ -200,6 +197,8 @@ export async function createJazzReactNativeContext<
|
|
|
200
197
|
handleAuthUpdate(authSecretStorage.isAuthenticated);
|
|
201
198
|
}
|
|
202
199
|
|
|
200
|
+
const sessionProvider = new ReactNativeSessionProvider();
|
|
201
|
+
|
|
203
202
|
const context = await createJazzContext({
|
|
204
203
|
credentials: options.credentials,
|
|
205
204
|
newAccountProps: options.newAccountProps,
|
|
@@ -207,7 +206,7 @@ export async function createJazzReactNativeContext<
|
|
|
207
206
|
crypto,
|
|
208
207
|
defaultProfileName: options.defaultProfileName,
|
|
209
208
|
AccountSchema: options.AccountSchema,
|
|
210
|
-
sessionProvider
|
|
209
|
+
sessionProvider,
|
|
211
210
|
authSecretStorage: options.authSecretStorage,
|
|
212
211
|
storage,
|
|
213
212
|
});
|
|
@@ -233,30 +232,6 @@ export async function createJazzReactNativeContext<
|
|
|
233
232
|
};
|
|
234
233
|
}
|
|
235
234
|
|
|
236
|
-
/** @category Auth Providers */
|
|
237
|
-
export type SessionProvider = (
|
|
238
|
-
accountID: ID<Account> | AgentID,
|
|
239
|
-
) => Promise<SessionID>;
|
|
240
|
-
|
|
241
|
-
export async function provideLockSession(
|
|
242
|
-
accountID: ID<Account> | AgentID,
|
|
243
|
-
crypto: CryptoProvider,
|
|
244
|
-
) {
|
|
245
|
-
const sessionDone = () => {};
|
|
246
|
-
|
|
247
|
-
const kvStore = KvStoreContext.getInstance().getStorage();
|
|
248
|
-
|
|
249
|
-
const sessionID =
|
|
250
|
-
((await kvStore.get(accountID)) as SessionID) ||
|
|
251
|
-
crypto.newRandomSessionID(accountID as RawAccountID | AgentID);
|
|
252
|
-
await kvStore.set(accountID, sessionID);
|
|
253
|
-
|
|
254
|
-
return Promise.resolve({
|
|
255
|
-
sessionID,
|
|
256
|
-
sessionDone,
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
|
|
260
235
|
/** @category Invite Links */
|
|
261
236
|
export function createInviteLink<C extends CoValue>(
|
|
262
237
|
value: C,
|
|
@@ -55,6 +55,9 @@ export function JazzProviderCore<
|
|
|
55
55
|
);
|
|
56
56
|
const logoutReplacementActiveRef = useRef(false);
|
|
57
57
|
logoutReplacementActiveRef.current = Boolean(logOutReplacement);
|
|
58
|
+
const onAnonymousAccountDiscardedEnabled = Boolean(
|
|
59
|
+
onAnonymousAccountDiscarded,
|
|
60
|
+
);
|
|
58
61
|
|
|
59
62
|
const value = React.useSyncExternalStore<
|
|
60
63
|
JazzContextType<InstanceOfSchema<S>> | undefined
|
|
@@ -71,7 +74,9 @@ export function JazzProviderCore<
|
|
|
71
74
|
logOutReplacement: logoutReplacementActiveRef.current
|
|
72
75
|
? logOutReplacementRefCallback
|
|
73
76
|
: undefined,
|
|
74
|
-
onAnonymousAccountDiscarded:
|
|
77
|
+
onAnonymousAccountDiscarded: onAnonymousAccountDiscardedEnabled
|
|
78
|
+
? onAnonymousAccountDiscardedRefCallback
|
|
79
|
+
: undefined,
|
|
75
80
|
CryptoProvider,
|
|
76
81
|
} satisfies JazzContextManagerProps<S>;
|
|
77
82
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
|
2
|
+
import { SessionID } from "cojson";
|
|
3
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
4
|
+
import { InMemoryKVStore } from "jazz-tools";
|
|
5
|
+
import { KvStoreContext, type KvStore } from "jazz-tools";
|
|
6
|
+
import { ReactNativeSessionProvider } from "../ReactNativeSessionProvider.js";
|
|
7
|
+
import { createJazzTestAccount } from "jazz-tools/testing";
|
|
8
|
+
import type { CryptoProvider } from "jazz-tools";
|
|
9
|
+
|
|
10
|
+
// Initialize KV store for tests
|
|
11
|
+
const kvStore = new InMemoryKVStore() as KvStore;
|
|
12
|
+
KvStoreContext.getInstance().initialize(kvStore);
|
|
13
|
+
|
|
14
|
+
const Crypto = await WasmCrypto.create();
|
|
15
|
+
|
|
16
|
+
describe("ReactNativeSessionProvider", () => {
|
|
17
|
+
let sessionProvider: ReactNativeSessionProvider;
|
|
18
|
+
let account: Awaited<ReturnType<typeof createJazzTestAccount>>;
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
// Clear KV store
|
|
22
|
+
kvStore.clearAll();
|
|
23
|
+
|
|
24
|
+
// Create new session provider instance
|
|
25
|
+
sessionProvider = new ReactNativeSessionProvider();
|
|
26
|
+
|
|
27
|
+
// Create test account
|
|
28
|
+
account = await createJazzTestAccount({
|
|
29
|
+
isCurrentActiveAccount: true,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("acquireSession", () => {
|
|
34
|
+
test("creates new session when none exists", async () => {
|
|
35
|
+
const accountID = account.$jazz.id;
|
|
36
|
+
|
|
37
|
+
// Verify no session exists
|
|
38
|
+
const existingSessionBefore = await kvStore.get(accountID);
|
|
39
|
+
expect(existingSessionBefore).toBeNull();
|
|
40
|
+
|
|
41
|
+
// Acquire session
|
|
42
|
+
const result = await sessionProvider.acquireSession(
|
|
43
|
+
accountID,
|
|
44
|
+
Crypto as CryptoProvider,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Verify a new session ID is generated
|
|
48
|
+
expect(result.sessionID).toBeDefined();
|
|
49
|
+
|
|
50
|
+
// Verify the session is stored in KvStore
|
|
51
|
+
const storedSession = await kvStore.get(accountID);
|
|
52
|
+
expect(storedSession).toBeDefined();
|
|
53
|
+
expect(storedSession).toBe(result.sessionID);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("returns existing session when one exists", async () => {
|
|
57
|
+
const accountID = account.$jazz.id;
|
|
58
|
+
const existingSessionID = "existing-session-id" as SessionID;
|
|
59
|
+
|
|
60
|
+
// Pre-populate KvStore with a session ID
|
|
61
|
+
await kvStore.set(accountID, existingSessionID);
|
|
62
|
+
|
|
63
|
+
// Verify session exists before calling acquireSession
|
|
64
|
+
const sessionBefore = await kvStore.get(accountID);
|
|
65
|
+
expect(sessionBefore).toBe(existingSessionID);
|
|
66
|
+
|
|
67
|
+
// Acquire session
|
|
68
|
+
const result = await sessionProvider.acquireSession(
|
|
69
|
+
accountID,
|
|
70
|
+
Crypto as CryptoProvider,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Verify the existing session ID is returned (not a new one)
|
|
74
|
+
expect(result.sessionID).toBe(existingSessionID);
|
|
75
|
+
|
|
76
|
+
// Verify no new session is created (same value still in store)
|
|
77
|
+
const sessionAfter = await kvStore.get(accountID);
|
|
78
|
+
expect(sessionAfter).toBe(existingSessionID);
|
|
79
|
+
expect(sessionAfter).toBe(result.sessionID);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("persistSession", () => {
|
|
84
|
+
test("stores session ID correctly", async () => {
|
|
85
|
+
const accountID = account.$jazz.id;
|
|
86
|
+
const sessionID = "test-session-id" as SessionID;
|
|
87
|
+
|
|
88
|
+
// Verify no session exists before
|
|
89
|
+
const sessionBefore = await kvStore.get(accountID);
|
|
90
|
+
expect(sessionBefore).toBeNull();
|
|
91
|
+
|
|
92
|
+
// Persist session
|
|
93
|
+
await sessionProvider.persistSession(accountID, sessionID);
|
|
94
|
+
|
|
95
|
+
// Verify the session ID is stored in KvStore
|
|
96
|
+
const storedSession = await kvStore.get(accountID);
|
|
97
|
+
expect(storedSession).toBeDefined();
|
|
98
|
+
|
|
99
|
+
// Verify the stored value matches the provided session ID
|
|
100
|
+
expect(storedSession).toBe(sessionID);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("overwrites existing session", async () => {
|
|
104
|
+
const accountID = account.$jazz.id;
|
|
105
|
+
const initialSessionID = "initial-session-id" as SessionID;
|
|
106
|
+
const newSessionID = "new-session-id" as SessionID;
|
|
107
|
+
|
|
108
|
+
// Store an initial session ID
|
|
109
|
+
await kvStore.set(accountID, initialSessionID);
|
|
110
|
+
|
|
111
|
+
// Verify initial session is stored
|
|
112
|
+
const sessionBefore = await kvStore.get(accountID);
|
|
113
|
+
expect(sessionBefore).toBe(initialSessionID);
|
|
114
|
+
|
|
115
|
+
// Persist a different session ID
|
|
116
|
+
await sessionProvider.persistSession(accountID, newSessionID);
|
|
117
|
+
|
|
118
|
+
// Verify the new session ID replaces the old one
|
|
119
|
+
const sessionAfter = await kvStore.get(accountID);
|
|
120
|
+
expect(sessionAfter).toBe(newSessionID);
|
|
121
|
+
expect(sessionAfter).not.toBe(initialSessionID);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -466,10 +466,14 @@ class AccountJazzApi<A extends Account> extends CoValueJazzApi<A> {
|
|
|
466
466
|
| undefined;
|
|
467
467
|
if (!refId) {
|
|
468
468
|
const descriptor = this.schema[key];
|
|
469
|
+
const newOwnerStrategy = descriptor.permissions?.newInlineOwnerStrategy;
|
|
470
|
+
const onCreate = descriptor.permissions?.onCreate;
|
|
469
471
|
const coValue = instantiateRefEncodedWithInit(
|
|
470
472
|
descriptor,
|
|
471
473
|
value,
|
|
472
474
|
accountOrGroupToGroup(this.account),
|
|
475
|
+
newOwnerStrategy,
|
|
476
|
+
onCreate,
|
|
473
477
|
);
|
|
474
478
|
refId = coValue.$jazz.id as CoID<RawCoMap>;
|
|
475
479
|
}
|
|
@@ -32,8 +32,6 @@ import {
|
|
|
32
32
|
SubscribeRestArgs,
|
|
33
33
|
TypeSym,
|
|
34
34
|
BranchDefinition,
|
|
35
|
-
} from "../internal.js";
|
|
36
|
-
import {
|
|
37
35
|
Account,
|
|
38
36
|
CoValueBase,
|
|
39
37
|
CoValueJazzApi,
|
|
@@ -379,10 +377,15 @@ export class CoFeedJazzApi<F extends CoFeed> extends CoValueJazzApi<F> {
|
|
|
379
377
|
} else if (isRefEncoded(itemDescriptor)) {
|
|
380
378
|
let refId = (item as unknown as CoValue).$jazz?.id;
|
|
381
379
|
if (!refId) {
|
|
380
|
+
const newOwnerStrategy =
|
|
381
|
+
itemDescriptor.permissions?.newInlineOwnerStrategy;
|
|
382
|
+
const onCreate = itemDescriptor.permissions?.onCreate;
|
|
382
383
|
const coValue = instantiateRefEncodedWithInit(
|
|
383
384
|
itemDescriptor,
|
|
384
385
|
item,
|
|
385
386
|
this.owner,
|
|
387
|
+
newOwnerStrategy,
|
|
388
|
+
onCreate,
|
|
386
389
|
);
|
|
387
390
|
refId = coValue.$jazz.id;
|
|
388
391
|
}
|
|
@@ -720,6 +723,7 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
|
720
723
|
*
|
|
721
724
|
* @param options - Configuration options for the new FileStream
|
|
722
725
|
* @param options.owner - The Account or Group that will own this FileStream and control access rights
|
|
726
|
+
* @param schemaConfiguration - Internal schema configuration
|
|
723
727
|
*
|
|
724
728
|
* @example
|
|
725
729
|
* ```typescript
|
|
@@ -743,7 +747,8 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
|
743
747
|
this: CoValueClass<S>,
|
|
744
748
|
options?: { owner?: Account | Group } | Account | Group,
|
|
745
749
|
) {
|
|
746
|
-
|
|
750
|
+
const { owner } = parseCoValueCreateOptions(options);
|
|
751
|
+
return new this({ owner });
|
|
747
752
|
}
|
|
748
753
|
|
|
749
754
|
getMetadata(): BinaryStreamInfo | undefined {
|