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.
Files changed (151) hide show
  1. package/.turbo/turbo-build.log +51 -51
  2. package/CHANGELOG.md +22 -0
  3. package/dist/browser/createBrowserContext.d.ts +1 -5
  4. package/dist/browser/createBrowserContext.d.ts.map +1 -1
  5. package/dist/browser/index.js +124 -47
  6. package/dist/browser/index.js.map +1 -1
  7. package/dist/browser/provideBrowserLockSession/BrowserSessionProvider.d.ts +12 -0
  8. package/dist/browser/provideBrowserLockSession/BrowserSessionProvider.d.ts.map +1 -0
  9. package/dist/browser/provideBrowserLockSession/BrowserSessionProvider.test.d.ts +2 -0
  10. package/dist/browser/provideBrowserLockSession/BrowserSessionProvider.test.d.ts.map +1 -0
  11. package/dist/browser/provideBrowserLockSession/SessionIDStorage.d.ts +6 -0
  12. package/dist/browser/provideBrowserLockSession/SessionIDStorage.d.ts.map +1 -0
  13. package/dist/browser/provideBrowserLockSession/index.d.ts +4 -0
  14. package/dist/browser/provideBrowserLockSession/index.d.ts.map +1 -0
  15. package/dist/{chunk-HX5S6W5E.js → chunk-GAPMDNJY.js} +492 -108
  16. package/dist/chunk-GAPMDNJY.js.map +1 -0
  17. package/dist/index.js +5 -3
  18. package/dist/index.js.map +1 -1
  19. package/dist/inspector/{chunk-C6BJPHBQ.js → chunk-YQNK5Y7B.js} +47 -35
  20. package/dist/inspector/chunk-YQNK5Y7B.js.map +1 -0
  21. package/dist/inspector/{custom-element-GJVBPZES.js → custom-element-KYV64IOC.js} +47 -35
  22. package/dist/inspector/{custom-element-GJVBPZES.js.map → custom-element-KYV64IOC.js.map} +1 -1
  23. package/dist/inspector/index.js +1 -1
  24. package/dist/inspector/register-custom-element.js +1 -1
  25. package/dist/inspector/standalone.js +1 -1
  26. package/dist/inspector/tests/utils/transactions-changes.test.d.ts +2 -0
  27. package/dist/inspector/tests/utils/transactions-changes.test.d.ts.map +1 -0
  28. package/dist/inspector/utils/transactions-changes.d.ts +13 -13
  29. package/dist/inspector/utils/transactions-changes.d.ts.map +1 -1
  30. package/dist/react/index.js +4 -1
  31. package/dist/react/index.js.map +1 -1
  32. package/dist/react/provider.d.ts.map +1 -1
  33. package/dist/react-core/index.js +2 -2
  34. package/dist/react-core/index.js.map +1 -1
  35. package/dist/react-native/index.js +45 -13
  36. package/dist/react-native/index.js.map +1 -1
  37. package/dist/react-native-core/ReactNativeSessionProvider.d.ts +11 -0
  38. package/dist/react-native-core/ReactNativeSessionProvider.d.ts.map +1 -0
  39. package/dist/react-native-core/index.js +45 -13
  40. package/dist/react-native-core/index.js.map +1 -1
  41. package/dist/react-native-core/platform.d.ts +2 -8
  42. package/dist/react-native-core/platform.d.ts.map +1 -1
  43. package/dist/react-native-core/provider.d.ts.map +1 -1
  44. package/dist/react-native-core/tests/ReactNativeSessionProvider.test.d.ts +2 -0
  45. package/dist/react-native-core/tests/ReactNativeSessionProvider.test.d.ts.map +1 -0
  46. package/dist/testing.js +4 -3
  47. package/dist/testing.js.map +1 -1
  48. package/dist/tools/coValues/account.d.ts.map +1 -1
  49. package/dist/tools/coValues/coFeed.d.ts +2 -2
  50. package/dist/tools/coValues/coFeed.d.ts.map +1 -1
  51. package/dist/tools/coValues/coList.d.ts +1 -2
  52. package/dist/tools/coValues/coList.d.ts.map +1 -1
  53. package/dist/tools/coValues/coMap.d.ts.map +1 -1
  54. package/dist/tools/coValues/coVector.d.ts.map +1 -1
  55. package/dist/tools/coValues/group.d.ts +5 -1
  56. package/dist/tools/coValues/group.d.ts.map +1 -1
  57. package/dist/tools/coValues/interfaces.d.ts +2 -1
  58. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  59. package/dist/tools/exports.d.ts +2 -2
  60. package/dist/tools/exports.d.ts.map +1 -1
  61. package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
  62. package/dist/tools/implementation/createContext.d.ts +21 -11
  63. package/dist/tools/implementation/createContext.d.ts.map +1 -1
  64. package/dist/tools/implementation/schema.d.ts +14 -6
  65. package/dist/tools/implementation/schema.d.ts.map +1 -1
  66. package/dist/tools/implementation/schemaUtils.d.ts +1 -1
  67. package/dist/tools/implementation/schemaUtils.d.ts.map +1 -1
  68. package/dist/tools/implementation/zodSchema/runtimeConverters/schemaFieldToCoFieldDef.d.ts.map +1 -1
  69. package/dist/tools/implementation/zodSchema/schemaPermissions.d.ts +99 -0
  70. package/dist/tools/implementation/zodSchema/schemaPermissions.d.ts.map +1 -0
  71. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +11 -0
  72. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  73. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +11 -0
  74. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  75. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +15 -1
  76. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  77. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +10 -0
  78. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
  79. package/dist/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.d.ts +9 -0
  80. package/dist/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.d.ts.map +1 -1
  81. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +13 -1
  82. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  83. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +10 -0
  84. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
  85. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +6 -0
  86. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
  87. package/dist/tools/implementation/zodSchema/unionUtils.d.ts +12 -1
  88. package/dist/tools/implementation/zodSchema/unionUtils.d.ts.map +1 -1
  89. package/dist/tools/internal.d.ts +1 -0
  90. package/dist/tools/internal.d.ts.map +1 -1
  91. package/dist/tools/subscribe/SubscriptionScope.d.ts +3 -6
  92. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  93. package/dist/tools/testing.d.ts.map +1 -1
  94. package/dist/tools/tests/schema.withPermissions.test.d.ts +2 -0
  95. package/dist/tools/tests/schema.withPermissions.test.d.ts.map +1 -0
  96. package/dist/worker/index.js +2 -2
  97. package/dist/worker/index.js.map +1 -1
  98. package/package.json +4 -4
  99. package/src/browser/createBrowserContext.ts +3 -62
  100. package/src/browser/provideBrowserLockSession/BrowserSessionProvider.test.ts +406 -0
  101. package/src/browser/provideBrowserLockSession/BrowserSessionProvider.ts +132 -0
  102. package/src/browser/provideBrowserLockSession/SessionIDStorage.ts +33 -0
  103. package/src/browser/provideBrowserLockSession/index.ts +11 -0
  104. package/src/inspector/tests/utils/transactions-changes.test.ts +102 -0
  105. package/src/inspector/ui/icons/add-icon.tsx +3 -3
  106. package/src/inspector/utils/history.ts +6 -6
  107. package/src/inspector/utils/transactions-changes.ts +37 -3
  108. package/src/inspector/viewer/history-view.tsx +13 -13
  109. package/src/react/provider.tsx +6 -1
  110. package/src/react-core/hooks.ts +2 -2
  111. package/src/react-core/tests/useSuspenseCoState.test.tsx +47 -0
  112. package/src/react-native-core/ReactNativeSessionProvider.ts +52 -0
  113. package/src/react-native-core/platform.ts +5 -30
  114. package/src/react-native-core/provider.tsx +6 -1
  115. package/src/react-native-core/tests/ReactNativeSessionProvider.test.ts +124 -0
  116. package/src/tools/coValues/account.ts +4 -0
  117. package/src/tools/coValues/coFeed.ts +8 -3
  118. package/src/tools/coValues/coList.ts +6 -3
  119. package/src/tools/coValues/coMap.ts +10 -0
  120. package/src/tools/coValues/coVector.ts +2 -1
  121. package/src/tools/coValues/group.ts +6 -4
  122. package/src/tools/coValues/interfaces.ts +19 -7
  123. package/src/tools/exports.ts +3 -1
  124. package/src/tools/implementation/ContextManager.ts +10 -0
  125. package/src/tools/implementation/createContext.ts +43 -15
  126. package/src/tools/implementation/schema.ts +23 -13
  127. package/src/tools/implementation/schemaUtils.ts +1 -1
  128. package/src/tools/implementation/zodSchema/runtimeConverters/schemaFieldToCoFieldDef.ts +105 -4
  129. package/src/tools/implementation/zodSchema/schemaPermissions.ts +188 -0
  130. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +46 -3
  131. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +46 -3
  132. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +50 -13
  133. package/src/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +14 -0
  134. package/src/tools/implementation/zodSchema/schemaTypes/CoVectorSchema.ts +24 -1
  135. package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +51 -4
  136. package/src/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +25 -1
  137. package/src/tools/implementation/zodSchema/schemaTypes/RichTextSchema.ts +21 -1
  138. package/src/tools/implementation/zodSchema/unionUtils.ts +72 -20
  139. package/src/tools/internal.ts +1 -0
  140. package/src/tools/subscribe/SubscriptionScope.ts +61 -39
  141. package/src/tools/testing.ts +3 -1
  142. package/src/tools/tests/ContextManager.test.ts +2 -1
  143. package/src/tools/tests/coPlainText.test.ts +2 -2
  144. package/src/tools/tests/createContext.test.ts +79 -1
  145. package/src/tools/tests/deepLoading.test.ts +25 -2
  146. package/src/tools/tests/schema.resolved.test.ts +10 -0
  147. package/src/tools/tests/schema.withPermissions.test.ts +859 -0
  148. package/src/tools/tests/utils.ts +2 -2
  149. package/src/worker/index.ts +2 -2
  150. package/dist/chunk-HX5S6W5E.js.map +0 -1
  151. package/dist/inspector/chunk-C6BJPHBQ.js.map +0 -1
