jazz-tools 0.17.14 → 0.18.1

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.
Files changed (250) hide show
  1. package/.svelte-kit/__package__/jazz.class.svelte.js +1 -1
  2. package/.svelte-kit/__package__/media/image.svelte +3 -9
  3. package/.svelte-kit/__package__/media/image.svelte.d.ts +1 -6
  4. package/.svelte-kit/__package__/media/image.svelte.d.ts.map +1 -1
  5. package/.svelte-kit/__package__/media/image.types.d.ts +7 -0
  6. package/.svelte-kit/__package__/media/image.types.d.ts.map +1 -0
  7. package/.svelte-kit/__package__/media/image.types.js +1 -0
  8. package/.svelte-kit/__package__/tests/media/image.svelte.test.js +31 -31
  9. package/.turbo/turbo-build.log +60 -46
  10. package/CHANGELOG.md +41 -0
  11. package/dist/better-auth/auth/client.d.ts +29 -0
  12. package/dist/better-auth/auth/client.d.ts.map +1 -0
  13. package/dist/better-auth/auth/client.js +127 -0
  14. package/dist/better-auth/auth/client.js.map +1 -0
  15. package/dist/better-auth/auth/react.d.ts +2170 -0
  16. package/dist/better-auth/auth/react.d.ts.map +1 -0
  17. package/dist/better-auth/auth/react.js +40 -0
  18. package/dist/better-auth/auth/react.js.map +1 -0
  19. package/dist/better-auth/auth/server.d.ts +14 -0
  20. package/dist/better-auth/auth/server.d.ts.map +1 -0
  21. package/dist/better-auth/auth/server.js +198 -0
  22. package/dist/better-auth/auth/server.js.map +1 -0
  23. package/dist/better-auth/auth/tests/client.test.d.ts +2 -0
  24. package/dist/better-auth/auth/tests/client.test.d.ts.map +1 -0
  25. package/dist/better-auth/auth/tests/server.test.d.ts +2 -0
  26. package/dist/better-auth/auth/tests/server.test.d.ts.map +1 -0
  27. package/dist/browser/index.js +2 -2
  28. package/dist/browser/index.js.map +1 -1
  29. package/dist/{chunk-LZOF6WP5.js → chunk-IERUTUXB.js} +1336 -1017
  30. package/dist/chunk-IERUTUXB.js.map +1 -0
  31. package/dist/index.js +18 -18
  32. package/dist/index.js.map +1 -1
  33. package/dist/inspector/{custom-element-ZSNTCECD.js → custom-element-WCY6D3QJ.js} +3 -3
  34. package/dist/inspector/{custom-element-ZSNTCECD.js.map → custom-element-WCY6D3QJ.js.map} +1 -1
  35. package/dist/inspector/index.js +1 -1
  36. package/dist/inspector/index.js.map +1 -1
  37. package/dist/inspector/register-custom-element.js +1 -1
  38. package/dist/media/{chunk-E5J3WLQW.js → chunk-KR2V6X2N.js} +14 -9
  39. package/dist/media/chunk-KR2V6X2N.js.map +1 -0
  40. package/dist/media/create-image.d.ts +6 -6
  41. package/dist/media/index.browser.d.ts +6 -6
  42. package/dist/media/index.browser.js +1 -1
  43. package/dist/media/index.d.ts +1 -1
  44. package/dist/media/index.js +1 -1
  45. package/dist/media/index.native.d.ts +6 -6
  46. package/dist/media/index.native.js +1 -1
  47. package/dist/media/utils.d.ts.map +1 -1
  48. package/dist/prosemirror/index.js +2 -2
  49. package/dist/prosemirror/index.js.map +1 -1
  50. package/dist/react/index.js +7 -5
  51. package/dist/react/index.js.map +1 -1
  52. package/dist/react-core/hooks.d.ts.map +1 -1
  53. package/dist/react-core/index.js +4675 -23
  54. package/dist/react-core/index.js.map +1 -1
  55. package/dist/react-native-core/index.js +1 -1
  56. package/dist/react-native-core/index.js.map +1 -1
  57. package/dist/svelte/jazz.class.svelte.js +1 -1
  58. package/dist/svelte/media/image.svelte +3 -9
  59. package/dist/svelte/media/image.svelte.d.ts +1 -6
  60. package/dist/svelte/media/image.svelte.d.ts.map +1 -1
  61. package/dist/svelte/media/image.types.d.ts +7 -0
  62. package/dist/svelte/media/image.types.d.ts.map +1 -0
  63. package/dist/svelte/media/image.types.js +1 -0
  64. package/dist/svelte/tests/media/image.svelte.test.js +31 -31
  65. package/dist/testing.js +18 -14
  66. package/dist/testing.js.map +1 -1
  67. package/dist/tools/coValues/CoFieldInit.d.ts +13 -0
  68. package/dist/tools/coValues/CoFieldInit.d.ts.map +1 -0
  69. package/dist/tools/coValues/CoValueBase.d.ts +18 -15
  70. package/dist/tools/coValues/CoValueBase.d.ts.map +1 -1
  71. package/dist/tools/coValues/account.d.ts +101 -46
  72. package/dist/tools/coValues/account.d.ts.map +1 -1
  73. package/dist/tools/coValues/coFeed.d.ts +78 -62
  74. package/dist/tools/coValues/coFeed.d.ts.map +1 -1
  75. package/dist/tools/coValues/coList.d.ts +212 -99
  76. package/dist/tools/coValues/coList.d.ts.map +1 -1
  77. package/dist/tools/coValues/coMap.d.ts +210 -192
  78. package/dist/tools/coValues/coMap.d.ts.map +1 -1
  79. package/dist/tools/coValues/coPlainText.d.ts +30 -22
  80. package/dist/tools/coValues/coPlainText.d.ts.map +1 -1
  81. package/dist/tools/coValues/deepLoading.d.ts +13 -13
  82. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  83. package/dist/tools/coValues/extensions/imageDef.d.ts +1 -1
  84. package/dist/tools/coValues/group.d.ts +32 -32
  85. package/dist/tools/coValues/group.d.ts.map +1 -1
  86. package/dist/tools/coValues/inbox.d.ts.map +1 -1
  87. package/dist/tools/coValues/interfaces.d.ts +18 -17
  88. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  89. package/dist/tools/coValues/profile.d.ts +6 -5
  90. package/dist/tools/coValues/profile.d.ts.map +1 -1
  91. package/dist/tools/coValues/schemaUnion.d.ts +3 -3
  92. package/dist/tools/coValues/schemaUnion.d.ts.map +1 -1
  93. package/dist/tools/exports.d.ts +1 -1
  94. package/dist/tools/exports.d.ts.map +1 -1
  95. package/dist/tools/implementation/anonymousJazzAgent.d.ts +2 -1
  96. package/dist/tools/implementation/anonymousJazzAgent.d.ts.map +1 -1
  97. package/dist/tools/implementation/schema.d.ts +5 -5
  98. package/dist/tools/implementation/schema.d.ts.map +1 -1
  99. package/dist/tools/implementation/symbols.d.ts +2 -0
  100. package/dist/tools/implementation/symbols.d.ts.map +1 -1
  101. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +2 -2
  102. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  103. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +6 -2
  104. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  105. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +8 -3
  106. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  107. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +12 -7
  108. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  109. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +13 -7
  110. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
  111. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +11 -2
  112. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  113. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +4 -0
  114. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
  115. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +4 -0
  116. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
  117. package/dist/tools/implementation/zodSchema/typeConverters/{CoFieldInit.d.ts → CoFieldSchemaInit.d.ts} +7 -7
  118. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.d.ts.map +1 -0
  119. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts +4 -4
  120. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts.map +1 -1
  121. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts +4 -4
  122. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts.map +1 -1
  123. package/dist/tools/implementation/zodSchema/zodCo.d.ts +3 -3
  124. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  125. package/dist/tools/internal.d.ts +2 -1
  126. package/dist/tools/internal.d.ts.map +1 -1
  127. package/dist/tools/lib/migration.d.ts +1 -1
  128. package/dist/tools/lib/migration.d.ts.map +1 -1
  129. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  130. package/dist/tools/subscribe/index.d.ts +1 -1
  131. package/dist/tools/subscribe/index.d.ts.map +1 -1
  132. package/dist/tools/subscribe/utils.d.ts +2 -2
  133. package/dist/tools/subscribe/utils.d.ts.map +1 -1
  134. package/dist/tools/testing.d.ts.map +1 -1
  135. package/dist/tools/tests/utils.d.ts +2 -6
  136. package/dist/tools/tests/utils.d.ts.map +1 -1
  137. package/dist/worker/index.js +3 -3
  138. package/dist/worker/index.js.map +1 -1
  139. package/package.json +23 -4
  140. package/src/better-auth/auth/client.ts +169 -0
  141. package/src/better-auth/auth/react.tsx +105 -0
  142. package/src/better-auth/auth/server.ts +250 -0
  143. package/src/better-auth/auth/tests/client.test.ts +249 -0
  144. package/src/better-auth/auth/tests/server.test.ts +226 -0
  145. package/src/browser/auth/PasskeyAuth.ts +2 -2
  146. package/src/browser/createBrowserContext.ts +2 -2
  147. package/src/browser/tests/PasskeyAuth.test.ts +2 -2
  148. package/src/inspector/custom-element.tsx +2 -2
  149. package/src/inspector/viewer/new-app.tsx +1 -1
  150. package/src/media/create-image.test.ts +7 -7
  151. package/src/media/create-image.ts +5 -3
  152. package/src/media/index.ts +1 -1
  153. package/src/media/utils.test.ts +72 -66
  154. package/src/media/utils.ts +9 -6
  155. package/src/prosemirror/lib/plugin.ts +1 -1
  156. package/src/prosemirror/lib/sync.ts +1 -1
  157. package/src/prosemirror/tests/plugin.test.ts +4 -4
  158. package/src/react/media/image.tsx +2 -2
  159. package/src/react/tests/media/image.test.tsx +52 -32
  160. package/src/react-core/hooks.ts +11 -5
  161. package/src/react-core/tests/useAccount.test.ts +16 -22
  162. package/src/react-core/tests/useCoState.test.ts +19 -19
  163. package/src/react-core/tests/useInboxSender.test.ts +5 -2
  164. package/src/react-core/tests/usePassPhraseAuth.test.ts +6 -6
  165. package/src/react-native-core/media/image.tsx +1 -1
  166. package/src/svelte/jazz.class.svelte.ts +1 -1
  167. package/src/svelte/media/image.svelte +3 -9
  168. package/src/svelte/media/image.types.ts +7 -0
  169. package/src/svelte/tests/media/image.svelte.test.ts +34 -32
  170. package/src/tools/auth/DemoAuth.ts +2 -2
  171. package/src/tools/auth/PassphraseAuth.ts +2 -2
  172. package/src/tools/auth/clerk/index.ts +2 -2
  173. package/src/tools/auth/clerk/tests/JazzClerkAuth.test.ts +1 -1
  174. package/src/tools/coValues/CoFieldInit.ts +20 -0
  175. package/src/tools/coValues/CoValueBase.ts +40 -60
  176. package/src/tools/coValues/account.ts +311 -232
  177. package/src/tools/coValues/coFeed.ts +185 -153
  178. package/src/tools/coValues/coList.ts +507 -334
  179. package/src/tools/coValues/coMap.ts +434 -286
  180. package/src/tools/coValues/coPlainText.ts +94 -110
  181. package/src/tools/coValues/deepLoading.ts +13 -13
  182. package/src/tools/coValues/group.ts +100 -114
  183. package/src/tools/coValues/inbox.ts +16 -14
  184. package/src/tools/coValues/interfaces.ts +49 -31
  185. package/src/tools/coValues/profile.ts +8 -6
  186. package/src/tools/coValues/request.ts +9 -9
  187. package/src/tools/coValues/schemaUnion.ts +11 -5
  188. package/src/tools/exports.ts +1 -1
  189. package/src/tools/implementation/ContextManager.ts +4 -4
  190. package/src/tools/implementation/anonymousJazzAgent.ts +2 -1
  191. package/src/tools/implementation/createContext.ts +1 -1
  192. package/src/tools/implementation/devtoolsFormatters.ts +9 -9
  193. package/src/tools/implementation/invites.ts +2 -2
  194. package/src/tools/implementation/schema.ts +7 -7
  195. package/src/tools/implementation/symbols.ts +3 -0
  196. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +2 -2
  197. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +11 -2
  198. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +18 -7
  199. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +17 -7
  200. package/src/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +20 -11
  201. package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +19 -2
  202. package/src/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +6 -0
  203. package/src/tools/implementation/zodSchema/schemaTypes/RichTextSchema.ts +6 -0
  204. package/src/tools/implementation/zodSchema/typeConverters/{CoFieldInit.ts → CoFieldSchemaInit.ts} +11 -11
  205. package/src/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.ts +4 -4
  206. package/src/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.ts +4 -4
  207. package/src/tools/implementation/zodSchema/zodCo.ts +3 -3
  208. package/src/tools/internal.ts +2 -1
  209. package/src/tools/lib/migration.ts +5 -5
  210. package/src/tools/subscribe/SubscriptionScope.ts +32 -24
  211. package/src/tools/subscribe/index.ts +4 -4
  212. package/src/tools/subscribe/utils.ts +11 -11
  213. package/src/tools/testing.ts +17 -13
  214. package/src/tools/tests/ContextManager.test.ts +70 -59
  215. package/src/tools/tests/PassphraseAuth.test.ts +2 -2
  216. package/src/tools/tests/account.test.ts +188 -67
  217. package/src/tools/tests/coDiscriminatedUnion.test-d.ts +12 -6
  218. package/src/tools/tests/coDiscriminatedUnion.test.ts +26 -17
  219. package/src/tools/tests/coFeed.test-d.ts +18 -17
  220. package/src/tools/tests/coFeed.test.ts +108 -97
  221. package/src/tools/tests/coList.test-d.ts +18 -23
  222. package/src/tools/tests/coList.test.ts +350 -165
  223. package/src/tools/tests/coMap.record.test-d.ts +9 -13
  224. package/src/tools/tests/coMap.record.test.ts +37 -23
  225. package/src/tools/tests/coMap.test-d.ts +43 -21
  226. package/src/tools/tests/coMap.test.ts +459 -182
  227. package/src/tools/tests/coOptional.test.ts +28 -13
  228. package/src/tools/tests/coPlainText.test.ts +15 -15
  229. package/src/tools/tests/createContext.test.ts +14 -14
  230. package/src/tools/tests/deepLoading.test.ts +95 -94
  231. package/src/tools/tests/exportImport.test.ts +61 -41
  232. package/src/tools/tests/groupsAndAccounts.test.ts +333 -116
  233. package/src/tools/tests/inbox.test.ts +22 -17
  234. package/src/tools/tests/interfaces.test.ts +12 -11
  235. package/src/tools/tests/invites.test.ts +6 -4
  236. package/src/tools/tests/load.test.ts +20 -18
  237. package/src/tools/tests/patterns/notifications.test.ts +7 -7
  238. package/src/tools/tests/patterns/quest.test.ts +3 -3
  239. package/src/tools/tests/patterns/requestToJoin.test.ts +22 -22
  240. package/src/tools/tests/request.test.ts +38 -39
  241. package/src/tools/tests/schemaUnion.test.ts +64 -10
  242. package/src/tools/tests/subscribe.test.ts +64 -64
  243. package/src/tools/tests/testing.test.ts +7 -11
  244. package/src/tools/tests/utils.ts +3 -3
  245. package/src/tools/tests/zod.test.ts +3 -3
  246. package/src/worker/index.ts +3 -3
  247. package/tsup.config.ts +9 -0
  248. package/dist/chunk-LZOF6WP5.js.map +0 -1
  249. package/dist/media/chunk-E5J3WLQW.js.map +0 -1
  250. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldInit.d.ts.map +0 -1
