jazz-tools 0.19.0 → 0.19.2

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 (84) hide show
  1. package/.turbo/turbo-build.log +53 -53
  2. package/CHANGELOG.md +21 -0
  3. package/dist/{chunk-P3YLNFN4.js → chunk-NCNM6UDZ.js} +61 -22
  4. package/dist/chunk-NCNM6UDZ.js.map +1 -0
  5. package/dist/index.js +1 -1
  6. package/dist/inspector/{custom-element-QESCMFY7.js → custom-element-ABVPHX53.js} +1118 -465
  7. package/dist/inspector/custom-element-ABVPHX53.js.map +1 -0
  8. package/dist/inspector/index.js +1090 -437
  9. package/dist/inspector/index.js.map +1 -1
  10. package/dist/inspector/register-custom-element.js +1 -1
  11. package/dist/inspector/tests/utils/history.test.d.ts +2 -0
  12. package/dist/inspector/tests/utils/history.test.d.ts.map +1 -0
  13. package/dist/inspector/tests/viewer/co-value-editor.test.d.ts +2 -0
  14. package/dist/inspector/tests/viewer/co-value-editor.test.d.ts.map +1 -0
  15. package/dist/inspector/tests/viewer/comap-view.test.d.ts +2 -0
  16. package/dist/inspector/tests/viewer/comap-view.test.d.ts.map +1 -0
  17. package/dist/inspector/ui/icon.d.ts +6 -0
  18. package/dist/inspector/ui/icon.d.ts.map +1 -1
  19. package/dist/inspector/ui/icons/add-icon.d.ts +2 -0
  20. package/dist/inspector/ui/icons/add-icon.d.ts.map +1 -0
  21. package/dist/inspector/ui/icons/edit-icon.d.ts +2 -0
  22. package/dist/inspector/ui/icons/edit-icon.d.ts.map +1 -0
  23. package/dist/inspector/ui/icons/history.d.ts +2 -0
  24. package/dist/inspector/ui/icons/history.d.ts.map +1 -0
  25. package/dist/inspector/utils/history.d.ts +3 -0
  26. package/dist/inspector/utils/history.d.ts.map +1 -0
  27. package/dist/inspector/utils/transactions-changes.d.ts +38 -0
  28. package/dist/inspector/utils/transactions-changes.d.ts.map +1 -0
  29. package/dist/inspector/viewer/co-map-view.d.ts +9 -0
  30. package/dist/inspector/viewer/co-map-view.d.ts.map +1 -0
  31. package/dist/inspector/viewer/co-value-editor.d.ts +10 -0
  32. package/dist/inspector/viewer/co-value-editor.d.ts.map +1 -0
  33. package/dist/inspector/viewer/grid-view.d.ts +3 -2
  34. package/dist/inspector/viewer/grid-view.d.ts.map +1 -1
  35. package/dist/inspector/viewer/history-view.d.ts.map +1 -1
  36. package/dist/inspector/viewer/page.d.ts.map +1 -1
  37. package/dist/testing.js +1 -1
  38. package/dist/tools/coValues/CoFieldInit.d.ts +2 -1
  39. package/dist/tools/coValues/CoFieldInit.d.ts.map +1 -1
  40. package/dist/tools/coValues/deepLoading.d.ts +8 -7
  41. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  42. package/dist/tools/coValues/interfaces.d.ts +3 -3
  43. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  44. package/dist/tools/coValues/schemaUnion.d.ts +6 -9
  45. package/dist/tools/coValues/schemaUnion.d.ts.map +1 -1
  46. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts +18 -7
  47. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts.map +1 -1
  48. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.d.ts +3 -2
  49. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.d.ts.map +1 -1
  50. package/dist/tools/implementation/zodSchema/unionUtils.d.ts.map +1 -1
  51. package/dist/tools/subscribe/SubscriptionScope.d.ts +1 -0
  52. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  53. package/package.json +4 -4
  54. package/src/inspector/tests/utils/history.test.ts +401 -0
  55. package/src/inspector/tests/viewer/co-value-editor.test.tsx +903 -0
  56. package/src/inspector/tests/viewer/comap-view.test.tsx +581 -0
  57. package/src/inspector/ui/icon.tsx +6 -0
  58. package/src/inspector/ui/icons/add-icon.tsx +21 -0
  59. package/src/inspector/ui/icons/edit-icon.tsx +17 -0
  60. package/src/inspector/ui/icons/history.tsx +28 -0
  61. package/src/inspector/ui/modal.tsx +3 -3
  62. package/src/inspector/utils/history.ts +49 -0
  63. package/src/inspector/utils/transactions-changes.ts +98 -0
  64. package/src/inspector/viewer/co-map-view.tsx +312 -0
  65. package/src/inspector/viewer/co-value-editor.tsx +164 -0
  66. package/src/inspector/viewer/grid-view.tsx +139 -10
  67. package/src/inspector/viewer/history-view.tsx +16 -118
  68. package/src/inspector/viewer/page.tsx +13 -0
  69. package/src/react-core/tests/usePassPhraseAuth.test.ts +1 -1
  70. package/src/tools/coValues/CoFieldInit.ts +6 -3
  71. package/src/tools/coValues/coList.ts +1 -1
  72. package/src/tools/coValues/deepLoading.ts +85 -71
  73. package/src/tools/coValues/interfaces.ts +3 -3
  74. package/src/tools/coValues/schemaUnion.ts +19 -14
  75. package/src/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.ts +69 -9
  76. package/src/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.ts +12 -7
  77. package/src/tools/implementation/zodSchema/unionUtils.ts +35 -4
  78. package/src/tools/subscribe/SubscriptionScope.ts +3 -14
  79. package/src/tools/tests/coDiscriminatedUnion.test.ts +347 -5
  80. package/src/tools/tests/coVector.test.ts +43 -0
  81. package/src/tools/tests/deepLoading.test.ts +55 -59
  82. package/src/tools/tests/schema.resolved.test.ts +70 -1
  83. package/dist/chunk-P3YLNFN4.js.map +0 -1
  84. package/dist/inspector/custom-element-QESCMFY7.js.map +0 -1
