jazz-tools 0.18.27 → 0.18.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +57 -57
- package/CHANGELOG.md +13 -0
- package/dist/{chunk-ZIAN4UY5.js → chunk-YOL3XDDW.js} +158 -120
- package/dist/chunk-YOL3XDDW.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/react-core/hooks.d.ts +4 -0
- package/dist/react-core/hooks.d.ts.map +1 -1
- package/dist/react-core/index.js +5 -0
- package/dist/react-core/index.js.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/tools/coValues/coList.d.ts +11 -3
- package/dist/tools/coValues/coList.d.ts.map +1 -1
- package/dist/tools/coValues/coMap.d.ts +21 -5
- package/dist/tools/coValues/coMap.d.ts.map +1 -1
- package/dist/tools/coValues/group.d.ts +2 -2
- package/dist/tools/coValues/group.d.ts.map +1 -1
- package/dist/tools/coValues/inbox.d.ts.map +1 -1
- package/dist/tools/coValues/interfaces.d.ts +9 -0
- package/dist/tools/coValues/interfaces.d.ts.map +1 -1
- package/dist/tools/exports.d.ts +1 -1
- package/dist/tools/exports.d.ts.map +1 -1
- package/dist/tools/tests/coList.unique.test.d.ts +2 -0
- package/dist/tools/tests/coList.unique.test.d.ts.map +1 -0
- package/dist/tools/tests/coMap.unique.test.d.ts +2 -0
- package/dist/tools/tests/coMap.unique.test.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/react-core/hooks.ts +8 -0
- package/src/react-core/tests/useAccount.test.ts +61 -1
- package/src/react-core/tests/usePassPhraseAuth.test.ts +74 -2
- package/src/tools/coValues/coList.ts +38 -35
- package/src/tools/coValues/coMap.ts +38 -38
- package/src/tools/coValues/group.ts +5 -1
- package/src/tools/coValues/inbox.ts +4 -3
- package/src/tools/coValues/interfaces.ts +88 -0
- package/src/tools/exports.ts +1 -0
- package/src/tools/tests/coList.test.ts +0 -190
- package/src/tools/tests/coList.unique.test.ts +244 -0
- package/src/tools/tests/coMap.test.ts +0 -433
- package/src/tools/tests/coMap.unique.test.ts +474 -0
- package/dist/chunk-ZIAN4UY5.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coList.unique.test.d.ts","sourceRoot":"","sources":["../../../src/tools/tests/coList.unique.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coMap.unique.test.d.ts","sourceRoot":"","sources":["../../../src/tools/tests/coMap.unique.test.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
},
|
|
188
188
|
"type": "module",
|
|
189
189
|
"license": "MIT",
|
|
190
|
-
"version": "0.18.
|
|
190
|
+
"version": "0.18.28",
|
|
191
191
|
"dependencies": {
|
|
192
192
|
"@manuscripts/prosemirror-recreate-steps": "^0.1.4",
|
|
193
193
|
"@scure/base": "1.2.1",
|
|
@@ -204,9 +204,9 @@
|
|
|
204
204
|
"prosemirror-transform": "^1.9.0",
|
|
205
205
|
"use-sync-external-store": "^1.5.0",
|
|
206
206
|
"zod": "4.1.11",
|
|
207
|
-
"cojson": "0.18.
|
|
208
|
-
"cojson-storage-indexeddb": "0.18.
|
|
209
|
-
"cojson-transport-ws": "0.18.
|
|
207
|
+
"cojson": "0.18.28",
|
|
208
|
+
"cojson-storage-indexeddb": "0.18.28",
|
|
209
|
+
"cojson-transport-ws": "0.18.28"
|
|
210
210
|
},
|
|
211
211
|
"devDependencies": {
|
|
212
212
|
"@scure/bip39": "^1.3.0",
|
package/src/react-core/hooks.ts
CHANGED
|
@@ -792,6 +792,14 @@ export function useAccountWithSelector<
|
|
|
792
792
|
);
|
|
793
793
|
}
|
|
794
794
|
|
|
795
|
+
/**
|
|
796
|
+
* Returns a function for logging out of the current account.
|
|
797
|
+
*/
|
|
798
|
+
export function useLogOut(): () => void {
|
|
799
|
+
const contextManager = useJazzContextManager();
|
|
800
|
+
return contextManager.logOut;
|
|
801
|
+
}
|
|
802
|
+
|
|
795
803
|
export function experimental_useInboxSender<
|
|
796
804
|
I extends CoValue,
|
|
797
805
|
O extends CoValue | undefined,
|
|
@@ -64,7 +64,67 @@ describe("useAccount", () => {
|
|
|
64
64
|
expect(result.current?.me?.root?.value).toBe("123");
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
it("should be in sync with useIsAuthenticated when logOut is called", async () => {
|
|
67
|
+
it("should be in sync with useIsAuthenticated when logOut (from useAccount.logOut) is called", async () => {
|
|
68
|
+
const account = await createJazzTestAccount({});
|
|
69
|
+
|
|
70
|
+
const accounts: string[] = [];
|
|
71
|
+
const updates: { isAuthenticated: boolean; accountIndex: number }[] = [];
|
|
72
|
+
|
|
73
|
+
const { result } = renderHook(
|
|
74
|
+
() => {
|
|
75
|
+
const isAuthenticated = useIsAuthenticated();
|
|
76
|
+
const account = useAccount();
|
|
77
|
+
|
|
78
|
+
if (account.me) {
|
|
79
|
+
if (!accounts.includes(account.me.$jazz.id)) {
|
|
80
|
+
accounts.push(account.me.$jazz.id);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
updates.push({
|
|
84
|
+
isAuthenticated,
|
|
85
|
+
accountIndex: accounts.indexOf(account.me.$jazz.id),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { isAuthenticated, account };
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
account,
|
|
93
|
+
isAuthenticated: true,
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
expect(result.current?.isAuthenticated).toBe(true);
|
|
98
|
+
expect(result.current?.account?.me).toBeDefined();
|
|
99
|
+
|
|
100
|
+
const id = result.current?.account?.me?.$jazz.id;
|
|
101
|
+
|
|
102
|
+
await act(async () => {
|
|
103
|
+
await result.current?.account?.logOut();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(result.current?.isAuthenticated).toBe(false);
|
|
107
|
+
expect(result.current?.account?.me?.$jazz.id).not.toBe(id);
|
|
108
|
+
|
|
109
|
+
expect(updates).toMatchInlineSnapshot(`
|
|
110
|
+
[
|
|
111
|
+
{
|
|
112
|
+
"accountIndex": 0,
|
|
113
|
+
"isAuthenticated": true,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"accountIndex": 0,
|
|
117
|
+
"isAuthenticated": false,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"accountIndex": 1,
|
|
121
|
+
"isAuthenticated": false,
|
|
122
|
+
},
|
|
123
|
+
]
|
|
124
|
+
`);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should be in sync with useIsAuthenticated when logOut (from useLogOut) is called", async () => {
|
|
68
128
|
const account = await createJazzTestAccount({});
|
|
69
129
|
|
|
70
130
|
const accounts: string[] = [];
|
|
@@ -4,7 +4,7 @@ import { mnemonicToEntropy } from "@scure/bip39";
|
|
|
4
4
|
import { AuthSecretStorage, KvStoreContext } from "jazz-tools";
|
|
5
5
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
6
6
|
import { usePassphraseAuth } from "../auth/PassphraseAuth";
|
|
7
|
-
import { useAccount } from "../hooks";
|
|
7
|
+
import { useAccount, useLogOut } from "../hooks";
|
|
8
8
|
import {
|
|
9
9
|
createJazzTestAccount,
|
|
10
10
|
createJazzTestGuest,
|
|
@@ -107,7 +107,7 @@ describe("usePassphraseAuth", () => {
|
|
|
107
107
|
expect(await result.current.signUp()).toBe(passphrase);
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
-
it("should be able to logout after sign up", async () => {
|
|
110
|
+
it("should be able to logout after sign up using useAccount.logOut", async () => {
|
|
111
111
|
const account = await createJazzTestAccount({});
|
|
112
112
|
|
|
113
113
|
const accounts: string[] = [];
|
|
@@ -177,4 +177,76 @@ describe("usePassphraseAuth", () => {
|
|
|
177
177
|
]
|
|
178
178
|
`);
|
|
179
179
|
});
|
|
180
|
+
|
|
181
|
+
it("should be able to logout after sign up using useLogout", async () => {
|
|
182
|
+
const account = await createJazzTestAccount({});
|
|
183
|
+
|
|
184
|
+
const accounts: string[] = [];
|
|
185
|
+
const updates: { state: string; accountIndex: number }[] = [];
|
|
186
|
+
|
|
187
|
+
const { result } = renderHook(
|
|
188
|
+
() => {
|
|
189
|
+
const passphraseAuth = usePassphraseAuth({ wordlist: testWordlist });
|
|
190
|
+
const account = useAccount();
|
|
191
|
+
const logOut = useLogOut();
|
|
192
|
+
|
|
193
|
+
if (account.me) {
|
|
194
|
+
if (!accounts.includes(account.me.$jazz.id)) {
|
|
195
|
+
accounts.push(account.me.$jazz.id);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
updates.push({
|
|
199
|
+
state: passphraseAuth.state,
|
|
200
|
+
accountIndex: accounts.indexOf(account.me.$jazz.id),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return { passphraseAuth, account, logOut };
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
account,
|
|
208
|
+
isAuthenticated: false,
|
|
209
|
+
},
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
expect(result.current?.passphraseAuth.state).toBe("anonymous");
|
|
213
|
+
expect(result.current?.account?.me).toBeDefined();
|
|
214
|
+
|
|
215
|
+
const id = result.current?.account?.me?.$jazz.id;
|
|
216
|
+
|
|
217
|
+
await act(async () => {
|
|
218
|
+
await result.current?.passphraseAuth.signUp();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
expect(result.current?.passphraseAuth.state).toBe("signedIn");
|
|
222
|
+
expect(result.current?.account?.me?.$jazz.id).toBe(id);
|
|
223
|
+
|
|
224
|
+
await act(async () => {
|
|
225
|
+
await result.current?.logOut();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(result.current?.passphraseAuth.state).toBe("anonymous");
|
|
229
|
+
expect(result.current?.account?.me?.$jazz.id).not.toBe(id);
|
|
230
|
+
|
|
231
|
+
expect(updates).toMatchInlineSnapshot(`
|
|
232
|
+
[
|
|
233
|
+
{
|
|
234
|
+
"accountIndex": 0,
|
|
235
|
+
"state": "anonymous",
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"accountIndex": 0,
|
|
239
|
+
"state": "signedIn",
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"accountIndex": 0,
|
|
243
|
+
"state": "anonymous",
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"accountIndex": 1,
|
|
247
|
+
"state": "anonymous",
|
|
248
|
+
},
|
|
249
|
+
]
|
|
250
|
+
`);
|
|
251
|
+
});
|
|
180
252
|
});
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
SubscribeRestArgs,
|
|
22
22
|
TypeSym,
|
|
23
23
|
BranchDefinition,
|
|
24
|
+
getIdFromHeader,
|
|
25
|
+
unstable_loadUnique,
|
|
24
26
|
} from "../internal.js";
|
|
25
27
|
import {
|
|
26
28
|
AnonymousJazzAgent,
|
|
@@ -320,19 +322,17 @@ export class CoList<out Item = any>
|
|
|
320
322
|
ownerID: ID<Account> | ID<Group>,
|
|
321
323
|
as?: Account | Group | AnonymousJazzAgent,
|
|
322
324
|
) {
|
|
323
|
-
|
|
325
|
+
const header = CoList._getUniqueHeader(unique, ownerID);
|
|
326
|
+
|
|
327
|
+
return getIdFromHeader(header, as);
|
|
324
328
|
}
|
|
325
329
|
|
|
326
330
|
/** @internal */
|
|
327
|
-
static
|
|
328
|
-
this: CoValueClass<L>,
|
|
331
|
+
static _getUniqueHeader(
|
|
329
332
|
unique: CoValueUniqueness["uniqueness"],
|
|
330
333
|
ownerID: ID<Account> | ID<Group>,
|
|
331
|
-
as?: Account | Group | AnonymousJazzAgent,
|
|
332
334
|
) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const header = {
|
|
335
|
+
return {
|
|
336
336
|
type: "colist" as const,
|
|
337
337
|
ruleset: {
|
|
338
338
|
type: "ownedByGroup" as const,
|
|
@@ -341,9 +341,6 @@ export class CoList<out Item = any>
|
|
|
341
341
|
meta: null,
|
|
342
342
|
uniqueness: unique,
|
|
343
343
|
};
|
|
344
|
-
const crypto =
|
|
345
|
-
as[TypeSym] === "Anonymous" ? as.node.crypto : as.$jazz.localNode.crypto;
|
|
346
|
-
return cojsonInternals.idforHeader(header, crypto) as ID<L>;
|
|
347
344
|
}
|
|
348
345
|
|
|
349
346
|
/**
|
|
@@ -378,29 +375,24 @@ export class CoList<out Item = any>
|
|
|
378
375
|
resolve?: RefsToResolveStrict<L, R>;
|
|
379
376
|
},
|
|
380
377
|
): Promise<Resolved<L, R> | null> {
|
|
381
|
-
const
|
|
378
|
+
const header = CoList._getUniqueHeader(
|
|
382
379
|
options.unique,
|
|
383
380
|
options.owner.$jazz.id,
|
|
384
|
-
options.owner.$jazz.loadedAs,
|
|
385
381
|
);
|
|
386
|
-
let list: Resolved<L, R> | null = await loadCoValueWithoutMe(this, listId, {
|
|
387
|
-
...options,
|
|
388
|
-
loadAs: options.owner.$jazz.loadedAs,
|
|
389
|
-
skipRetry: true,
|
|
390
|
-
});
|
|
391
|
-
if (!list) {
|
|
392
|
-
list = (this as any).create(options.value, {
|
|
393
|
-
owner: options.owner,
|
|
394
|
-
unique: options.unique,
|
|
395
|
-
}) as Resolved<L, R>;
|
|
396
|
-
} else {
|
|
397
|
-
(list as L).$jazz.applyDiff(options.value);
|
|
398
|
-
}
|
|
399
382
|
|
|
400
|
-
return
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
383
|
+
return unstable_loadUnique(this, {
|
|
384
|
+
header,
|
|
385
|
+
owner: options.owner,
|
|
386
|
+
resolve: options.resolve,
|
|
387
|
+
onCreateWhenMissing: () => {
|
|
388
|
+
(this as any).create(options.value, {
|
|
389
|
+
owner: options.owner,
|
|
390
|
+
unique: options.unique,
|
|
391
|
+
});
|
|
392
|
+
},
|
|
393
|
+
onUpdateWhenFound(value) {
|
|
394
|
+
value.$jazz.applyDiff(options.value);
|
|
395
|
+
},
|
|
404
396
|
});
|
|
405
397
|
}
|
|
406
398
|
|
|
@@ -411,7 +403,10 @@ export class CoList<out Item = any>
|
|
|
411
403
|
* @param options Additional options for loading the CoList.
|
|
412
404
|
* @returns The loaded CoList, or null if unavailable.
|
|
413
405
|
*/
|
|
414
|
-
static loadUnique<
|
|
406
|
+
static async loadUnique<
|
|
407
|
+
L extends CoList,
|
|
408
|
+
const R extends RefsToResolve<L> = true,
|
|
409
|
+
>(
|
|
415
410
|
this: CoValueClass<L>,
|
|
416
411
|
unique: CoValueUniqueness["uniqueness"],
|
|
417
412
|
ownerID: ID<Account> | ID<Group>,
|
|
@@ -420,11 +415,19 @@ export class CoList<out Item = any>
|
|
|
420
415
|
loadAs?: Account | AnonymousJazzAgent;
|
|
421
416
|
},
|
|
422
417
|
): Promise<Resolved<L, R> | null> {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
);
|
|
418
|
+
const header = CoList._getUniqueHeader(unique, ownerID);
|
|
419
|
+
|
|
420
|
+
const owner = await Group.load(ownerID, {
|
|
421
|
+
loadAs: options?.loadAs,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
if (!owner) return owner;
|
|
425
|
+
|
|
426
|
+
return unstable_loadUnique(this, {
|
|
427
|
+
header,
|
|
428
|
+
owner,
|
|
429
|
+
resolve: options?.resolve,
|
|
430
|
+
});
|
|
428
431
|
}
|
|
429
432
|
|
|
430
433
|
// Override mutation methods defined on Array, as CoLists aren't meant to be mutated directly
|
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
SubscribeRestArgs,
|
|
29
29
|
TypeSym,
|
|
30
30
|
BranchDefinition,
|
|
31
|
+
getIdFromHeader,
|
|
32
|
+
unstable_loadUnique,
|
|
31
33
|
} from "../internal.js";
|
|
32
34
|
import {
|
|
33
35
|
Account,
|
|
@@ -434,19 +436,17 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
|
434
436
|
ownerID: ID<Account> | ID<Group>,
|
|
435
437
|
as?: Account | Group | AnonymousJazzAgent,
|
|
436
438
|
) {
|
|
437
|
-
|
|
439
|
+
const header = CoMap._getUniqueHeader(unique, ownerID);
|
|
440
|
+
|
|
441
|
+
return getIdFromHeader(header, as);
|
|
438
442
|
}
|
|
439
443
|
|
|
440
444
|
/** @internal */
|
|
441
|
-
static
|
|
442
|
-
this: CoValueClass<M>,
|
|
445
|
+
static _getUniqueHeader(
|
|
443
446
|
unique: CoValueUniqueness["uniqueness"],
|
|
444
447
|
ownerID: ID<Account> | ID<Group>,
|
|
445
|
-
as?: Account | Group | AnonymousJazzAgent,
|
|
446
448
|
) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
const header = {
|
|
449
|
+
return {
|
|
450
450
|
type: "comap" as const,
|
|
451
451
|
ruleset: {
|
|
452
452
|
type: "ownedByGroup" as const,
|
|
@@ -455,9 +455,6 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
|
455
455
|
meta: null,
|
|
456
456
|
uniqueness: unique,
|
|
457
457
|
};
|
|
458
|
-
const crypto =
|
|
459
|
-
as[TypeSym] === "Anonymous" ? as.node.crypto : as.$jazz.localNode.crypto;
|
|
460
|
-
return cojsonInternals.idforHeader(header, crypto) as ID<M>;
|
|
461
458
|
}
|
|
462
459
|
|
|
463
460
|
/**
|
|
@@ -497,32 +494,24 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
|
497
494
|
resolve?: RefsToResolveStrict<M, R>;
|
|
498
495
|
},
|
|
499
496
|
): Promise<Resolved<M, R> | null> {
|
|
500
|
-
const
|
|
497
|
+
const header = CoMap._getUniqueHeader(
|
|
501
498
|
options.unique,
|
|
502
499
|
options.owner.$jazz.id,
|
|
503
|
-
options.owner.$jazz.loadedAs,
|
|
504
500
|
);
|
|
505
|
-
let map: Resolved<M, R> | null = await loadCoValueWithoutMe(this, mapId, {
|
|
506
|
-
...options,
|
|
507
|
-
loadAs: options.owner.$jazz.loadedAs,
|
|
508
|
-
skipRetry: true,
|
|
509
|
-
});
|
|
510
|
-
if (!map) {
|
|
511
|
-
const instance = new this();
|
|
512
|
-
map = CoMap._createCoMap(instance, options.value, {
|
|
513
|
-
owner: options.owner,
|
|
514
|
-
unique: options.unique,
|
|
515
|
-
}) as Resolved<M, R>;
|
|
516
|
-
} else {
|
|
517
|
-
(map as M).$jazz.applyDiff(
|
|
518
|
-
options.value as unknown as Partial<CoMapInit<M>>,
|
|
519
|
-
);
|
|
520
|
-
}
|
|
521
501
|
|
|
522
|
-
return
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
502
|
+
return unstable_loadUnique(this, {
|
|
503
|
+
header,
|
|
504
|
+
owner: options.owner,
|
|
505
|
+
resolve: options.resolve,
|
|
506
|
+
onCreateWhenMissing: () => {
|
|
507
|
+
(this as any).create(options.value, {
|
|
508
|
+
owner: options.owner,
|
|
509
|
+
unique: options.unique,
|
|
510
|
+
});
|
|
511
|
+
},
|
|
512
|
+
onUpdateWhenFound(value) {
|
|
513
|
+
value.$jazz.applyDiff(options.value);
|
|
514
|
+
},
|
|
526
515
|
});
|
|
527
516
|
}
|
|
528
517
|
|
|
@@ -535,7 +524,10 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
|
535
524
|
*
|
|
536
525
|
* @deprecated Use `co.map(...).loadUnique` instead.
|
|
537
526
|
*/
|
|
538
|
-
static loadUnique<
|
|
527
|
+
static async loadUnique<
|
|
528
|
+
M extends CoMap,
|
|
529
|
+
const R extends RefsToResolve<M> = true,
|
|
530
|
+
>(
|
|
539
531
|
this: CoValueClass<M>,
|
|
540
532
|
unique: CoValueUniqueness["uniqueness"],
|
|
541
533
|
ownerID: ID<Account> | ID<Group>,
|
|
@@ -544,11 +536,19 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
|
544
536
|
loadAs?: Account | AnonymousJazzAgent;
|
|
545
537
|
},
|
|
546
538
|
): Promise<Resolved<M, R> | null> {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
);
|
|
539
|
+
const header = CoMap._getUniqueHeader(unique, ownerID);
|
|
540
|
+
|
|
541
|
+
const owner = await Group.load(ownerID, {
|
|
542
|
+
loadAs: options?.loadAs,
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
if (!owner) return owner;
|
|
546
|
+
|
|
547
|
+
return unstable_loadUnique(this, {
|
|
548
|
+
header,
|
|
549
|
+
owner,
|
|
550
|
+
resolve: options?.resolve,
|
|
551
|
+
});
|
|
552
552
|
}
|
|
553
553
|
}
|
|
554
554
|
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type Role,
|
|
10
10
|
} from "cojson";
|
|
11
11
|
import {
|
|
12
|
+
AnonymousJazzAgent,
|
|
12
13
|
BranchDefinition,
|
|
13
14
|
CoValue,
|
|
14
15
|
CoValueClass,
|
|
@@ -272,7 +273,10 @@ export class Group extends CoValueBase implements CoValue {
|
|
|
272
273
|
static load<G extends Group, const R extends RefsToResolve<G>>(
|
|
273
274
|
this: CoValueClass<G>,
|
|
274
275
|
id: ID<G>,
|
|
275
|
-
options?: {
|
|
276
|
+
options?: {
|
|
277
|
+
resolve?: RefsToResolveStrict<G, R>;
|
|
278
|
+
loadAs?: Account | AnonymousJazzAgent;
|
|
279
|
+
},
|
|
276
280
|
): Promise<Resolved<G, R> | null> {
|
|
277
281
|
return loadCoValueWithoutMe(this, id, options);
|
|
278
282
|
}
|
|
@@ -293,12 +293,12 @@ export class Inbox {
|
|
|
293
293
|
|
|
294
294
|
const handleNewMessages = () => {
|
|
295
295
|
for (const tx of messagesFeed.getNewItems()) {
|
|
296
|
-
const accountID = getAccountIDfromSessionID(tx.
|
|
296
|
+
const accountID = getAccountIDfromSessionID(tx.currentTxID.sessionID);
|
|
297
297
|
|
|
298
298
|
if (!accountID) {
|
|
299
299
|
console.warn(
|
|
300
300
|
"Received message from unknown account",
|
|
301
|
-
tx.
|
|
301
|
+
tx.currentTxID.sessionID,
|
|
302
302
|
);
|
|
303
303
|
continue;
|
|
304
304
|
}
|
|
@@ -309,7 +309,8 @@ export class Inbox {
|
|
|
309
309
|
continue;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
const txKey =
|
|
312
|
+
const txKey =
|
|
313
|
+
`${tx.currentTxID.sessionID}/${tx.currentTxID.txIndex}` as const;
|
|
313
314
|
|
|
314
315
|
if (processed.has(txKey)) {
|
|
315
316
|
continue;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
cojsonInternals,
|
|
2
3
|
type CoValueUniqueness,
|
|
3
4
|
type CojsonInternalTypes,
|
|
4
5
|
type RawCoValue,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
inspect,
|
|
26
27
|
} from "../internal.js";
|
|
27
28
|
import type { BranchDefinition } from "../subscribe/types.js";
|
|
29
|
+
import { CoValueHeader } from "cojson/dist/coValueCore/verifiedState.js";
|
|
28
30
|
|
|
29
31
|
/** @category Abstract interfaces */
|
|
30
32
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -446,6 +448,92 @@ export function parseGroupCreateOptions(
|
|
|
446
448
|
: { owner: options.owner ?? activeAccountContext.get() };
|
|
447
449
|
}
|
|
448
450
|
|
|
451
|
+
export function getIdFromHeader(
|
|
452
|
+
header: CoValueHeader,
|
|
453
|
+
loadAs?: Account | AnonymousJazzAgent | Group,
|
|
454
|
+
) {
|
|
455
|
+
loadAs ||= activeAccountContext.get();
|
|
456
|
+
|
|
457
|
+
const node =
|
|
458
|
+
loadAs[TypeSym] === "Anonymous" ? loadAs.node : loadAs.$jazz.localNode;
|
|
459
|
+
|
|
460
|
+
return cojsonInternals.idforHeader(header, node.crypto);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export async function unstable_loadUnique<
|
|
464
|
+
V extends CoValue,
|
|
465
|
+
R extends RefsToResolve<V>,
|
|
466
|
+
>(
|
|
467
|
+
cls: CoValueClass<V>,
|
|
468
|
+
options: {
|
|
469
|
+
header: CoValueHeader;
|
|
470
|
+
onCreateWhenMissing?: () => void;
|
|
471
|
+
onUpdateWhenFound?: (value: Resolved<V, R>) => void;
|
|
472
|
+
owner: Account | Group;
|
|
473
|
+
resolve?: RefsToResolveStrict<V, R>;
|
|
474
|
+
},
|
|
475
|
+
): Promise<Resolved<V, R> | null> {
|
|
476
|
+
const loadAs = options.owner.$jazz.loadedAs;
|
|
477
|
+
|
|
478
|
+
const node =
|
|
479
|
+
loadAs[TypeSym] === "Anonymous" ? loadAs.node : loadAs.$jazz.localNode;
|
|
480
|
+
|
|
481
|
+
const id = cojsonInternals.idforHeader(options.header, node.crypto);
|
|
482
|
+
|
|
483
|
+
// We first try to load the unique value without using resolve and without
|
|
484
|
+
// retrying failures
|
|
485
|
+
// This way when we want to upsert we are sure that, if the load failed
|
|
486
|
+
// it failed because the unique value was missing
|
|
487
|
+
let result = await loadCoValueWithoutMe(cls, id, {
|
|
488
|
+
skipRetry: true,
|
|
489
|
+
loadAs,
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
if (options.onCreateWhenMissing) {
|
|
493
|
+
// if load returns unavailable, we check the state in localNode
|
|
494
|
+
// to ward against race conditions that would happen when
|
|
495
|
+
// running the same upsert unique concurrently
|
|
496
|
+
if (!result && node.getCoValue(id).hasVerifiedContent()) {
|
|
497
|
+
result = await loadCoValueWithoutMe(cls, id, {
|
|
498
|
+
loadAs,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (!result) {
|
|
503
|
+
options.onCreateWhenMissing();
|
|
504
|
+
|
|
505
|
+
return loadCoValueWithoutMe(cls, id, {
|
|
506
|
+
loadAs,
|
|
507
|
+
resolve: options.resolve,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (!result) return result;
|
|
513
|
+
|
|
514
|
+
if (options.onUpdateWhenFound) {
|
|
515
|
+
// we deeply load the value, retrying any failures
|
|
516
|
+
const loaded = await loadCoValueWithoutMe(cls, id, {
|
|
517
|
+
loadAs,
|
|
518
|
+
resolve: options.resolve,
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
if (loaded) {
|
|
522
|
+
// we don't return the update result because
|
|
523
|
+
// we want to run another load to backfill any possible partially loaded
|
|
524
|
+
// values that have been set in the update
|
|
525
|
+
options.onUpdateWhenFound(loaded);
|
|
526
|
+
} else {
|
|
527
|
+
return loaded;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
return loadCoValueWithoutMe(cls, id, {
|
|
532
|
+
loadAs,
|
|
533
|
+
resolve: options.resolve,
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
449
537
|
/**
|
|
450
538
|
* Deeply export a CoValue to a content piece.
|
|
451
539
|
*
|