@@ -35,12 +35,14 @@ describe("Custom accounts and groups", async () => {
35
35
  type P = typeof account.profile;
36
36
  const _p: P = {} as Loaded<typeof CustomProfile> | null;
37
37
  if (creationProps) {
38
- console.log("In migration!");
39
38
  const profileGroup = Group.create({ owner: account });
40
39
  profileGroup.addMember("everyone", "reader");
41
- account.profile = CustomProfile.create(
42
- { name: creationProps.name, color: "blue" },
43
- profileGroup,
40
+ account.$jazz.set(
41
+ "profile",
42
+ CustomProfile.create(
43
+ { name: creationProps.name, color: "blue" },
44
+ profileGroup,
45
+ ),
44
46
  );
45
47
  }
46
48
  });
@@ -58,38 +60,14 @@ describe("Custom accounts and groups", async () => {
58
60
  const group = Group.create({ owner: me });
59
61
  group.addMember("everyone", "reader");
60
62
 
61
- expect(group.members).toMatchObject([{ id: me.id, role: "admin" }]);
63
+ expect(group.members).toMatchObject([{ id: me.$jazz.id, role: "admin" }]);
62
64
 
63
- const meAsMember = group.members.find((member) => member.id === me.id);
65
+ const meAsMember = group.members.find(
66
+ (member) => member.id === me.$jazz.id,
67
+ );
64
68
  assert(meAsMember?.account);
65
69
  expect((meAsMember?.account).profile?.name).toBe("Hermes Puggington");
66
70
  });
67
-
68
- test("Should throw when creating a profile with an account as owner", async () => {
69
- const CustomAccount = co
70
- .account()
71
- .withMigration(
72
- (
73
- account: Loaded<typeof CustomAccount>,
74
- creationProps?: { name: string },
75
- ) => {
76
- if (creationProps) {
77
- account.profile = co.profile().create(
78
- { name: creationProps.name },
79
- // @ts-expect-error - only groups can own profiles, but we want to also perform a runtime check
80
- account,
81
- );
82
- }
83
- },
84
- );
85
-
86
- await expect(() =>
87
- CustomAccount.create({
88
- creationProps: { name: "Hermes Puggington" },
89
- crypto: Crypto,
90
- }),
91
- ).rejects.toThrowError("Profile must be owned by a Group");
92
- });
93
71
  });