@@ -1,27 +1,93 @@
1
1
  import { CoID, LocalNode, RawCoValue } from "cojson";
2
2
  import { JsonObject, JsonValue } from "cojson";
3
+ import { useState } from "react";
4
+ import { styled } from "goober";
3
5
  import { ResolveIcon } from "./type-icon.js";
4
6
  import { PageInfo, isCoId } from "./types.js";
5
7
  import { CoMapPreview, ValueRenderer } from "./value-renderer.js";
8
+ import { CoValueEditor } from "./co-value-editor.js";
6
9
 
7
10
  import { Badge } from "../ui/badge.js";
8
11
  import { Card, CardBody, CardHeader } from "../ui/card.js";
9
12
  import { Grid } from "../ui/grid.js";
13
+ import { Icon } from "../ui/icon.js";
10
14
  import { Text } from "../ui/text.js";
11
15
 
12
16
  function GridItem({
13
17
  entry,
14
18
  onNavigate,
15
19
  node,
20
+ coValue,
16
21
  }: {
17
22
  entry: [string, JsonValue | undefined];
18
23
  onNavigate: (pages: PageInfo[]) => void;
19
24
  node: LocalNode;
25
+ coValue?: RawCoValue;
20
26
  }) {
21
27
  const [key, value] = entry;
22
28
  const isCoValue = isCoId(value);
29
+ const [isEditing, setIsEditing] = useState(false);
23
30
 
24
- const props = isCoValue
31
+ const handleEditClick = (e: React.MouseEvent) => {
32
+ e.stopPropagation();
33
+ setIsEditing(true);
34
+ };
35
+
36
+ const handleCancel = () => {
37
+ setIsEditing(false);
38
+ };
39
+
40
+ const handleDelete = (e: React.MouseEvent) => {
41
+ e.stopPropagation();
42
+ if (confirm(`Are you sure you want to delete the property "${key}"?`)) {
43
+ coValue?.core.makeTransaction(
44
+ [
45
+ {
46
+ op: "del",
47
+ key,
48
+ },
49
+ ],
50
+ "private",
51
+ );
52
+ }
53
+ };
54
+
55
+ if (isEditing) {
56
+ return (
57
+ <Card
58
+ style={{
59
+ backgroundColor: "var(--j-foreground)",
60
+ borderColor: "var(--j-foreground)",
61
+ }}
62
+ >
63
+ <CardHeader>
64
+ <div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
65
+ {isCoValue ? (
66
+ <>
67
+ <Text strong>{key}</Text>
68
+ <Badge>
69
+ <ResolveIcon coId={value as CoID<RawCoValue>} node={node} />
70
+ </Badge>
71
+ </>
72
+ ) : (
73
+ <Text strong>{key}</Text>
74
+ )}
75
+ </div>
76
+ </CardHeader>
77
+ <CardBody style={{ wordBreak: "break-word" }}>
78
+ <CoValueEditor
79
+ node={node}
80
+ property={key}
81
+ value={value}
82
+ coValue={coValue!}
83
+ onCancel={handleCancel}
84
+ />
85
+ </CardBody>
86
+ </Card>
87
+ );
88
+ }
89
+
90
+ const cardProps = isCoValue
25
91
  ? {
26
92
  onClick: () =>
27
93
  onNavigate([{ coId: value as CoID<RawCoValue>, name: key }]),
@@ -35,17 +101,37 @@ function GridItem({
35
101
  };
36
102
 
37
103
  return (
38
- <Card {...props}>
104
+ <Card {...cardProps}>
39
105
  <CardHeader>
40
- {isCoValue ? (
41
- <>
106
+ <div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
107
+ {isCoValue ? (
108
+ <>
109
+ <Text strong>{key}</Text>
110
+ <Badge>
111
+ <ResolveIcon coId={value as CoID<RawCoValue>} node={node} />
112
+ </Badge>
113
+ </>
114
+ ) : (
42
115
  <Text strong>{key}</Text>
43
- <Badge>
44
- <ResolveIcon coId={value as CoID<RawCoValue>} node={node} />
45
- </Badge>
46
- </>
47
- ) : (
48
- <Text strong>{key}</Text>
116
+ )}
117
+ </div>
118
+ {coValue && (
119
+ <ActionButtons>
120
+ <EditButton
121
+ onClick={handleEditClick}
122
+ type="button"
123
+ aria-label="Edit"
124
+ >
125
+ <Icon name="edit" size="sm" />
126
+ </EditButton>
127
+ <DeleteButton
128
+ onClick={handleDelete}
129
+ type="button"
130
+ aria-label="Delete"
131
+ >
132
+ <Icon name="delete" size="sm" />
133
+ </DeleteButton>
134
+ </ActionButtons>
49
135
  )}
50
136
  </CardHeader>
51
137
  <CardBody style={{ wordBreak: "break-word" }}>
@@ -68,10 +154,12 @@ export function GridView({
68
154
  data,
69
155
  onNavigate,
70
156
  node,
157
+ coValue,
71
158
  }: {
72
159
  data: JsonObject;
73
160
  onNavigate: (pages: PageInfo[]) => void;
74
161
  node: LocalNode;
162
+ coValue?: RawCoValue;
75
163
  }) {
76
164
  const entries = Object.entries(data);
77
165
 
@@ -82,9 +170,50 @@ export function GridView({
82
170
  entry={entry}
83
171
  onNavigate={onNavigate}
84
172
  node={node}
173
+ coValue={coValue}
85
174
  key={childIndex}
86
175
  />
87
176
  ))}
88
177
  </Grid>
89
178
  );
90
179
  }
180
+
181
+ const EditButton = styled("button")`
182
+ display: inline-flex;
183
+ align-items: center;
184
+ justify-content: center;
185
+ padding: 0.25rem;
186
+ border: none;
187
+ background: transparent;
188
+ cursor: pointer;
189
+ color: var(--j-text-color);
190
+ border-radius: var(--j-radius-sm);
191
+ transition: background-color 0.2s;
192
+
193
+ &:hover {
194
+ background-color: var(--j-foreground);
195
+ }
196
+ `;
197
+
198
+ const DeleteButton = styled("button")`
199
+ display: inline-flex;
200
+ align-items: center;
201
+ justify-content: center;
202
+ padding: 0.25rem;
203
+ border: none;
204
+ background: transparent;
205
+ cursor: pointer;
206
+ color: var(--j-text-color);
207
+ border-radius: var(--j-radius-sm);
208
+ transition: background-color 0.2s;
209
+
210
+ &:hover {
211
+ background-color: var(--j-foreground);
212
+ }
213
+ `;
214
+
215
+ const ActionButtons = styled("div")`
216
+ display: flex;
217
+ align-items: center;
218
+ gap: 0.25rem;
219
+ `;
@@ -1,29 +1,11 @@
1
- import {
2
- AccountRole,
3
- BinaryStreamStart,
4
- CoID,
5
- JsonValue,
6
- LocalNode,
7
- OpID,
8
- RawCoValue,
9
- Role,
10
- } from "cojson";
1
+ import { CoID, JsonValue, LocalNode, OpID, RawCoValue } from "cojson";
11
2
  import { useMemo } from "react";
12
3
  import { styled } from "goober";
13
- import { isCoId } from "./types";
14
4
  import { AccountOrGroupText } from "./account-or-group-text";
15
5
  import { DataTable, ColumnDef } from "../ui/data-table";
16
- import { MapOpPayload } from "cojson/dist/coValues/coMap.js";
17
- import {
18
- DeletionOpPayload,
19
- InsertionOpPayload,
20
- } from "cojson/dist/coValues/coList.js";
21
- import {
22
- BinaryStreamChunk,
23
- BinaryStreamEnd,
24
- } from "cojson/dist/coValues/coStream.js";
25
- import { VerifiedTransaction } from "cojson/dist/coValueCore/coValueCore.js";
6
+ import type { VerifiedTransaction } from "cojson/dist/coValueCore/coValueCore.js";
26
7
  import { Icon, Accordion } from "../ui";
8
+ import * as TransactionChanges from "../utils/transactions-changes";
27
9
 
28
10
  type HistoryEntry = {
29
11
  id: string;
@@ -168,7 +150,7 @@ function mapTransactionToAction(
168
150
  coValue: RawCoValue,
169
151
  ): string {
170
152
  // Group changes
171
- if (isUserPromotion(change)) {
153
+ if (TransactionChanges.isUserPromotion(change)) {
172
154
  if (change.value === "revoked") {
173
155
  return `${change.key} has been revoked`;
174
156
  }
@@ -176,28 +158,28 @@ function mapTransactionToAction(
176
158
  return `${change.key} has been promoted to ${change.value}`;
177
159
  }
178
160
 
179
- if (isGroupExtension(change)) {
161
+ if (TransactionChanges.isGroupExtension(change)) {
180
162
  const child = change.key.slice(6);
181
163
  return `Group became a member of ${child}`;
182
164
  }
183
165
 
184
- if (isGroupExtendRevocation(change)) {
166
+ if (TransactionChanges.isGroupExtendRevocation(change)) {
185
167
  const child = change.key.slice(6);
186
168
  return `Group's membership of ${child} has been revoked.`;
187
169
  }
188
170
 
189
- if (isGroupPromotion(change)) {
171
+ if (TransactionChanges.isGroupPromotion(change)) {
190
172
  const parent = change.key.slice(7);
191
173
  return `Group ${parent} has been promoted to ${change.value}`;
192
174
  }
193
175
 
194
- if (isKeyRevelation(change)) {
176
+ if (TransactionChanges.isKeyRevelation(change)) {
195
177
  const [key, target] = change.key.split("_for_");
196
178
  return `Key "${key}" has been revealed to "${target}"`;
197
179
  }
198
180
 
199
181
  // coList changes
200
- if (isItemAppend(change)) {
182
+ if (TransactionChanges.isItemAppend(change)) {
201
183
  if (change.after === "start") {
202
184
  return `"${change.value}" has been appended`;
203
185
  }
@@ -211,7 +193,7 @@ function mapTransactionToAction(
211
193
  return `"${change.value}" has been inserted after "${(after as any).value}"`;
212
194
  }
213
195
 
214
- if (isItemPrepend(change)) {
196
+ if (TransactionChanges.isItemPrepend(change)) {
215
197
  if (change.before === "end") {
216
198
  return `"${change.value}" has been prepended`;
217
199
  }
@@ -225,7 +207,7 @@ function mapTransactionToAction(
225
207
  return `"${change.value}" has been inserted before "${(before as any).value}"`;
226
208
  }
227
209
 
228
- if (isItemDeletion(change)) {
210
+ if (TransactionChanges.isItemDeletion(change)) {
229
211
  const insertion = findListChange(change.insertion, coValue);
230
212
  if (insertion === undefined) {
231
213
  return `An undefined item has been deleted`;
@@ -235,24 +217,24 @@ function mapTransactionToAction(
235
217
  }
236
218
 
237
219
  // coStream changes
238
- if (isStreamStart(change)) {
220
+ if (TransactionChanges.isStreamStart(change)) {
239
221
  return `Stream started with mime type "${change.mimeType}" and file name "${change.fileName}"`;
240
222
  }
241
223
 
242
- if (isStreamChunk(change)) {
224
+ if (TransactionChanges.isStreamChunk(change)) {
243
225
  return `Stream chunk added`;
244
226
  }
245
227
 
246
- if (isStreamEnd(change)) {
228
+ if (TransactionChanges.isStreamEnd(change)) {
247
229
  return `Stream ended`;
248
230
  }
249
231
 
250
232
  // coMap changes
251
- if (isPropertySet(change)) {
233
+ if (TransactionChanges.isPropertySet(change)) {
252
234
  return `Property "${change.key}" has been set to ${JSON.stringify(change.value)}`;
253
235
  }
254
236
 
255
- if (isPropertyDeletion(change)) {
237
+ if (TransactionChanges.isPropertyDeletion(change)) {
256
238
  return `Property "${change.key}" has been deleted`;
257
239
  }
258
240
 
@@ -269,90 +251,6 @@ const findListChange = (
269
251
  )?.changes?.[opId.changeIdx];
270
252
  };
271
253
 
272
- const isGroupExtension = (
273
- change: any,
274
- ): change is Extract<
275
- MapOpPayload<`child_${string}`, "extend">,
276
- { op: "set" }
277
- > => {
278
- return change?.op === "set" && change?.value === "extend";
279
- };
280
-
281
- const isGroupExtendRevocation = (
282
- change: any,
283
- ): change is Extract<
284
- MapOpPayload<`child_${string}`, "revoked">,
285
- { op: "set" }
286
- > => {
287
- return change?.op === "set" && change?.value === "revoked";
288
- };
289
-
290
- const isGroupPromotion = (
291
- change: any,
292
- ): change is Extract<
293
- MapOpPayload<`parent_co_${string}`, AccountRole>,
294
- { op: "set" }
295
- > => {
296
- return change?.op === "set" && change?.key.startsWith("parent_co_");
297
- };
298
-
299
- const isUserPromotion = (
300
- change: any,
301
- ): change is Extract<MapOpPayload<CoID<RawCoValue>, Role>, { op: "set" }> => {
302
- return (
303
- change?.op === "set" && (isCoId(change?.key) || change?.key === "everyone")
304
- );
305
- };
306
-
307
- const isKeyRevelation = (
308
- change: any,
309
- ): change is Extract<
310
- MapOpPayload<`${string}_for_${string}`, string>,
311
- { op: "set" }
312
- > => {
313
- return change?.op === "set" && change?.key.includes("_for_");
314
- };
315
-
316
- const isPropertySet = (
317
- change: any,
318
- ): change is Extract<MapOpPayload<string, any>, { op: "set" }> => {
319
- return change?.op === "set" && "key" in change && "value" in change;
320
- };
321
- const isPropertyDeletion = (
322
- change: any,
323
- ): change is Extract<MapOpPayload<string, any>, { op: "del" }> => {
324
- return change?.op === "del" && "key" in change;
325
- };
326
-
327
- const isItemAppend = (
328
- change: any,
329
- ): change is Extract<InsertionOpPayload<any>, { op: "app" }> => {
330
- return change?.op === "app" && "after" in change && "value" in change;
331
- };
332
- const isItemPrepend = (
333
- change: any,
334
- ): change is Extract<InsertionOpPayload<any>, { op: "pre" }> => {
335
- return change?.op === "pre" && "before" in change && "value" in change;
336
- };
337
-
338
- const isItemDeletion = (
339
- change: any,
340
- ): change is Extract<DeletionOpPayload, { op: "del" }> => {
341
- return change?.op === "del" && "insertion" in change;
342
- };
343
-
344
- const isStreamStart = (change: any): change is BinaryStreamStart => {
345
- return change?.type === "start" && "mimeType" in change;
346
- };
347
-
348
- const isStreamChunk = (change: any): change is BinaryStreamChunk => {
349
- return change?.type === "chunk" && "chunk" in change;
350
- };
351
-
352
- const isStreamEnd = (change: any): change is BinaryStreamEnd => {
353
- return change?.type === "end";
354
- };
355
-
356
254
  const RedTooltip = styled("span")`
357
255
  position:relative; /* making the .tooltip span a container for the tooltip text */
358
256
  border-bottom:1px dashed #000; /* little indicater to indicate it's hoverable */
@@ -2,6 +2,7 @@ import {
2
2
  CoID,
3
3
  LocalNode,
4
4
  RawCoList,
5
+ RawCoMap,
5
6
  RawCoStream,
6
7
  RawCoValue,
7
8
  RawGroup,
@@ -23,6 +24,7 @@ import { TypeIcon } from "./type-icon.js";
23
24
  import { PageInfo } from "./types.js";
24
25
  import { resolveCoValue, useResolvedCoValue } from "./use-resolve-covalue.js";
25
26
  import { HistoryView } from "./history-view.js";
27
+ import { CoMapView } from "./co-map-view.js";
26
28
 
27
29
  interface PageContainerProps extends React.HTMLAttributes<HTMLDivElement> {
28
30
  isTopLevel?: boolean;
@@ -165,6 +167,17 @@ function View(
165
167
  return <TableView data={snapshot} node={node} onNavigate={onNavigate} />;
166
168
  }
167
169
 
170
+ if (type === "comap") {
171
+ return (
172
+ <CoMapView
173
+ coValue={value as RawCoMap}
174
+ data={snapshot}
175
+ node={node}
176
+ onNavigate={onNavigate}
177
+ />
178
+ );
179
+ }
180
+
168
181
  return <GridView data={snapshot} onNavigate={onNavigate} node={node} />;
169
182
  }
170
183
 
@@ -119,7 +119,7 @@ describe("usePassphraseAuth", () => {
119
119
  const me = useAccount();
120
120
  const logOut = useLogOut();
121
121
 
122
- if (me) {
122
+ if (me.$isLoaded) {
123
123
  if (!accounts.includes(me.$jazz.id)) {
124
124
  accounts.push(me.$jazz.id);
125
125
  }
@@ -3,6 +3,7 @@ import { CoList } from "./coList.js";
3
3
  import { CoMap, CoMapInit } from "./coMap.js";
4
4
  import { CoPlainText } from "./coPlainText.js";
5
5
  import { CoRichText } from "./coRichText.js";
6
+ import { CoVector } from "./coVector.js";
6
7
 
7
8
  /**
8
9
  * Returns the type of values that can be used to initialize a field of the provided type.
@@ -15,6 +16,8 @@ export type CoFieldInit<V> = V extends CoMap
15
16
  ? V | CoMapInit<V>
16
17
  : V extends CoList<infer T> | CoFeed<infer T>
17
18
  ? V | ReadonlyArray<CoFieldInit<T>>
18
- : V extends CoPlainText | CoRichText
19
- ? V | string
20
- : V;
19
+ : V extends CoVector | Readonly<CoVector>
20
+ ? V | ReadonlyArray<number> | Float32Array
21
+ : V extends CoPlainText | CoRichText
22
+ ? V | string
23
+ : V;
@@ -397,7 +397,7 @@ export class CoList<out Item = any>
397
397
  });
398
398
  },
399
399
  onUpdateWhenFound(value) {
400
- value.$jazz.applyDiff(options.value);
400
+ (value as Resolved<L>).$jazz.applyDiff(options.value);
401
401
  },
402
402
  });
403
403
  }
@@ -6,16 +6,23 @@ import { type CoKeys } from "./coMap.js";
6
6
  import { type CoValue, type ID } from "./interfaces.js";
7
7
 
8
8
  /**
9
- * Used to check if T is a union type.
9
+ * Returns a boolean for whether the given type is a union.
10
10
  *
11
- * If T is a union type, the left hand side of the extends becomes a union of function types.
12
- * The right hand side is always a single function type.
11
+ * Taken from https://github.com/sindresorhus/type-fest/blob/main/source/is-union.d.ts
13
12
  */
14
- type IsUnion<T, U = T> = (T extends any ? (x: T) => void : never) extends (
15
- x: U,
16
- ) => void
17
- ? false
18
- : true;
13
+ type IsUnion<T, U = T> = (
14
+ [T] extends [never]
15
+ ? false
16
+ : T extends any
17
+ ? [U] extends [T]
18
+ ? false
19
+ : true
20
+ : never
21
+ ) extends infer Result
22
+ ? boolean extends Result
23
+ ? true
24
+ : Result
25
+ : never;
19
26
 
20
27
  /**
21
28
  * A CoValue that may or may not be loaded.
@@ -67,61 +74,57 @@ export type RefsToResolve<
67
74
  | (DepthLimit extends CurrentDepth["length"]
68
75
  ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
76
  any
70
- : IsUnion<LoadedAndRequired<V>> extends true
71
- ? true
72
- : // Basically V extends CoList - but if we used that we'd introduce circularity into the definition of CoList itself
73
- V extends ReadonlyArray<infer Item>
74
- ? LoadedAndRequired<Item> extends CoValue
77
+ : // Basically V extends CoList - but if we used that we'd introduce circularity into the definition of CoList itself
78
+ V extends ReadonlyArray<infer Item>
79
+ ? LoadedAndRequired<Item> extends CoValue
80
+ ?
81
+ | ({
82
+ $each?: RefsToResolve<
83
+ AsLoaded<Item>,
84
+ DepthLimit,
85
+ [0, ...CurrentDepth]
86
+ >;
87
+ } & OnError)
88
+ | boolean
89
+ : OnError | boolean
90
+ : // Basically V extends CoMap | Group | Account - but if we used that we'd introduce circularity into the definition of CoMap itself
91
+ V extends { [TypeSym]: "CoMap" | "Group" | "Account" }
92
+ ?
93
+ | ({
94
+ [Key in CoKeys<V> as LoadedAndRequired<V[Key]> extends CoValue
95
+ ? Key
96
+ : never]?: RefsToResolve<
97
+ LoadedAndRequired<V[Key]>,
98
+ DepthLimit,
99
+ [0, ...CurrentDepth]
100
+ >;
101
+ } & OnError)
102
+ | (ItemsSym extends keyof V
103
+ ? {
104
+ $each: RefsToResolve<
105
+ LoadedAndRequired<V[ItemsSym]>,
106
+ DepthLimit,
107
+ [0, ...CurrentDepth]
108
+ >;
109
+ } & OnError
110
+ : never)
111
+ | boolean
112
+ : V extends {
113
+ [TypeSym]: "CoStream";
114
+ byMe: CoFeedEntry<infer Item> | undefined;
115
+ }
75
116
  ?
76
117
  | ({
77
- $each?: RefsToResolve<
118
+ $each: RefsToResolve<
78
119
  AsLoaded<Item>,
79
120
  DepthLimit,
80
121
  [0, ...CurrentDepth]
81
122
  >;
82
123
  } & OnError)
83
124
  | boolean
84
- : OnError | boolean
85
- : // Basically V extends CoMap | Group | Account - but if we used that we'd introduce circularity into the definition of CoMap itself
86
- V extends { [TypeSym]: "CoMap" | "Group" | "Account" }
87
- ?
88
- | ({
89
- [Key in CoKeys<V> as LoadedAndRequired<
90
- V[Key]
91
- > extends CoValue
92
- ? Key
93
- : never]?: RefsToResolve<
94
- LoadedAndRequired<V[Key]>,
95
- DepthLimit,
96
- [0, ...CurrentDepth]
97
- >;
98
- } & OnError)
99
- | (ItemsSym extends keyof V
100
- ? {
101
- $each: RefsToResolve<
102
- LoadedAndRequired<V[ItemsSym]>,
103
- DepthLimit,
104
- [0, ...CurrentDepth]
105
- >;
106
- } & OnError
107
- : never)
108
- | boolean
109
- : V extends {
110
- [TypeSym]: "CoStream";
111
- byMe: CoFeedEntry<infer Item> | undefined;
112
- }
113
- ?
114
- | ({
115
- $each: RefsToResolve<
116
- AsLoaded<Item>,
117
- DepthLimit,
118
- [0, ...CurrentDepth]
119
- >;
120
- } & OnError)
121
- | boolean
122
- : V extends { [TypeSym]: "CoPlainText" | "BinaryCoStream" }
123
- ? boolean | OnError
124
- : boolean);
125
+ : V extends { [TypeSym]: "CoPlainText" | "BinaryCoStream" }
126
+ ? boolean | OnError
127
+ : boolean);
125
128
 
126
129
  export type RefsToResolveStrict<T, V> = [V] extends [RefsToResolve<T>]
127
130
  ? RefsToResolve<T>
@@ -130,7 +133,7 @@ export type RefsToResolveStrict<T, V> = [V] extends [RefsToResolve<T>]
130
133
  export type Resolved<
131
134
  T,
132
135
  R extends RefsToResolve<T> | undefined = true,
133
- > = DeeplyLoaded<T, R, 10, []>;
136
+ > = DeeplyLoaded<T, R>;
134
137
 
135
138
  /**
136
139
  * If the resolve query contains `$onError: "catch"`, we return a not loaded value for this nested CoValue.
@@ -145,21 +148,32 @@ type CoMapLikeLoaded<
145
148
  Depth,
146
149
  DepthLimit extends number,
147
150
  CurrentDepth extends number[],
148
- > = {
149
- readonly [Key in keyof Omit<Depth, "$onError">]-?: Key extends CoKeys<V>
150
- ? LoadedAndRequired<V[Key]> extends CoValue
151
- ?
152
- | DeeplyLoaded<
153
- LoadedAndRequired<V[Key]>,
154
- Depth[Key],
155
- DepthLimit,
156
- [0, ...CurrentDepth]
157
- >
158
- | (undefined extends V[Key] ? undefined : never)
159
- | OnErrorResolvedValue<V[Key], Depth[Key]>
160
- : never
161
- : never;
162
- } & V;
151
+ > = IsUnion<LoadedAndRequired<V>> extends true
152
+ ? // Trigger conditional type distributivity to deeply resolve each member of the union separately
153
+ // Otherwise, deeply loaded values will resolve to `never`
154
+ V extends V
155
+ ? CoMapLikeLoaded<
156
+ V,
157
+ Pick<Depth, keyof V & keyof Depth>,
158
+ DepthLimit,
159
+ CurrentDepth
160
+ >
161
+ : never
162
+ : {
163
+ readonly [Key in keyof Omit<Depth, "$onError">]-?: Key extends CoKeys<V>
164
+ ? LoadedAndRequired<V[Key]> extends CoValue
165
+ ?
166
+ | DeeplyLoaded<
167
+ LoadedAndRequired<V[Key]>,
168
+ Depth[Key],
169
+ DepthLimit,
170
+ [0, ...CurrentDepth]
171
+ >
172
+ | (undefined extends V[Key] ? undefined : never)
173
+ | OnErrorResolvedValue<V[Key], Depth[Key]>
174
+ : never
175
+ : never;
176
+ } & V;
163
177
 
164
178
  export type DeeplyLoaded<
165
179
  V,