jazz-tools 0.19.14 → 0.19.15
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 +55 -55
- package/CHANGELOG.md +15 -0
- package/dist/{chunk-GAPMDNJY.js → chunk-R3KIZG4P.js} +47 -27
- package/dist/chunk-R3KIZG4P.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/react-native/index.js +18 -0
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native-core/ReactNativeSessionProvider.d.ts.map +1 -1
- package/dist/react-native-core/index.js +18 -0
- package/dist/react-native-core/index.js.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/tools/coValues/CoValueBase.d.ts +13 -0
- package/dist/tools/coValues/CoValueBase.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts +33 -35
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/react-native-core/ReactNativeSessionProvider.ts +29 -3
- package/src/react-native-core/tests/ReactNativeSessionProvider.test.ts +175 -3
- package/src/tools/coValues/CoValueBase.ts +24 -0
- package/src/tools/coValues/coMap.ts +1 -1
- package/src/tools/implementation/createContext.ts +2 -2
- package/src/tools/subscribe/SubscriptionScope.ts +43 -34
- package/src/tools/tests/account.test.ts +19 -0
- package/src/tools/tests/coMap.record.test.ts +43 -0
- package/src/tools/tests/coMap.test.ts +67 -1
- package/dist/chunk-GAPMDNJY.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CoValueBase.d.ts","sourceRoot":"","sources":["../../../src/tools/coValues/CoValueBase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AACvE,OAAO,EACL,kBAAkB,EAClB,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,eAAe,EAEf,KAAK,iBAAiB,EAKtB,OAAO,EAER,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEhD,gBAAgB;AAChB,8BAAsB,WAAY,YAAW,OAAO;IAC1C,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAE1B,SAAiB,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IACrC,SAAS,EAAE,IAAI,CAAC;;IAQxB,0BAA0B;IAC1B,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,GAAG,CAAC;IAK5E,MAAM,IAAI,MAAM,GAAG,GAAG,EAAE,GAAG,MAAM;IAQjC,CAAC,OAAO,CAAC;CAGV;AAED,8BAAsB,cAAc,CAAC,CAAC,SAAS,OAAO;IAKxC,OAAO,CAAC,OAAO;IAJ3B,0BAA0B;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;gBAE/C,OAAO,EAAE,CAAC;IAO9B,IAAI,EAAE,IAAI,MAAM,CAQf;IAED,IAAI,YAAY,IAAI,OAAO,mBAAmB,CAAC,MAAM,CAEpD;IAED,QAAQ,KAAK,GAAG,IAAI,UAAU,CAAC;IAC/B,QAAQ,KAAK,KAAK,IAAI,KAAK,GAAG,SAAS,CAAC;IAExC,gBAAgB;IAChB,IAAI,SAAS,IAAI,SAAS,CAEzB;IAED,eAAe;IACf,IAAI,QAAQ,wDAYX;IAED;;;;OAIG;IACH,IAAI,SAAS,IAAI,MAAM,CAQtB;IAED;;;;;;OAMG;IACH,IAAI,aAAa,IAAI,MAAM,CAQ1B;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAInC;IAED,IAAI,UAAU,IAAI,OAAO,CAIxB;IAED;;;;OAIG;IACH,cAAc;IAUd,MAAM,IAAI,eAAe,CAAC,CAAC,CAAC;CAO7B"}
|
|
1
|
+
{"version":3,"file":"CoValueBase.d.ts","sourceRoot":"","sources":["../../../src/tools/coValues/CoValueBase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AACvE,OAAO,EACL,kBAAkB,EAClB,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,eAAe,EAEf,KAAK,iBAAiB,EAKtB,OAAO,EAER,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEhD,gBAAgB;AAChB,8BAAsB,WAAY,YAAW,OAAO;IAC1C,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAE1B,SAAiB,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IACrC,SAAS,EAAE,IAAI,CAAC;;IAQxB,0BAA0B;IAC1B,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,GAAG,CAAC;IAK5E,MAAM,IAAI,MAAM,GAAG,GAAG,EAAE,GAAG,MAAM;IAQjC,CAAC,OAAO,CAAC;CAGV;AAED,8BAAsB,cAAc,CAAC,CAAC,SAAS,OAAO;IAKxC,OAAO,CAAC,OAAO;IAJ3B,0BAA0B;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;gBAE/C,OAAO,EAAE,CAAC;IAO9B,IAAI,EAAE,IAAI,MAAM,CAQf;IAED,IAAI,YAAY,IAAI,OAAO,mBAAmB,CAAC,MAAM,CAEpD;IAED,QAAQ,KAAK,GAAG,IAAI,UAAU,CAAC;IAC/B,QAAQ,KAAK,KAAK,IAAI,KAAK,GAAG,SAAS,CAAC;IAExC,gBAAgB;IAChB,IAAI,SAAS,IAAI,SAAS,CAEzB;IAED,eAAe;IACf,IAAI,QAAQ,wDAYX;IAED;;;;OAIG;IACH,IAAI,SAAS,IAAI,MAAM,CAQtB;IAED;;;;;;;;;;;OAWG;IACH,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAUlC;IAED;;;;;;OAMG;IACH,IAAI,aAAa,IAAI,MAAM,CAQ1B;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAInC;IAED,IAAI,UAAU,IAAI,OAAO,CAIxB;IAED;;;;OAIG;IACH,cAAc;IAUd,MAAM,IAAI,eAAe,CAAC,CAAC,CAAC;CAO7B"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { LocalNode
|
|
2
|
-
import {
|
|
3
|
-
import { CoValueCoreSubscription } from "./CoValueCoreSubscription.js";
|
|
1
|
+
import { LocalNode } from "cojson";
|
|
2
|
+
import { type CoValue, type ID, MaybeLoaded, NotLoaded, type RefEncoded, type RefsToResolve } from "../internal.js";
|
|
4
3
|
import { JazzError } from "./JazzError.js";
|
|
5
4
|
import type { BranchDefinition, SubscriptionValue, SubscriptionValueLoading } from "./types.js";
|
|
6
|
-
import { CoValueLoadingState, NotLoadedCoValueState } from "./types.js";
|
|
7
5
|
import { PromiseWithStatus } from "./utils.js";
|
|
8
6
|
export declare class SubscriptionScope<D extends CoValue> {
|
|
9
7
|
node: LocalNode;
|
|
@@ -21,24 +19,24 @@ export declare class SubscriptionScope<D extends CoValue> {
|
|
|
21
19
|
/**
|
|
22
20
|
* Autoloaded child ids that are unloaded
|
|
23
21
|
*/
|
|
24
|
-
pendingAutoloadedChildren
|
|
22
|
+
private pendingAutoloadedChildren;
|
|
25
23
|
value: SubscriptionValue<D, any> | SubscriptionValueLoading;
|
|
26
|
-
childErrors
|
|
27
|
-
validationErrors
|
|
24
|
+
private childErrors;
|
|
25
|
+
private validationErrors;
|
|
28
26
|
errorFromChildren: JazzError | undefined;
|
|
29
|
-
subscription
|
|
30
|
-
dirty
|
|
31
|
-
resolve
|
|
32
|
-
idsSubscribed
|
|
33
|
-
autoloaded
|
|
34
|
-
autoloadedKeys
|
|
35
|
-
skipInvalidKeys
|
|
36
|
-
totalValidTransactions
|
|
37
|
-
version
|
|
38
|
-
migrated
|
|
39
|
-
migrating
|
|
27
|
+
private subscription;
|
|
28
|
+
private dirty;
|
|
29
|
+
private resolve;
|
|
30
|
+
private idsSubscribed;
|
|
31
|
+
private autoloaded;
|
|
32
|
+
private autoloadedKeys;
|
|
33
|
+
private skipInvalidKeys;
|
|
34
|
+
private totalValidTransactions;
|
|
35
|
+
private version;
|
|
36
|
+
private migrated;
|
|
37
|
+
private migrating;
|
|
40
38
|
closed: boolean;
|
|
41
|
-
silenceUpdates
|
|
39
|
+
private silenceUpdates;
|
|
42
40
|
/**
|
|
43
41
|
* Stack trace captured at subscription creation time.
|
|
44
42
|
* This helps identify which component/hook created the subscription
|
|
@@ -47,22 +45,22 @@ export declare class SubscriptionScope<D extends CoValue> {
|
|
|
47
45
|
callerStack: Error | undefined;
|
|
48
46
|
constructor(node: LocalNode, resolve: RefsToResolve<D>, id: ID<D>, schema: RefEncoded<D>, skipRetry?: boolean, bestEffortResolution?: boolean, unstable_branch?: BranchDefinition | undefined, callerStack?: Error | undefined);
|
|
49
47
|
updateValue(value: SubscriptionValue<D, any>): void;
|
|
50
|
-
handleUpdate
|
|
51
|
-
computeChildErrors
|
|
52
|
-
handleChildUpdate
|
|
53
|
-
shouldSendUpdates
|
|
48
|
+
private handleUpdate;
|
|
49
|
+
private computeChildErrors;
|
|
50
|
+
handleChildUpdate(id: string, value: SubscriptionValue<any, any> | SubscriptionValueLoading, key?: string): void;
|
|
51
|
+
private shouldSendUpdates;
|
|
54
52
|
unloadedValue: NotLoaded<D> | undefined;
|
|
55
|
-
lastPromise
|
|
56
|
-
getPromise
|
|
53
|
+
private lastPromise;
|
|
54
|
+
private getPromise;
|
|
57
55
|
getCachedPromise(): PromiseWithStatus<D>;
|
|
58
56
|
private getUnloadedValue;
|
|
59
|
-
lastErrorLogged
|
|
57
|
+
private lastErrorLogged;
|
|
60
58
|
getCurrentValue(): MaybeLoaded<D>;
|
|
61
|
-
getCurrentRawValue
|
|
62
|
-
getCreationStackLines
|
|
63
|
-
getError
|
|
64
|
-
logError
|
|
65
|
-
triggerUpdate
|
|
59
|
+
private getCurrentRawValue;
|
|
60
|
+
private getCreationStackLines;
|
|
61
|
+
private getError;
|
|
62
|
+
private logError;
|
|
63
|
+
private triggerUpdate;
|
|
66
64
|
subscribers: Set<(value: SubscriptionValue<D, any>) => void>;
|
|
67
65
|
subscriberChangeCallbacks: Set<(count: number) => void>;
|
|
68
66
|
/**
|
|
@@ -83,10 +81,10 @@ export declare class SubscriptionScope<D extends CoValue> {
|
|
|
83
81
|
*/
|
|
84
82
|
pullValue(listener: (value: SubscriptionValue<D, any>) => void): void;
|
|
85
83
|
subscribeToId(id: string, descriptor: RefEncoded<any>): void;
|
|
86
|
-
loadChildren
|
|
87
|
-
loadCoMapKey
|
|
88
|
-
loadCoListKey
|
|
89
|
-
loadChildNode
|
|
84
|
+
private loadChildren;
|
|
85
|
+
private loadCoMapKey;
|
|
86
|
+
private loadCoListKey;
|
|
87
|
+
private loadChildNode;
|
|
90
88
|
destroy(): void;
|
|
91
89
|
}
|
|
92
90
|
//# sourceMappingURL=SubscriptionScope.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubscriptionScope.d.ts","sourceRoot":"","sources":["../../../src/tools/subscribe/SubscriptionScope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"SubscriptionScope.d.ts","sourceRoot":"","sources":["../../../src/tools/subscribe/SubscriptionScope.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -205,7 +205,7 @@
|
|
|
205
205
|
},
|
|
206
206
|
"type": "module",
|
|
207
207
|
"license": "MIT",
|
|
208
|
-
"version": "0.19.
|
|
208
|
+
"version": "0.19.15",
|
|
209
209
|
"dependencies": {
|
|
210
210
|
"@manuscripts/prosemirror-recreate-steps": "^0.1.4",
|
|
211
211
|
"@scure/base": "1.2.1",
|
|
@@ -222,9 +222,9 @@
|
|
|
222
222
|
"prosemirror-transform": "^1.9.0",
|
|
223
223
|
"use-sync-external-store": "^1.5.0",
|
|
224
224
|
"zod": "4.1.11",
|
|
225
|
-
"cojson": "0.19.
|
|
226
|
-
"cojson-storage-indexeddb": "0.19.
|
|
227
|
-
"cojson-transport-ws": "0.19.
|
|
225
|
+
"cojson": "0.19.15",
|
|
226
|
+
"cojson-storage-indexeddb": "0.19.15",
|
|
227
|
+
"cojson-transport-ws": "0.19.15"
|
|
228
228
|
},
|
|
229
229
|
"devDependencies": {
|
|
230
230
|
"@scure/bip39": "^1.3.0",
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
} from "jazz-tools";
|
|
7
7
|
import { AgentID, RawAccountID } from "cojson";
|
|
8
8
|
|
|
9
|
+
const lockedSessions = new Set<SessionID>();
|
|
10
|
+
|
|
9
11
|
export class ReactNativeSessionProvider implements SessionProvider {
|
|
10
12
|
async acquireSession(
|
|
11
13
|
accountID: string,
|
|
@@ -14,11 +16,29 @@ export class ReactNativeSessionProvider implements SessionProvider {
|
|
|
14
16
|
const kvStore = KvStoreContext.getInstance().getStorage();
|
|
15
17
|
const existingSession = await kvStore.get(accountID as string);
|
|
16
18
|
|
|
19
|
+
// Check if the session is already in use, should happen only if the dev
|
|
20
|
+
// mounts multiple providers at the same time
|
|
21
|
+
if (lockedSessions.has(existingSession as SessionID)) {
|
|
22
|
+
const newSessionID = crypto.newRandomSessionID(
|
|
23
|
+
accountID as RawAccountID | AgentID,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
console.error("Existing session in use, creating new one", newSessionID);
|
|
27
|
+
|
|
28
|
+
return Promise.resolve({
|
|
29
|
+
sessionID: newSessionID,
|
|
30
|
+
sessionDone: () => {},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
17
34
|
if (existingSession) {
|
|
18
35
|
console.log("Using existing session", existingSession);
|
|
36
|
+
lockedSessions.add(existingSession as SessionID);
|
|
19
37
|
return Promise.resolve({
|
|
20
38
|
sessionID: existingSession as SessionID,
|
|
21
|
-
sessionDone: () => {
|
|
39
|
+
sessionDone: () => {
|
|
40
|
+
lockedSessions.delete(existingSession as SessionID);
|
|
41
|
+
},
|
|
22
42
|
});
|
|
23
43
|
}
|
|
24
44
|
|
|
@@ -30,12 +50,15 @@ export class ReactNativeSessionProvider implements SessionProvider {
|
|
|
30
50
|
accountID as RawAccountID | AgentID,
|
|
31
51
|
);
|
|
32
52
|
await kvStore.set(accountID, newSessionID);
|
|
53
|
+
lockedSessions.add(newSessionID);
|
|
33
54
|
|
|
34
55
|
console.error("Created new session", newSessionID);
|
|
35
56
|
|
|
36
57
|
return Promise.resolve({
|
|
37
58
|
sessionID: newSessionID,
|
|
38
|
-
sessionDone: () => {
|
|
59
|
+
sessionDone: () => {
|
|
60
|
+
lockedSessions.delete(newSessionID);
|
|
61
|
+
},
|
|
39
62
|
});
|
|
40
63
|
}
|
|
41
64
|
|
|
@@ -45,8 +68,11 @@ export class ReactNativeSessionProvider implements SessionProvider {
|
|
|
45
68
|
): Promise<{ sessionDone: () => void }> {
|
|
46
69
|
const kvStore = KvStoreContext.getInstance().getStorage();
|
|
47
70
|
await kvStore.set(accountID, sessionID);
|
|
71
|
+
lockedSessions.add(sessionID);
|
|
48
72
|
return Promise.resolve({
|
|
49
|
-
sessionDone: () => {
|
|
73
|
+
sessionDone: () => {
|
|
74
|
+
lockedSessions.delete(sessionID);
|
|
75
|
+
},
|
|
50
76
|
});
|
|
51
77
|
}
|
|
52
78
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
|
2
|
-
import { SessionID } from "cojson";
|
|
2
|
+
import { RawAccountID, SessionID } from "cojson";
|
|
3
3
|
import { beforeEach, describe, expect, test } from "vitest";
|
|
4
4
|
import { InMemoryKVStore } from "jazz-tools";
|
|
5
5
|
import { KvStoreContext, type KvStore } from "jazz-tools";
|
|
@@ -51,6 +51,9 @@ describe("ReactNativeSessionProvider", () => {
|
|
|
51
51
|
const storedSession = await kvStore.get(accountID);
|
|
52
52
|
expect(storedSession).toBeDefined();
|
|
53
53
|
expect(storedSession).toBe(result.sessionID);
|
|
54
|
+
|
|
55
|
+
// Clean up
|
|
56
|
+
result.sessionDone();
|
|
54
57
|
});
|
|
55
58
|
|
|
56
59
|
test("returns existing session when one exists", async () => {
|
|
@@ -77,6 +80,89 @@ describe("ReactNativeSessionProvider", () => {
|
|
|
77
80
|
const sessionAfter = await kvStore.get(accountID);
|
|
78
81
|
expect(sessionAfter).toBe(existingSessionID);
|
|
79
82
|
expect(sessionAfter).toBe(result.sessionID);
|
|
83
|
+
|
|
84
|
+
// Clean up
|
|
85
|
+
result.sessionDone();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("creates new session when existing session is locked", async () => {
|
|
89
|
+
const accountID = account.$jazz.id;
|
|
90
|
+
const existingSessionID = Crypto.newRandomSessionID(
|
|
91
|
+
accountID as RawAccountID,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// Pre-populate KvStore with a session ID
|
|
95
|
+
await kvStore.set(accountID, existingSessionID);
|
|
96
|
+
|
|
97
|
+
// Acquire the session (this locks it)
|
|
98
|
+
const firstResult = await sessionProvider.acquireSession(
|
|
99
|
+
accountID,
|
|
100
|
+
Crypto as CryptoProvider,
|
|
101
|
+
);
|
|
102
|
+
expect(firstResult.sessionID).toBe(existingSessionID);
|
|
103
|
+
|
|
104
|
+
// Try to acquire session again while the first is still locked
|
|
105
|
+
const secondResult = await sessionProvider.acquireSession(
|
|
106
|
+
accountID,
|
|
107
|
+
Crypto as CryptoProvider,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Should get a different (new) session since the existing one is locked
|
|
111
|
+
expect(secondResult.sessionID).not.toBe(existingSessionID);
|
|
112
|
+
expect(secondResult.sessionID).toBeDefined();
|
|
113
|
+
|
|
114
|
+
// Clean up
|
|
115
|
+
firstResult.sessionDone();
|
|
116
|
+
secondResult.sessionDone();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("reuses session after sessionDone is called", async () => {
|
|
120
|
+
const accountID = account.$jazz.id;
|
|
121
|
+
|
|
122
|
+
// Acquire initial session
|
|
123
|
+
const firstResult = await sessionProvider.acquireSession(
|
|
124
|
+
accountID,
|
|
125
|
+
Crypto as CryptoProvider,
|
|
126
|
+
);
|
|
127
|
+
const firstSessionID = firstResult.sessionID;
|
|
128
|
+
|
|
129
|
+
// Release the session
|
|
130
|
+
firstResult.sessionDone();
|
|
131
|
+
|
|
132
|
+
// Acquire session again - should reuse the same session
|
|
133
|
+
const secondResult = await sessionProvider.acquireSession(
|
|
134
|
+
accountID,
|
|
135
|
+
Crypto as CryptoProvider,
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(secondResult.sessionID).toBe(firstSessionID);
|
|
139
|
+
|
|
140
|
+
// Clean up
|
|
141
|
+
secondResult.sessionDone();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("sessionDone can be called multiple times safely", async () => {
|
|
145
|
+
const accountID = account.$jazz.id;
|
|
146
|
+
|
|
147
|
+
const result = await sessionProvider.acquireSession(
|
|
148
|
+
accountID,
|
|
149
|
+
Crypto as CryptoProvider,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Call sessionDone multiple times - should not throw
|
|
153
|
+
result.sessionDone();
|
|
154
|
+
result.sessionDone();
|
|
155
|
+
result.sessionDone();
|
|
156
|
+
|
|
157
|
+
// Should still be able to acquire the session
|
|
158
|
+
const secondResult = await sessionProvider.acquireSession(
|
|
159
|
+
accountID,
|
|
160
|
+
Crypto as CryptoProvider,
|
|
161
|
+
);
|
|
162
|
+
expect(secondResult.sessionID).toBe(result.sessionID);
|
|
163
|
+
|
|
164
|
+
// Clean up
|
|
165
|
+
secondResult.sessionDone();
|
|
80
166
|
});
|
|
81
167
|
});
|
|
82
168
|
|
|
@@ -90,7 +176,10 @@ describe("ReactNativeSessionProvider", () => {
|
|
|
90
176
|
expect(sessionBefore).toBeNull();
|
|
91
177
|
|
|
92
178
|
// Persist session
|
|
93
|
-
await sessionProvider.persistSession(
|
|
179
|
+
const { sessionDone } = await sessionProvider.persistSession(
|
|
180
|
+
accountID,
|
|
181
|
+
sessionID,
|
|
182
|
+
);
|
|
94
183
|
|
|
95
184
|
// Verify the session ID is stored in KvStore
|
|
96
185
|
const storedSession = await kvStore.get(accountID);
|
|
@@ -98,6 +187,9 @@ describe("ReactNativeSessionProvider", () => {
|
|
|
98
187
|
|
|
99
188
|
// Verify the stored value matches the provided session ID
|
|
100
189
|
expect(storedSession).toBe(sessionID);
|
|
190
|
+
|
|
191
|
+
// Clean up
|
|
192
|
+
sessionDone();
|
|
101
193
|
});
|
|
102
194
|
|
|
103
195
|
test("overwrites existing session", async () => {
|
|
@@ -113,12 +205,92 @@ describe("ReactNativeSessionProvider", () => {
|
|
|
113
205
|
expect(sessionBefore).toBe(initialSessionID);
|
|
114
206
|
|
|
115
207
|
// Persist a different session ID
|
|
116
|
-
await sessionProvider.persistSession(
|
|
208
|
+
const { sessionDone } = await sessionProvider.persistSession(
|
|
209
|
+
accountID,
|
|
210
|
+
newSessionID,
|
|
211
|
+
);
|
|
117
212
|
|
|
118
213
|
// Verify the new session ID replaces the old one
|
|
119
214
|
const sessionAfter = await kvStore.get(accountID);
|
|
120
215
|
expect(sessionAfter).toBe(newSessionID);
|
|
121
216
|
expect(sessionAfter).not.toBe(initialSessionID);
|
|
217
|
+
|
|
218
|
+
// Clean up
|
|
219
|
+
sessionDone();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("locks session when persisting", async () => {
|
|
223
|
+
const accountID = account.$jazz.id;
|
|
224
|
+
const sessionID = Crypto.newRandomSessionID(accountID as RawAccountID);
|
|
225
|
+
|
|
226
|
+
// Persist session - this should lock the session
|
|
227
|
+
const { sessionDone } = await sessionProvider.persistSession(
|
|
228
|
+
accountID,
|
|
229
|
+
sessionID,
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
// Try to acquire session while it's locked by persistSession
|
|
233
|
+
const result = await sessionProvider.acquireSession(
|
|
234
|
+
accountID,
|
|
235
|
+
Crypto as CryptoProvider,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
// Should get a different session since the persisted one is locked
|
|
239
|
+
expect(result.sessionID).not.toBe(sessionID);
|
|
240
|
+
|
|
241
|
+
// Clean up
|
|
242
|
+
sessionDone();
|
|
243
|
+
result.sessionDone();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("allows session reuse after sessionDone is called", async () => {
|
|
247
|
+
const accountID = account.$jazz.id;
|
|
248
|
+
const sessionID = Crypto.newRandomSessionID(accountID as RawAccountID);
|
|
249
|
+
|
|
250
|
+
// Persist session
|
|
251
|
+
const { sessionDone } = await sessionProvider.persistSession(
|
|
252
|
+
accountID,
|
|
253
|
+
sessionID,
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// Release the session
|
|
257
|
+
sessionDone();
|
|
258
|
+
|
|
259
|
+
// Acquire session - should reuse the persisted session
|
|
260
|
+
const result = await sessionProvider.acquireSession(
|
|
261
|
+
accountID,
|
|
262
|
+
Crypto as CryptoProvider,
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
expect(result.sessionID).toBe(sessionID);
|
|
266
|
+
|
|
267
|
+
// Clean up
|
|
268
|
+
result.sessionDone();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test("sessionDone can be called multiple times safely", async () => {
|
|
272
|
+
const accountID = account.$jazz.id;
|
|
273
|
+
const sessionID = Crypto.newRandomSessionID(accountID as RawAccountID);
|
|
274
|
+
|
|
275
|
+
const { sessionDone } = await sessionProvider.persistSession(
|
|
276
|
+
accountID,
|
|
277
|
+
sessionID,
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
// Call sessionDone multiple times - should not throw
|
|
281
|
+
sessionDone();
|
|
282
|
+
sessionDone();
|
|
283
|
+
sessionDone();
|
|
284
|
+
|
|
285
|
+
// Should still be able to acquire the session
|
|
286
|
+
const result = await sessionProvider.acquireSession(
|
|
287
|
+
accountID,
|
|
288
|
+
Crypto as CryptoProvider,
|
|
289
|
+
);
|
|
290
|
+
expect(result.sessionID).toBe(sessionID);
|
|
291
|
+
|
|
292
|
+
// Clean up
|
|
293
|
+
result.sessionDone();
|
|
122
294
|
});
|
|
123
295
|
});
|
|
124
296
|
});
|
|
@@ -112,6 +112,30 @@ export abstract class CoValueJazzApi<V extends CoValue> {
|
|
|
112
112
|
return this.raw.core.earliestTxMadeAt;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Returns the account ID of the user who created this CoValue.
|
|
117
|
+
*
|
|
118
|
+
* Creation is determined by inspecting the earliest valid transaction,
|
|
119
|
+
* Note: Where the author is a sealer/signer identifiers (e.g. accounts)
|
|
120
|
+
* nothing is returned intentionally
|
|
121
|
+
*
|
|
122
|
+
* @returns {string | undefined} The creating user's account ID, or
|
|
123
|
+
* `undefined` if no author can be determined
|
|
124
|
+
*
|
|
125
|
+
* @category Content
|
|
126
|
+
*/
|
|
127
|
+
get createdBy(): string | undefined {
|
|
128
|
+
const createdBy = this.raw.core.getValidSortedTransactions({
|
|
129
|
+
ignorePrivateTransactions: false,
|
|
130
|
+
})[0]?.author;
|
|
131
|
+
|
|
132
|
+
// Only return accounts, not sealer/signer strings
|
|
133
|
+
if (typeof createdBy === "string" && createdBy.startsWith("co_z"))
|
|
134
|
+
return createdBy;
|
|
135
|
+
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
115
139
|
/**
|
|
116
140
|
* The timestamp of the last updated time of the CoValue
|
|
117
141
|
*
|
|
@@ -274,8 +274,8 @@ export async function createJazzContext<
|
|
|
274
274
|
crypto,
|
|
275
275
|
AccountSchema: options.AccountSchema,
|
|
276
276
|
sessionProvider: options.sessionProvider,
|
|
277
|
-
onLogOut: () => {
|
|
278
|
-
authSecretStorage.clearWithoutNotify();
|
|
277
|
+
onLogOut: async () => {
|
|
278
|
+
await authSecretStorage.clearWithoutNotify();
|
|
279
279
|
},
|
|
280
280
|
storage: options.storage,
|
|
281
281
|
asActiveAccount: true,
|