94
72
 
95
73
  describe("Group inheritance", () => {
@@ -116,15 +94,17 @@ describe("Group inheritance", () => {
116
94
 
117
95
  const mapInChild = TestMap.create({ title: "In Child" }, { owner: group });
118
96
 
119
- const mapAsReader = await TestMap.load(mapInChild.id, { loadAs: reader });
97
+ const mapAsReader = await TestMap.load(mapInChild.$jazz.id, {
98
+ loadAs: reader,
99
+ });
120
100
  expect(mapAsReader?.title).toBe("In Child");
121
101
 
122
102
  await parentGroup.removeMember(reader);
123
103
 
124
- mapInChild.title = "In Child (updated)";
104
+ mapInChild.$jazz.set("title", "In Child (updated)");
125
105
 
126
106
  await waitFor(async () => {
127
- const mapAsReaderAfterUpdate = await TestMap.load(mapInChild.id, {
107
+ const mapAsReaderAfterUpdate = await TestMap.load(mapInChild.$jazz.id, {
128
108
  loadAs: reader,
129
109
  });
130
110
  expect(mapAsReaderAfterUpdate).toBe(null);
@@ -155,20 +135,23 @@ describe("Group inheritance", () => {
155
135
  { owner: group },
156
136
  );
157
137
 
158
- const mapAsReader = await TestMap.load(mapInGrandChild.id, {
138
+ const mapAsReader = await TestMap.load(mapInGrandChild.$jazz.id, {
159
139
  loadAs: reader,
160
140
  });
161
141
  expect(mapAsReader?.title).toBe("In Grand Child");
162
142
 
163
143
  await grandParentGroup.removeMember(reader);
164
144
 
165
- await grandParentGroup.waitForSync();
145
+ await grandParentGroup.$jazz.waitForSync();
166
146
 
167
- mapInGrandChild.title = "In Grand Child (updated)";
147
+ mapInGrandChild.$jazz.set("title", "In Grand Child (updated)");
168
148
 
169
- const mapAsReaderAfterUpdate = await TestMap.load(mapInGrandChild.id, {
170
- loadAs: reader,
171
- });
149
+ const mapAsReaderAfterUpdate = await TestMap.load(
150
+ mapInGrandChild.$jazz.id,
151
+ {
152
+ loadAs: reader,
153
+ },
154
+ );
172
155
  expect(mapAsReaderAfterUpdate).toBe(null);
173
156
  });
174
157
 
@@ -189,36 +172,29 @@ describe("Group inheritance", () => {
189
172
 
190
173
  expect(parentGroups).toHaveLength(1);
191
174
  expect(parentGroups).toContainEqual(
192
- expect.objectContaining({ id: parentGroup.id }),
175
+ expect.objectContaining({
176
+ $jazz: expect.objectContaining({ id: parentGroup.$jazz.id }),
177
+ }),
193
178
  );
194
179
 
195
180
  expect(parentGroups[0]?.getParentGroups()).toContainEqual(
196
- expect.objectContaining({ id: grandParentGroup.id }),
181
+ expect.objectContaining({
182
+ $jazz: expect.objectContaining({ id: grandParentGroup.$jazz.id }),
183
+ }),
197
184
  );
198
185
  });
199
186
 
200
- test("Account.getParentGroups should return an empty array", async () => {
201
- const account = await co.account().create({
202
- creationProps: { name: "Test Account" },
203
- crypto: Crypto,
204
- });
205
-
206
- const parentGroups = account.getParentGroups();
207
-
208
- expect(parentGroups).toEqual([]);
209
- });
210
-
211
187
  test("waitForSync should resolve when the value is uploaded", async () => {
212
188
  const { clientNode, serverNode, clientAccount } = await setupTwoNodes();
213
189
 
214
190
  const group = Group.create({ owner: clientAccount });
215
191
 
216
- await group.waitForSync({ timeout: 1000 });
192
+ await group.$jazz.waitForSync({ timeout: 1000 });
217
193
 
218
194
  // Killing the client node so the serverNode can't load the map from it
219
195
  clientNode.gracefulShutdown();
220
196
 
221
- const loadedGroup = await serverNode.load(group._raw.id);
197
+ const loadedGroup = await serverNode.load(group.$jazz.raw.id);
222
198
 
223
199
  expect(loadedGroup).not.toBe("unavailable");
224
200
  });
@@ -257,7 +233,7 @@ describe("Group inheritance", () => {
257
233
 
258
234
  test("typescript should show an error when adding a member with a non-account role", async () => {
259
235
  const account = await createJazzTestAccount({});
260
- await account.waitForAllCoValuesSync();
236
+ await account.$jazz.waitForAllCoValuesSync();
261
237
 
262
238
  const group = Group.create();
263
239
 
@@ -270,17 +246,17 @@ describe("Group inheritance", () => {
270
246
 
271
247
  expect(group.members).not.toContainEqual(
272
248
  expect.objectContaining({
273
- id: account.id,
249
+ id: account.$jazz.id,
274
250
  role: "readerInvite",
275
251
  }),
276
252
  );
277
253
 
278
- expect(group.getRoleOf(account.id)).toBe("readerInvite");
254
+ expect(group.getRoleOf(account.$jazz.id)).toBe("readerInvite");
279
255
  });
280
256
 
281
257
  test("adding a group member as writeOnly should fail", async () => {
282
258
  const account = await createJazzTestAccount({});
283
- await account.waitForAllCoValuesSync();
259
+ await account.$jazz.waitForAllCoValuesSync();
284
260
 
285
261
  const parentGroup = Group.create();
286
262
  const group = Group.create();
@@ -292,29 +268,29 @@ describe("Group inheritance", () => {
292
268
 
293
269
  test("Removing member group", async () => {
294
270
  const alice = await createJazzTestAccount({});
295
- await alice.waitForAllCoValuesSync();
271
+ await alice.$jazz.waitForAllCoValuesSync();
296
272
  const bob = await createJazzTestAccount({});
297
- await bob.waitForAllCoValuesSync();
273
+ await bob.$jazz.waitForAllCoValuesSync();
298
274
 
299
275
  const parentGroup = Group.create();
300
276
  // `parentGroup` has `alice` as a writer
301
277
  parentGroup.addMember(alice, "writer");
302
- expect(parentGroup.getRoleOf(alice.id)).toBe("writer");
278
+ expect(parentGroup.getRoleOf(alice.$jazz.id)).toBe("writer");
303
279
 
304
280
  const group = Group.create();
305
281
  // `group` has `bob` as a reader
306
282
  group.addMember(bob, "reader");
307
- expect(group.getRoleOf(bob.id)).toBe("reader");
283
+ expect(group.getRoleOf(bob.$jazz.id)).toBe("reader");
308
284
 
309
285
  group.addMember(parentGroup);
310
286
  // `group` has `parentGroup`'s members (in this case, `alice` as a writer)
311
- expect(group.getRoleOf(bob.id)).toBe("reader");
312
- expect(group.getRoleOf(alice.id)).toBe("writer");
287
+ expect(group.getRoleOf(bob.$jazz.id)).toBe("reader");
288
+ expect(group.getRoleOf(alice.$jazz.id)).toBe("writer");
313
289
 
314
290
  // `group` no longer has `parentGroup`'s members
315
291
  await group.removeMember(parentGroup);
316
- expect(group.getRoleOf(bob.id)).toBe("reader");
317
- expect(group.getRoleOf(alice.id)).toBe(undefined);
292
+ expect(group.getRoleOf(bob.$jazz.id)).toBe("reader");
293
+ expect(group.getRoleOf(alice.$jazz.id)).toBe(undefined);
318
294
  });
319
295
 
320
296
  describe("when creating nested CoValues from a JSON object", () => {
@@ -348,9 +324,9 @@ describe("Group inheritance", () => {
348
324
  const me = co.account().getMe();
349
325
  const task = board.columns[0]![0]!;
350
326
 
351
- const boardAsWriter = await Board.load(board.id, { loadAs: me });
327
+ const boardAsWriter = await Board.load(board.$jazz.id, { loadAs: me });
352
328
  expect(boardAsWriter?.title).toEqual("My board");
353
- const taskAsWriter = await Task.load(task.id, { loadAs: me });
329
+ const taskAsWriter = await Task.load(task.$jazz.id, { loadAs: me });
354
330
  expect(taskAsWriter?.toString()).toEqual("Task 1.1");
355
331
  });
356
332
 
@@ -361,12 +337,14 @@ describe("Group inheritance", () => {
361
337
  });
362
338
 
363
339
  const task = board.columns[0]![0]!;
364
- const taskGroup = task._owner.castAs(Group);
340
+ const taskGroup = task.$jazz.owner;
365
341
  taskGroup.addMember(reader, "reader");
366
342
 
367
- const taskAsReader = await Task.load(task.id, { loadAs: reader });
343
+ const taskAsReader = await Task.load(task.$jazz.id, { loadAs: reader });
368
344
  expect(taskAsReader?.toString()).toEqual("Task 1.1");
369
- const boardAsReader = await Board.load(board.id, { loadAs: reader });
345
+ const boardAsReader = await Board.load(board.$jazz.id, {
346
+ loadAs: reader,
347
+ });
370
348
  expect(boardAsReader).toBeNull();
371
349
  });
372
350
  });
@@ -380,34 +358,34 @@ describe("Group.getRoleOf", () => {
380
358
  test("returns correct role for admin", async () => {
381
359
  const group = Group.create();
382
360
  const admin = await createJazzTestAccount({});
383
- await admin.waitForAllCoValuesSync();
361
+ await admin.$jazz.waitForAllCoValuesSync();
384
362
  group.addMember(admin, "admin");
385
- expect(group.getRoleOf(admin.id)).toBe("admin");
363
+ expect(group.getRoleOf(admin.$jazz.id)).toBe("admin");
386
364
  expect(group.getRoleOf("me")).toBe("admin");
387
365
  });
388
366
 
389
367
  test("returns correct role for writer", async () => {
390
368
  const group = Group.create();
391
369
  const writer = await createJazzTestAccount({});
392
- await writer.waitForAllCoValuesSync();
370
+ await writer.$jazz.waitForAllCoValuesSync();
393
371
  group.addMember(writer, "writer");
394
- expect(group.getRoleOf(writer.id)).toBe("writer");
372
+ expect(group.getRoleOf(writer.$jazz.id)).toBe("writer");
395
373
  });
396
374
 
397
375
  test("returns correct role for reader", async () => {
398
376
  const group = Group.create();
399
377
  const reader = await createJazzTestAccount({});
400
- await reader.waitForAllCoValuesSync();
378
+ await reader.$jazz.waitForAllCoValuesSync();
401
379
  group.addMember(reader, "reader");
402
- expect(group.getRoleOf(reader.id)).toBe("reader");
380
+ expect(group.getRoleOf(reader.$jazz.id)).toBe("reader");
403
381
  });
404
382
 
405
383
  test("returns correct role for writeOnly", async () => {
406
384
  const group = Group.create();
407
385
  const writeOnly = await createJazzTestAccount({});
408
- await writeOnly.waitForAllCoValuesSync();
386
+ await writeOnly.$jazz.waitForAllCoValuesSync();
409
387
  group.addMember(writeOnly, "writeOnly");
410
- expect(group.getRoleOf(writeOnly.id)).toBe("writeOnly");
388
+ expect(group.getRoleOf(writeOnly.$jazz.id)).toBe("writeOnly");
411
389
  });
412
390
 
413
391
  test("returns correct role for everyone", () => {
@@ -429,7 +407,7 @@ describe("Group.getRoleOf with 'me' parameter", () => {
429
407
 
430
408
  test("returns correct role for 'me' when current account is writer", async () => {
431
409
  const account = await createJazzTestAccount();
432
- await account.waitForAllCoValuesSync();
410
+ await account.$jazz.waitForAllCoValuesSync();
433
411
  const group = Group.create({ owner: account });
434
412
 
435
413
  group.addMember(co.account().getMe(), "writer");
@@ -439,7 +417,7 @@ describe("Group.getRoleOf with 'me' parameter", () => {
439
417
 
440
418
  test("returns correct role for 'me' when current account is reader", async () => {
441
419
  const account = await createJazzTestAccount();
442
- await account.waitForAllCoValuesSync();
420
+ await account.$jazz.waitForAllCoValuesSync();
443
421
  const group = Group.create({ owner: account });
444
422
 
445
423
  group.addMember(co.account().getMe(), "reader");
@@ -449,7 +427,7 @@ describe("Group.getRoleOf with 'me' parameter", () => {
449
427
 
450
428
  test("returns undefined for 'me' when current account has no role", async () => {
451
429
  const account = await createJazzTestAccount();
452
- await account.waitForAllCoValuesSync();
430
+ await account.$jazz.waitForAllCoValuesSync();
453
431
  const group = Group.create({ owner: account });
454
432
 
455
433
  expect(group.getRoleOf("me")).toBeUndefined();
@@ -468,7 +446,7 @@ describe("Account permissions", () => {
468
446
  });
469
447
 
470
448
  // Account should be admin of itself
471
- expect(account.getRoleOf(account.id)).toBe("admin");
449
+ expect(account.getRoleOf(account.$jazz.id)).toBe("admin");
472
450
 
473
451
  // The GlobalMe is not this account
474
452
  expect(account.getRoleOf("me")).toBe(undefined);
@@ -479,22 +457,11 @@ describe("Account permissions", () => {
479
457
  creationProps: { name: "Other Account" },
480
458
  crypto: Crypto,
481
459
  });
482
- expect(account.getRoleOf(otherAccount.id)).toBeUndefined();
460
+ expect(account.getRoleOf(otherAccount.$jazz.id)).toBeUndefined();
483
461
 
484
462
  // Everyone should have no role
485
463
  expect(account.getRoleOf("everyone")).toBeUndefined();
486
464
  });
487
-
488
- test("members array only contains self as admin", async () => {
489
- const account = await co.account().create({
490
- creationProps: { name: "Test Account" },
491
- crypto: Crypto,
492
- });
493
-
494
- expect(account.members).toEqual([
495
- { id: account.id, role: "admin", account: account, ref: expect.any(Ref) },
496
- ]);
497
- });
498
465
  });
499
466
 
500
467
  describe("Account permissions", () => {
@@ -612,6 +579,232 @@ describe("Account permissions", () => {
612
579
  expect(nonMember.canWrite(testObject)).toBe(false);
613
580
  expect(nonMember.canAdmin(testObject)).toBe(false);
614
581
  });
582
+
583
+ describe("permissions over Groups and Accounts", () => {
584
+ describe("read", () => {
585
+ test("can read all Accounts", async () => {
586
+ const account = await co.account().create({
587
+ creationProps: { name: "Test Account" },
588
+ crypto: Crypto,
589
+ });
590
+ const otherAccount = await co.account().create({
591
+ creationProps: { name: "Other Account" },
592
+ crypto: Crypto,
593
+ });
594
+ expect(account.canRead(otherAccount)).toBe(true);
595
+ });
596
+
597
+ test("can read all groups", async () => {
598
+ const account = await co.account().create({
599
+ creationProps: { name: "Test Account" },
600
+ crypto: Crypto,
601
+ });
602
+ const group = Group.create();
603
+
604
+ expect(account.canRead(group)).toBe(true);
605
+ });
606
+ });
607
+
608
+ describe("write", () => {
609
+ test("can write Account if it's itself", async () => {
610
+ const account = await co.account().create({
611
+ creationProps: { name: "Test Account" },
612
+ crypto: Crypto,
613
+ });
614
+ expect(account.canWrite(account)).toBe(true);
615
+ });
616
+
617
+ test("cannot write other accounts", async () => {
618
+ const account = await co.account().create({
619
+ creationProps: { name: "Test Account" },
620
+ crypto: Crypto,
621
+ });
622
+ const otherAccount = await co.account().create({
623
+ creationProps: { name: "Other Account" },
624
+ crypto: Crypto,
625
+ });
626
+ expect(account.canWrite(otherAccount)).toBe(false);
627
+ });
628
+
629
+ test("can write Group if it's a writer for that group", async () => {
630
+ const account = await co.account().create({
631
+ creationProps: { name: "Test Account" },
632
+ crypto: Crypto,
633
+ });
634
+ const otherAccount = await co.account().create({
635
+ creationProps: { name: "Other Account" },
636
+ crypto: Crypto,
637
+ });
638
+ const group = Group.create({ owner: otherAccount });
639
+
640
+ group.addMember(account, "writer");
641
+
642
+ expect(account.canWrite(group)).toBe(true);
643
+ });
644
+
645
+ test("can write Group if it's an admin for that group", async () => {
646
+ const account = await co.account().create({
647
+ creationProps: { name: "Test Account" },
648
+ crypto: Crypto,
649
+ });
650
+ const otherAccount = await co.account().create({
651
+ creationProps: { name: "Other Account" },
652
+ crypto: Crypto,
653
+ });
654
+ const group = Group.create({ owner: otherAccount });
655
+
656
+ group.addMember(account, "admin");
657
+
658
+ expect(account.canWrite(group)).toBe(true);
659
+ });
660
+
661
+ test("cannot write Group if it has writeOnly permissions for that group", async () => {
662
+ const account = await co.account().create({
663
+ creationProps: { name: "Test Account" },
664
+ crypto: Crypto,
665
+ });
666
+ const otherAccount = await co.account().create({
667
+ creationProps: { name: "Other Account" },
668
+ crypto: Crypto,
669
+ });
670
+ const group = Group.create({ owner: otherAccount });
671
+
672
+ group.addMember(account, "writeOnly");
673
+
674
+ expect(account.canWrite(group)).toBe(false);
675
+ });
676
+
677
+ test("cannot write Group if it's a reader for that group", async () => {
678
+ const account = await co.account().create({
679
+ creationProps: { name: "Test Account" },
680
+ crypto: Crypto,
681
+ });
682
+ const otherAccount = await co.account().create({
683
+ creationProps: { name: "Other Account" },
684
+ crypto: Crypto,
685
+ });
686
+ const group = Group.create({ owner: otherAccount });
687
+
688
+ group.addMember(account, "reader");
689
+
690
+ expect(account.canWrite(group)).toBe(false);
691
+ });
692
+
693
+ test("cannot write Group if it has no permissions for that group", async () => {
694
+ const account = await co.account().create({
695
+ creationProps: { name: "Test Account" },
696
+ crypto: Crypto,
697
+ });
698
+ const otherAccount = await co.account().create({
699
+ creationProps: { name: "Other Account" },
700
+ crypto: Crypto,
701
+ });
702
+ const group = Group.create({ owner: otherAccount });
703
+
704
+ expect(account.canWrite(group)).toBe(false);
705
+ });
706
+ });
707
+
708
+ describe("admin", () => {
709
+ test("can admin Account if it's itself", async () => {
710
+ const account = await co.account().create({
711
+ creationProps: { name: "Test Account" },
712
+ crypto: Crypto,
713
+ });
714
+ expect(account.canAdmin(account)).toBe(true);
715
+ });
716
+
717
+ test("cannot admin other accounts", async () => {
718
+ const account = await co.account().create({
719
+ creationProps: { name: "Test Account" },
720
+ crypto: Crypto,
721
+ });
722
+ const otherAccount = await co.account().create({
723
+ creationProps: { name: "Other Account" },
724
+ crypto: Crypto,
725
+ });
726
+ expect(account.canAdmin(otherAccount)).toBe(false);
727
+ });
728
+
729
+ test("can admin Group if it's an admin for that group", async () => {
730
+ const account = await co.account().create({
731
+ creationProps: { name: "Test Account" },
732
+ crypto: Crypto,
733
+ });
734
+ const otherAccount = await co.account().create({
735
+ creationProps: { name: "Other Account" },
736
+ crypto: Crypto,
737
+ });
738
+ const group = Group.create({ owner: otherAccount });
739
+
740
+ group.addMember(account, "admin");
741
+
742
+ expect(account.canAdmin(group)).toBe(true);
743
+ });
744
+
745
+ test("cannot admin Group if it's a writer for that group", async () => {
746
+ const account = await co.account().create({
747
+ creationProps: { name: "Test Account" },
748
+ crypto: Crypto,
749
+ });
750
+ const otherAccount = await co.account().create({
751
+ creationProps: { name: "Other Account" },
752
+ crypto: Crypto,
753
+ });
754
+ const group = Group.create({ owner: otherAccount });
755
+
756
+ group.addMember(account, "writer");
757
+
758
+ expect(account.canAdmin(group)).toBe(false);
759
+ });
760
+
761
+ test("cannot admin Group if it has writeOnly permissions for that group", async () => {
762
+ const account = await co.account().create({
763
+ creationProps: { name: "Test Account" },
764
+ crypto: Crypto,
765
+ });
766
+ const otherAccount = await co.account().create({
767
+ creationProps: { name: "Other Account" },
768
+ crypto: Crypto,
769
+ });
770
+ const group = Group.create({ owner: otherAccount });
771
+
772
+ group.addMember(account, "writeOnly");
773
+
774
+ expect(account.canAdmin(group)).toBe(false);
775
+ });
776
+
777
+ test("cannot write Group if it's a reader for that group", async () => {
778
+ const account = await co.account().create({
779
+ creationProps: { name: "Test Account" },
780
+ crypto: Crypto,
781
+ });
782
+ const otherAccount = await co.account().create({
783
+ creationProps: { name: "Other Account" },
784
+ crypto: Crypto,
785
+ });
786
+ const group = Group.create({ owner: otherAccount });
787
+
788
+ group.addMember(account, "reader");
789
+
790
+ expect(account.canAdmin(group)).toBe(false);
791
+ });
792
+
793
+ test("cannot write Group if it has no permissions for that group", async () => {
794
+ const account = await co.account().create({
795
+ creationProps: { name: "Test Account" },
796
+ crypto: Crypto,
797
+ });
798
+ const otherAccount = await co.account().create({
799
+ creationProps: { name: "Other Account" },
800
+ crypto: Crypto,
801
+ });
802
+ const group = Group.create({ owner: otherAccount });
803
+
804
+ expect(account.canAdmin(group)).toBe(false);
805
+ });
806
+ });
807
+ });
615
808
  });
616
809
 
617
810
  describe("Group.members", () => {
@@ -619,21 +812,25 @@ describe("Group.members", () => {
619
812
  const childGroup = Group.create();
620
813
 
621
814
  const bob = await createJazzTestAccount({});
622
- await bob.waitForAllCoValuesSync();
815
+ await bob.$jazz.waitForAllCoValuesSync();
623
816
 
624
817
  childGroup.addMember(bob, "reader");
625
- expect(childGroup.getRoleOf(bob.id)).toBe("reader");
818
+ expect(childGroup.getRoleOf(bob.$jazz.id)).toBe("reader");
626
819
 
627
820
  expect(childGroup.members).toEqual([
628
821
  expect.objectContaining({
629
822
  account: expect.objectContaining({
630
- id: co.account().getMe().id,
823
+ $jazz: expect.objectContaining({
824
+ id: co.account().getMe().$jazz.id,
825
+ }),
631
826
  }),
632
827
  role: "admin",
633
828
  }),
634
829
  expect.objectContaining({
635
830
  account: expect.objectContaining({
636
- id: bob.id,
831
+ $jazz: expect.objectContaining({
832
+ id: bob.$jazz.id,
833
+ }),
637
834
  }),
638
835
  role: "reader",
639
836
  }),
@@ -645,23 +842,27 @@ describe("Group.members", () => {
645
842
  const parentGroup = Group.create();
646
843
 
647
844
  const bob = await createJazzTestAccount({});
648
- await bob.waitForAllCoValuesSync();
845
+ await bob.$jazz.waitForAllCoValuesSync();
649
846
 
650
847
  parentGroup.addMember(bob, "writer");
651
848
  childGroup.addMember(parentGroup, "reader");
652
849
 
653
- expect(childGroup.getRoleOf(bob.id)).toBe("reader");
850
+ expect(childGroup.getRoleOf(bob.$jazz.id)).toBe("reader");
654
851
 
655
852
  expect(childGroup.members).toEqual([
656
853
  expect.objectContaining({
657
854
  account: expect.objectContaining({
658
- id: co.account().getMe().id,
855
+ $jazz: expect.objectContaining({
856
+ id: co.account().getMe().$jazz.id,
857
+ }),
659
858
  }),
660
859
  role: "admin",
661
860
  }),
662
861
  expect.objectContaining({
663
862
  account: expect.objectContaining({
664
- id: bob.id,
863
+ $jazz: expect.objectContaining({
864
+ id: bob.$jazz.id,
865
+ }),
665
866
  }),
666
867
  role: "reader",
667
868
  }),
@@ -677,7 +878,9 @@ describe("Group.members", () => {
677
878
  expect(childGroup.members).toEqual([
678
879
  expect.objectContaining({
679
880
  account: expect.objectContaining({
680
- id: co.account().getMe().id,
881
+ $jazz: expect.objectContaining({
882
+ id: co.account().getMe().$jazz.id,
883
+ }),
681
884
  }),
682
885
  role: "admin",
683
886
  }),
@@ -688,17 +891,19 @@ describe("Group.members", () => {
688
891
  const childGroup = Group.create();
689
892
 
690
893
  const bob = await createJazzTestAccount({});
691
- await bob.waitForAllCoValuesSync();
894
+ await bob.$jazz.waitForAllCoValuesSync();
692
895
 
693
896
  childGroup.addMember(bob, "reader");
694
897
  await childGroup.removeMember(bob);
695
898
 
696
- expect(childGroup.getRoleOf(bob.id)).toBeUndefined();
899
+ expect(childGroup.getRoleOf(bob.$jazz.id)).toBeUndefined();
697
900
 
698
901
  expect(childGroup.members).toEqual([
699
902
  expect.objectContaining({
700
903
  account: expect.objectContaining({
701
- id: co.account().getMe().id,
904
+ $jazz: expect.objectContaining({
905
+ id: co.account().getMe().$jazz.id,
906
+ }),
702
907
  }),
703
908
  role: "admin",
704
909
  }),
@@ -712,7 +917,7 @@ describe("Group.getDirectMembers", () => {
712
917
  const childGroup = Group.create();
713
918
 
714
919
  const bob = await createJazzTestAccount({});
715
- await bob.waitForAllCoValuesSync();
920
+ await bob.$jazz.waitForAllCoValuesSync();
716
921
 
717
922
  // Add bob to parent group
718
923
  parentGroup.addMember(bob, "reader");
@@ -724,12 +929,16 @@ describe("Group.getDirectMembers", () => {
724
929
  expect(childGroup.members).toEqual([
725
930
  expect.objectContaining({
726
931
  account: expect.objectContaining({
727
- id: co.account().getMe().id,
932
+ $jazz: expect.objectContaining({
933
+ id: co.account().getMe().$jazz.id,
934
+ }),
728
935
  }),
729
936
  }),
730
937
  expect.objectContaining({
731
938
  account: expect.objectContaining({
732
- id: bob.id,
939
+ $jazz: expect.objectContaining({
940
+ id: bob.$jazz.id,
941
+ }),
733
942
  }),
734
943
  }),
735
944
  ]);
@@ -738,7 +947,9 @@ describe("Group.getDirectMembers", () => {
738
947
  expect(childGroup.getDirectMembers()).toEqual([
739
948
  expect.objectContaining({
740
949
  account: expect.objectContaining({
741
- id: co.account().getMe().id,
950
+ $jazz: expect.objectContaining({
951
+ id: co.account().getMe().$jazz.id,
952
+ }),
742
953
  }),
743
954
  }),
744
955
  ]);
@@ -747,7 +958,9 @@ describe("Group.getDirectMembers", () => {
747
958
  expect(childGroup.getDirectMembers()).not.toContainEqual(
748
959
  expect.objectContaining({
749
960
  account: expect.objectContaining({
750
- id: bob.id,
961
+ $jazz: expect.objectContaining({
962
+ id: bob.$jazz.id,
963
+ }),
751
964
  }),
752
965
  }),
753
966
  );
@@ -756,12 +969,16 @@ describe("Group.getDirectMembers", () => {
756
969
  expect(parentGroup.getDirectMembers()).toEqual([
757
970
  expect.objectContaining({
758
971
  account: expect.objectContaining({
759
- id: co.account().getMe().id,
972
+ $jazz: expect.objectContaining({
973
+ id: co.account().getMe().$jazz.id,
974
+ }),
760
975
  }),
761
976
  }),
762
977
  expect.objectContaining({
763
978
  account: expect.objectContaining({
764
- id: bob.id,
979
+ $jazz: expect.objectContaining({
980
+ id: bob.$jazz.id,
981
+ }),
765
982
  }),
766
983
  }),
767
984
  ]);