@@ -26,8 +26,6 @@ import {
26
26
  getIdFromHeader,
27
27
  internalLoadUnique,
28
28
  CoValueLoadingState,
29
- } from "../internal.js";
30
- import {
31
29
  AnonymousJazzAgent,
32
30
  ItemsSym,
33
31
  Ref,
@@ -172,8 +170,8 @@ export class CoList<out Item = any>
172
170
  | Account
173
171
  | Group,
174
172
  ) {
175
- const { owner, uniqueness } = parseCoValueCreateOptions(options);
176
173
  const instance = new this();
174
+ const { owner, uniqueness } = parseCoValueCreateOptions(options);
177
175
 
178
176
  Object.defineProperties(instance, {
179
177
  $jazz: {
@@ -918,10 +916,15 @@ function toRawItems<Item>(
918
916
  }
919
917
  let refId = (value as unknown as CoValue).$jazz?.id;
920
918
  if (!refId) {
919
+ const newOwnerStrategy =
920
+ itemDescriptor.permissions?.newInlineOwnerStrategy;
921
+ const onCreate = itemDescriptor.permissions?.onCreate;
921
922
  const coValue = instantiateRefEncodedWithInit(
922
923
  itemDescriptor,
923
924
  value,
924
925
  owner,
926
+ newOwnerStrategy,
927
+ onCreate,
925
928
  );
926
929
  refId = coValue.$jazz.id;
927
930
  }
@@ -298,10 +298,15 @@ export class CoMap extends CoValueBase implements CoValue {
298
298
  if (initValue != null) {
299
299
  let refId = (initValue as unknown as CoValue).$jazz?.id;
300
300
  if (!refId) {
301
+ const newOwnerStrategy =
302
+ descriptor.permissions?.newInlineOwnerStrategy;
303
+ const onCreate = descriptor.permissions?.onCreate;
301
304
  const coValue = instantiateRefEncodedWithInit(
302
305
  descriptor,
303
306
  initValue,
304
307
  owner,
308
+ newOwnerStrategy,
309
+ onCreate,
305
310
  );
306
311
  refId = coValue.$jazz.id;
307
312
  }
@@ -610,10 +615,15 @@ class CoMapJazzApi<M extends CoMap> extends CoValueJazzApi<M> {
610
615
  this.raw.set(key, null);
611
616
  } else {
612
617
  if (!refId) {
618
+ const newOwnerStrategy =
619
+ descriptor.permissions?.newInlineOwnerStrategy;
620
+ const onCreate = descriptor.permissions?.onCreate;
613
621
  const coValue = instantiateRefEncodedWithInit(
614
622
  descriptor,
615
623
  value,
616
624
  this.owner,
625
+ newOwnerStrategy,
626
+ onCreate,
617
627
  );
618
628
  refId = coValue.$jazz.id;
619
629
  }
@@ -129,7 +129,8 @@ export class CoVector
129
129
  );
130
130
  }
131
131
 
132
- const coVector = new this(parseCoValueCreateOptions(options));
132
+ const { owner } = parseCoValueCreateOptions(options);
133
+ const coVector = new this({ owner });
133
134
  coVector.setVectorData(vectorAsFloat32Array);
134
135
 
135
136
  const byteArray = CoVector.toByteArray(vectorAsFloat32Array);
@@ -48,6 +48,11 @@ type GroupMember = {
48
48
  account: Account;
49
49
  };
50
50
 
51
+ /**
52
+ * Roles that can be granted to a group member.
53
+ */
54
+ export type GroupRole = "reader" | "writer" | "admin" | "manager";
55
+
51
56
  /** @category Identity & Permissions */
52
57
  export class Group extends CoValueBase implements CoValue {
53
58
  declare [TypeSym]: "Group";
@@ -107,10 +112,7 @@ export class Group extends CoValueBase implements CoValue {
107
112
  * @param member The group that will gain access to this group.
108
113
  * @param role The role all members of the parent group should have in this group.
109
114
  */
110
- addMember(
111
- member: Group,
112
- role?: "reader" | "writer" | "admin" | "manager" | "inherit",
113
- ): void;
115
+ addMember(member: Group, role?: GroupRole | "inherit"): void;
114
116
  addMember(
115
117
  member: Group | Account,
116
118
  role: "reader" | "writer" | "admin" | "manager",
@@ -11,10 +11,11 @@ import {
11
11
  CoValueClassOrSchema,
12
12
  CoValueLoadingState,
13
13
  NotLoadedCoValueState,
14
- type Group,
14
+ Group,
15
15
  Loaded,
16
16
  Inaccessible,
17
17
  MaybeLoaded,
18
+ OnCreateCallback,
18
19
  Settled,
19
20
  RefsToResolve,
20
21
  RefsToResolveStrict,
@@ -424,6 +425,7 @@ export function parseCoValueCreateOptions(
424
425
  | {
425
426
  owner?: Account | Group;
426
427
  unique?: CoValueUniqueness["uniqueness"];
428
+ onCreate?: OnCreateCallback;
427
429
  }
428
430
  | Account
429
431
  | Group
@@ -432,16 +434,22 @@ export function parseCoValueCreateOptions(
432
434
  owner: Group;
433
435
  uniqueness?: CoValueUniqueness;
434
436
  } {
437
+ const onCreate =
438
+ options && "onCreate" in options ? options.onCreate : undefined;
435
439
  const Group = RegisteredSchemas["Group"];
436
-
437
440
  if (!options) {
438
- return { owner: Group.create(), uniqueness: undefined };
441
+ const owner = Group.create();
442
+ onCreate?.(owner);
443
+ return { owner, uniqueness: undefined };
439
444
  }
440
445
 
441
446
  if (TypeSym in options) {
442
447
  if (options[TypeSym] === "Account") {
443
- return { owner: accountOrGroupToGroup(options), uniqueness: undefined };
448
+ const owner = accountOrGroupToGroup(options);
449
+ onCreate?.(owner);
450
+ return { owner, uniqueness: undefined };
444
451
  } else if (options[TypeSym] === "Group") {
452
+ onCreate?.(options);
445
453
  return { owner: options, uniqueness: undefined };
446
454
  }
447
455
  }
@@ -450,10 +458,14 @@ export function parseCoValueCreateOptions(
450
458
  ? { uniqueness: options.unique }
451
459
  : undefined;
452
460
 
461
+ const owner = options.owner
462
+ ? accountOrGroupToGroup(options.owner)
463
+ : Group.create();
464
+
465
+ onCreate?.(owner);
466
+
453
467
  const opts = {
454
- owner: options.owner
455
- ? accountOrGroupToGroup(options.owner)
456
- : Group.create(),
468
+ owner,
457
469
  uniqueness,
458
470
  };
459
471
  return opts;
@@ -66,6 +66,7 @@ export {
66
66
  createUnloadedCoValue,
67
67
  unstable_loadUnique,
68
68
  getUnloadedCoValueWithoutId,
69
+ setDefaultSchemaPermissions,
69
70
  } from "./internal.js";
70
71
 
71
72
  export {
@@ -100,7 +101,8 @@ export {
100
101
  createJazzContextFromExistingCredentials,
101
102
  createJazzContextForNewAccount,
102
103
  createJazzContext,
103
- randomSessionProvider,
104
+ SessionProvider,
105
+ MockSessionProvider,
104
106
  type AuthResult,
105
107
  type Credentials,
106
108
  type JazzContextWithAccount,
@@ -351,6 +351,16 @@ export class JazzContextManager<
351
351
  // The storage is reachable through currentContext using the connectedPeers
352
352
  prevContext.node.removeStorage();
353
353
 
354
+ // Ensure that the new context is the only peer connected to the previous context
355
+ // This way all the changes made in the previous context are synced only to the new context
356
+ for (const peer of Object.values(prevContext.node.syncManager.peers)) {
357
+ if (!peer.closed) {
358
+ peer.gracefulShutdown();
359
+ }
360
+ }
361
+
362
+ prevContext.node.syncManager.peers = {};
363
+
354
364
  currentContext.node.syncManager.addPeer(prevAccountAsPeer);
355
365
  prevContext.node.syncManager.addPeer(currentAccountAsPeer);
356
366
 
@@ -28,10 +28,39 @@ export type Credentials = {
28
28
  secret: AgentSecret;
29
29
  };
30
30
 
31
- type SessionProvider = (
32
- accountID: ID<Account>,
33
- crypto: CryptoProvider,
34
- ) => Promise<{ sessionID: SessionID; sessionDone: () => void }>;
31
+ export interface SessionProvider {
32
+ acquireSession: (
33
+ accountID: ID<Account>,
34
+ crypto: CryptoProvider,
35
+ ) => Promise<{ sessionID: SessionID; sessionDone: () => void }>;
36
+ persistSession: (
37
+ accountID: ID<Account>,
38
+ sessionID: SessionID,
39
+ ) => Promise<{ sessionDone: () => void }>;
40
+ }
41
+
42
+ export class MockSessionProvider implements SessionProvider {
43
+ async acquireSession(
44
+ accountID: ID<Account>,
45
+ crypto: CryptoProvider,
46
+ ): Promise<{ sessionID: SessionID; sessionDone: () => void }> {
47
+ return {
48
+ sessionID: crypto.newRandomSessionID(
49
+ accountID as unknown as RawAccountID,
50
+ ),
51
+ sessionDone: () => {},
52
+ };
53
+ }
54
+
55
+ async persistSession(
56
+ _accountID: ID<Account>,
57
+ _sessionID: SessionID,
58
+ ): Promise<{ sessionDone: () => void }> {
59
+ return {
60
+ sessionDone: () => {},
61
+ };
62
+ }
63
+ }
35
64
 
36
65
  export type AuthResult =
37
66
  | {
@@ -57,16 +86,6 @@ export type AuthResult =
57
86
  logOut: () => Promise<void>;
58
87
  };
59
88
 
60
- export async function randomSessionProvider(
61
- accountID: ID<Account>,
62
- crypto: CryptoProvider,
63
- ) {
64
- return {
65
- sessionID: crypto.newRandomSessionID(accountID as unknown as RawAccountID),
66
- sessionDone: () => {},
67
- };
68
- }
69
-
70
89
  export type JazzContextWithAccount<Acc extends Account> = {
71
90
  node: LocalNode;
72
91
  account: Acc;
@@ -107,7 +126,7 @@ export async function createJazzContextFromExistingCredentials<
107
126
  storage?: StorageAPI;
108
127
  asActiveAccount: boolean;
109
128
  }): Promise<JazzContextWithAccount<InstanceOfSchema<S>>> {
110
- const { sessionID, sessionDone } = await sessionProvider(
129
+ const { sessionID, sessionDone } = await sessionProvider.acquireSession(
111
130
  credentials.accountID,
112
131
  crypto,
113
132
  );
@@ -167,6 +186,7 @@ export async function createJazzContextForNewAccount<
167
186
  AccountSchema: PropsAccountSchema,
168
187
  onLogOut,
169
188
  storage,
189
+ sessionProvider,
170
190
  }: {
171
191
  creationProps: { name: string };
172
192
  initialAgentSecret?: AgentSecret;
@@ -175,6 +195,7 @@ export async function createJazzContextForNewAccount<
175
195
  AccountSchema?: S;
176
196
  onLogOut?: () => Promise<void>;
177
197
  storage?: StorageAPI;
198
+ sessionProvider: SessionProvider;
178
199
  }): Promise<JazzContextWithAccount<InstanceOfSchema<S>>> {
179
200
  const CurrentAccountSchema =
180
201
  PropsAccountSchema ?? (RegisteredSchemas["Account"] as unknown as S);
@@ -199,11 +220,17 @@ export async function createJazzContextForNewAccount<
199
220
  const account = AccountClass.fromNode(node);
200
221
  activeAccountContext.set(account);
201
222
 
223
+ const { sessionDone } = await sessionProvider.persistSession(
224
+ account.$jazz.id,
225
+ node.currentSessionID,
226
+ );
227
+
202
228
  return {
203
229
  node,
204
230
  account: account as InstanceOfSchema<S>,
205
231
  done: () => {
206
232
  node.gracefulShutdown();
233
+ sessionDone();
207
234
  },
208
235
  logOut: async () => {
209
236
  node.gracefulShutdown();
@@ -270,6 +297,7 @@ export async function createJazzContext<
270
297
  peers: options.peers,
271
298
  crypto,
272
299
  AccountSchema: options.AccountSchema,
300
+ sessionProvider: options.sessionProvider,
273
301
  onLogOut: async () => {
274
302
  await authSecretStorage.clearWithoutNotify();
275
303
  },
@@ -5,9 +5,14 @@ import {
5
5
  type CoValue,
6
6
  type CoValueClass,
7
7
  CoValueFromRaw,
8
+ extendContainerOwner,
8
9
  Group,
10
+ type GroupRole,
9
11
  ItemsSym,
10
12
  LoadedAndRequired,
13
+ type NewInlineOwnerStrategy,
14
+ type RefOnCreateCallback,
15
+ type RefPermissions,
11
16
  SchemaInit,
12
17
  isCoValueClass,
13
18
  } from "../internal.js";
@@ -94,31 +99,33 @@ export const coField = {
94
99
 
95
100
  function optionalRef<C extends CoValueClass>(
96
101
  arg: C | ((raw: InstanceType<C>["$jazz"]["raw"]) => C),
102
+ options: { permissions: RefPermissions },
97
103
  ): InstanceType<C> | null | undefined {
98
- return ref(arg, { optional: true });
104
+ return ref(arg, { optional: true, permissions: options.permissions });
99
105
  }
100
106
 
101
107
  function ref<C extends CoValueClass>(
102
108
  arg: C | ((raw: InstanceType<C>["$jazz"]["raw"]) => C),
103
- options?: never,
109
+ options: { permissions?: RefPermissions },
104
110
  ): InstanceType<C> | null;
105
111
  function ref<C extends CoValueClass>(
106
112
  arg: C | ((raw: InstanceType<C>["$jazz"]["raw"]) => C),
107
- options: { optional: true },
113
+ options: { optional: true; permissions?: RefPermissions },
108
114
  ): InstanceType<C> | null | undefined;
109
115
  function ref<
110
116
  C extends CoValueClass,
111
- Options extends { optional?: boolean } | undefined,
117
+ Options extends { optional?: boolean; permissions?: RefPermissions },
112
118
  >(
113
119
  arg: C | ((raw: InstanceType<C>["$jazz"]["raw"]) => C),
114
- options?: Options,
120
+ options: Options,
115
121
  ): Options extends { optional: true }
116
122
  ? InstanceType<C> | null | undefined
117
123
  : InstanceType<C> | null {
118
124
  return {
119
125
  [SchemaInit]: {
120
126
  ref: arg,
121
- optional: options?.optional || false,
127
+ optional: options.optional || false,
128
+ permissions: options.permissions,
122
129
  } satisfies Schema,
123
130
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
131
  } as any;
@@ -129,6 +136,7 @@ export type EncodedAs<V> = { encoded: Encoder<V> | OptionalEncoder<V> };
129
136
  export type RefEncoded<V extends CoValue> = {
130
137
  ref: CoValueClass<V> | ((raw: RawCoValue) => CoValueClass<V>);
131
138
  optional: boolean;
139
+ permissions?: RefPermissions;
132
140
  };
133
141
 
134
142
  export function isRefEncoded<V extends CoValue>(
@@ -158,24 +166,26 @@ export function instantiateRefEncodedFromRaw<V extends CoValue>(
158
166
  *
159
167
  * @param schema - The schema of the CoValue to create.
160
168
  * @param init - The init values to use to create the CoValue.
161
- * @param parentOwner - The owner of the referencing CoValue. Will be used
162
- * as the parent group of the created CoValue's group
169
+ * @param containerOwner - The owner of the referencing CoValue. Will be used
170
+ * to determine the owner of the new CoValue
171
+ * @param newOwnerStrategy - The strategy to use to determine the owner of the new CoValue
172
+ * @param onCreate - The callback to call when the new CoValue is created
163
173
  * @returns The created CoValue.
164
174
  */
165
175
  export function instantiateRefEncodedWithInit<V extends CoValue>(
166
176
  schema: RefEncoded<V>,
167
177
  init: any,
168
- parentOwner: Group,
178
+ containerOwner: Group,
179
+ newOwnerStrategy: NewInlineOwnerStrategy = extendContainerOwner,
180
+ onCreate?: RefOnCreateCallback,
169
181
  ): V {
170
182
  if (!isCoValueClass<V>(schema.ref)) {
171
183
  throw Error(
172
184
  `Cannot automatically create CoValue from value: ${JSON.stringify(init)}. Use the CoValue schema's create() method instead.`,
173
185
  );
174
186
  }
175
- const node = parentOwner.$jazz.localNode;
176
- const rawGroup = node.createGroup();
177
- const owner = new Group({ fromRaw: rawGroup });
178
- owner.addMember(parentOwner);
187
+ const owner = newOwnerStrategy(() => Group.create(), containerOwner, init);
188
+ onCreate?.(owner, init);
179
189
  // @ts-expect-error - create is a static method in all CoValue classes
180
190
  return schema.ref.create(init, owner);
181
191
  }
@@ -1,4 +1,4 @@
1
- import { CoreResolveQuery } from "./zodSchema/schemaTypes/CoValueSchema";
1
+ import { CoreResolveQuery } from "./zodSchema/schemaTypes/CoValueSchema.js";
2
2
 
3
3
  /**
4
4
  * Remove getters from an object
@@ -1,8 +1,24 @@
1
1
  import type { JsonValue } from "cojson";
2
- import { CoValueClass, isCoValueClass } from "../../../internal.js";
2
+ import {
3
+ CoValueClass,
4
+ isCoValueClass,
5
+ schemaToRefPermissions,
6
+ getDefaultRefPermissions,
7
+ SchemaPermissions,
8
+ RefPermissions,
9
+ type NewInlineOwnerStrategy,
10
+ type CoreCoDiscriminatedUnionSchema,
11
+ type DiscriminableCoValueSchemas,
12
+ type RefOnCreateCallback,
13
+ } from "../../../internal.js";
3
14
  import { coField } from "../../schema.js";
4
15
  import { CoreCoValueSchema } from "../schemaTypes/CoValueSchema.js";
5
- import { isUnionOfPrimitivesDeeply } from "../unionUtils.js";
16
+ import {
17
+ isUnionOfPrimitivesDeeply,
18
+ getFlattenedUnionOptions,
19
+ getDiscriminatorValuesForOption,
20
+ resolveDiscriminantValue,
21
+ } from "../unionUtils.js";
6
22
  import {
7
23
  ZodCatch,
8
24
  ZodDefault,
@@ -76,17 +92,28 @@ export function schemaFieldToCoFieldDef(schema: SchemaField): CoFieldDef {
76
92
  }
77
93
 
78
94
  if (isCoValueClass(schema)) {
79
- return cacheSchemaField(schema, coField.ref(schema));
95
+ return cacheSchemaField(
96
+ schema,
97
+ coField.ref(schema, {
98
+ permissions: getDefaultRefPermissions(),
99
+ }),
100
+ );
80
101
  } else if (isCoValueSchema(schema)) {
81
102
  if (schema.builtin === "CoOptional") {
82
103
  return cacheSchemaField(
83
104
  schema,
84
105
  coField.ref(schema.getCoValueClass(), {
85
106
  optional: true,
107
+ permissions: schemaFieldPermissions(schema),
86
108
  }),
87
109
  );
88
110
  }
89
- return cacheSchemaField(schema, coField.ref(schema.getCoValueClass()));
111
+ return cacheSchemaField(
112
+ schema,
113
+ coField.ref(schema.getCoValueClass(), {
114
+ permissions: schemaFieldPermissions(schema),
115
+ }),
116
+ );
90
117
  } else {
91
118
  if ("_zod" in schema) {
92
119
  const zodSchemaDef = schema._zod.def;
@@ -228,3 +255,77 @@ export function schemaFieldToCoFieldDef(schema: SchemaField): CoFieldDef {
228
255
  }
229
256
  }
230
257
  }
258
+
259
+ function schemaFieldPermissions(schema: CoreCoValueSchema): RefPermissions {
260
+ if (schema.builtin === "CoOptional") {
261
+ return schemaFieldPermissions((schema as any).innerType);
262
+ }
263
+ if (schema.builtin === "CoDiscriminatedUnion") {
264
+ return discriminatedUnionFieldPermissions(
265
+ schema as CoreCoDiscriminatedUnionSchema<DiscriminableCoValueSchemas>,
266
+ );
267
+ }
268
+ return "permissions" in schema
269
+ ? schemaToRefPermissions(schema.permissions as SchemaPermissions)
270
+ : getDefaultRefPermissions();
271
+ }
272
+
273
+ function discriminatedUnionFieldPermissions(
274
+ schema: CoreCoDiscriminatedUnionSchema<DiscriminableCoValueSchemas>,
275
+ ): RefPermissions {
276
+ const discriminatorKey = schema.getDefinition().discriminator;
277
+ const allOptions = getFlattenedUnionOptions(schema);
278
+
279
+ const valueToStrategy = new Map<unknown, RefPermissions>();
280
+ for (const option of allOptions) {
281
+ const optionPermissions = schemaFieldPermissions(option);
282
+ const discriminatorValues = getDiscriminatorValuesForOption(
283
+ option,
284
+ discriminatorKey,
285
+ );
286
+
287
+ if (!discriminatorValues) {
288
+ continue;
289
+ }
290
+
291
+ for (const value of discriminatorValues) {
292
+ if (!valueToStrategy.has(value)) {
293
+ valueToStrategy.set(value, optionPermissions);
294
+ }
295
+ }
296
+ }
297
+
298
+ const fallbackStrategy = getDefaultRefPermissions();
299
+
300
+ const newInlineOwnerStrategy: NewInlineOwnerStrategy = (
301
+ createNewGroup,
302
+ containerOwner,
303
+ init,
304
+ ) => {
305
+ const discriminantValue = resolveDiscriminantValue(init, discriminatorKey);
306
+ const strategy =
307
+ discriminantValue !== undefined
308
+ ? valueToStrategy.get(discriminantValue)
309
+ : undefined;
310
+
311
+ const effectiveStrategy = strategy ?? fallbackStrategy;
312
+ return effectiveStrategy.newInlineOwnerStrategy(
313
+ createNewGroup,
314
+ containerOwner,
315
+ init,
316
+ );
317
+ };
318
+
319
+ const onCreate: RefOnCreateCallback = (newGroup, init) => {
320
+ const discriminantValue = resolveDiscriminantValue(init, discriminatorKey);
321
+ const strategy =
322
+ discriminantValue !== undefined
323
+ ? valueToStrategy.get(discriminantValue)
324
+ : undefined;
325
+
326
+ const effectiveStrategy = strategy ?? fallbackStrategy;
327
+ effectiveStrategy.onCreate?.(newGroup, init);
328
+ };
329
+
330
+ return { newInlineOwnerStrategy, onCreate };
331
+ }