jazz-tools 0.10.14 → 0.11.0
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 +11 -7
- package/CHANGELOG.md +31 -0
- package/dist/auth/AuthSecretStorage.d.ts +25 -0
- package/dist/auth/AuthSecretStorage.d.ts.map +1 -0
- package/dist/auth/DemoAuth.d.ts +27 -0
- package/dist/auth/DemoAuth.d.ts.map +1 -0
- package/dist/auth/InMemoryKVStore.d.ts +9 -0
- package/dist/auth/InMemoryKVStore.d.ts.map +1 -0
- package/dist/auth/KvStoreContext.d.ts +17 -0
- package/dist/auth/KvStoreContext.d.ts.map +1 -0
- package/dist/auth/PassphraseAuth.d.ts +35 -0
- package/dist/auth/PassphraseAuth.d.ts.map +1 -0
- package/dist/{chunk-5YDDEUNX.js → chunk-RTRX7HIO.js} +193 -81
- package/dist/chunk-RTRX7HIO.js.map +1 -0
- package/dist/coValues/account.d.ts +120 -0
- package/dist/coValues/account.d.ts.map +1 -0
- package/dist/coValues/coFeed.d.ts +361 -0
- package/dist/coValues/coFeed.d.ts.map +1 -0
- package/dist/coValues/coList.d.ts +221 -0
- package/dist/coValues/coList.d.ts.map +1 -0
- package/dist/coValues/coMap.d.ts +500 -0
- package/dist/coValues/coMap.d.ts.map +1 -0
- package/dist/coValues/coPlainText.d.ts +69 -0
- package/dist/coValues/coPlainText.d.ts.map +1 -0
- package/dist/coValues/coRichText.d.ts +259 -0
- package/dist/coValues/coRichText.d.ts.map +1 -0
- package/dist/coValues/deepLoading.d.ts +81 -0
- package/dist/coValues/deepLoading.d.ts.map +1 -0
- package/dist/coValues/extensions/imageDef.d.ts +17 -0
- package/dist/coValues/extensions/imageDef.d.ts.map +1 -0
- package/dist/coValues/group.d.ts +67 -0
- package/dist/coValues/group.d.ts.map +1 -0
- package/dist/coValues/inbox.d.ts +52 -0
- package/dist/coValues/inbox.d.ts.map +1 -0
- package/dist/coValues/interfaces.d.ts +97 -0
- package/dist/coValues/interfaces.d.ts.map +1 -0
- package/dist/coValues/profile.d.ts +28 -0
- package/dist/coValues/profile.d.ts.map +1 -0
- package/dist/coValues/registeredSchemas.d.ts +12 -0
- package/dist/coValues/registeredSchemas.d.ts.map +1 -0
- package/dist/coValues/schemaUnion.d.ts +79 -0
- package/dist/coValues/schemaUnion.d.ts.map +1 -0
- package/dist/exports.d.ts +27 -0
- package/dist/exports.d.ts.map +1 -0
- package/dist/implementation/ContextManager.d.ts +65 -0
- package/dist/implementation/ContextManager.d.ts.map +1 -0
- package/dist/implementation/activeAccountContext.d.ts +12 -0
- package/dist/implementation/activeAccountContext.d.ts.map +1 -0
- package/dist/implementation/anonymousJazzAgent.d.ts +7 -0
- package/dist/implementation/anonymousJazzAgent.d.ts.map +1 -0
- package/dist/implementation/createContext.d.ts +91 -0
- package/dist/implementation/createContext.d.ts.map +1 -0
- package/dist/implementation/devtoolsFormatters.d.ts +2 -0
- package/dist/implementation/devtoolsFormatters.d.ts.map +1 -0
- package/dist/implementation/errors.d.ts +2 -0
- package/dist/implementation/errors.d.ts.map +1 -0
- package/dist/implementation/inspect.d.ts +3 -0
- package/dist/implementation/inspect.d.ts.map +1 -0
- package/dist/implementation/invites.d.ts +23 -0
- package/dist/implementation/invites.d.ts.map +1 -0
- package/dist/implementation/refs.d.ts +21 -0
- package/dist/implementation/refs.d.ts.map +1 -0
- package/dist/implementation/schema.d.ts +72 -0
- package/dist/implementation/schema.d.ts.map +1 -0
- package/dist/implementation/subscriptionScope.d.ts +33 -0
- package/dist/implementation/subscriptionScope.d.ts.map +1 -0
- package/dist/implementation/symbols.d.ts +8 -0
- package/dist/implementation/symbols.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +12 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/lib/cache.d.ts +6 -0
- package/dist/lib/cache.d.ts.map +1 -0
- package/dist/lib/cache.test.d.ts +2 -0
- package/dist/lib/cache.test.d.ts.map +1 -0
- package/dist/testing.d.ts +41 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +11 -16
- package/dist/testing.js.map +1 -1
- package/dist/tests/AuthSecretStorage.test.d.ts +2 -0
- package/dist/tests/AuthSecretStorage.test.d.ts.map +1 -0
- package/dist/tests/ContextManager.test.d.ts +2 -0
- package/dist/tests/ContextManager.test.d.ts.map +1 -0
- package/dist/tests/DemoAuth.test.d.ts +2 -0
- package/dist/tests/DemoAuth.test.d.ts.map +1 -0
- package/dist/tests/PassphraseAuth.test.d.ts +2 -0
- package/dist/tests/PassphraseAuth.test.d.ts.map +1 -0
- package/dist/tests/account.test.d.ts +2 -0
- package/dist/tests/account.test.d.ts.map +1 -0
- package/dist/tests/coFeed.test.d.ts +2 -0
- package/dist/tests/coFeed.test.d.ts.map +1 -0
- package/dist/tests/coList.test.d.ts +2 -0
- package/dist/tests/coList.test.d.ts.map +1 -0
- package/dist/tests/coMap.test.d.ts +2 -0
- package/dist/tests/coMap.test.d.ts.map +1 -0
- package/dist/tests/coPlainText.test.d.ts +2 -0
- package/dist/tests/coPlainText.test.d.ts.map +1 -0
- package/dist/tests/coRichText.test.d.ts +2 -0
- package/dist/tests/coRichText.test.d.ts.map +1 -0
- package/dist/tests/createContext.test.d.ts +2 -0
- package/dist/tests/createContext.test.d.ts.map +1 -0
- package/dist/tests/deepLoading.test.d.ts +2 -0
- package/dist/tests/deepLoading.test.d.ts.map +1 -0
- package/dist/tests/fixtures.d.ts +2 -0
- package/dist/tests/fixtures.d.ts.map +1 -0
- package/dist/tests/groupsAndAccounts.test.d.ts +2 -0
- package/dist/tests/groupsAndAccounts.test.d.ts.map +1 -0
- package/dist/tests/inbox.test.d.ts +2 -0
- package/dist/tests/inbox.test.d.ts.map +1 -0
- package/dist/tests/interfaces.test.d.ts +2 -0
- package/dist/tests/interfaces.test.d.ts.map +1 -0
- package/dist/tests/invites.test.d.ts +2 -0
- package/dist/tests/invites.test.d.ts.map +1 -0
- package/dist/tests/schema.test.d.ts +2 -0
- package/dist/tests/schema.test.d.ts.map +1 -0
- package/dist/tests/schemaUnion.test.d.ts +2 -0
- package/dist/tests/schemaUnion.test.d.ts.map +1 -0
- package/dist/tests/subscribe.test.d.ts +2 -0
- package/dist/tests/subscribe.test.d.ts.map +1 -0
- package/dist/tests/testing.test.d.ts +2 -0
- package/dist/tests/testing.test.d.ts.map +1 -0
- package/dist/tests/utils.d.ts +21 -0
- package/dist/tests/utils.d.ts.map +1 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +8 -7
- package/src/coValues/account.ts +69 -11
- package/src/coValues/coMap.ts +2 -2
- package/src/coValues/coRichText.ts +42 -17
- package/src/coValues/group.ts +76 -31
- package/src/coValues/inbox.ts +10 -0
- package/src/coValues/interfaces.ts +1 -1
- package/src/coValues/profile.ts +35 -2
- package/src/implementation/ContextManager.ts +63 -15
- package/src/implementation/schema.ts +1 -3
- package/src/testing.ts +10 -16
- package/src/tests/AuthSecretStorage.test.ts +1 -2
- package/src/tests/ContextManager.test.ts +27 -14
- package/src/tests/PassphraseAuth.test.ts +7 -3
- package/src/tests/coMap.test.ts +20 -21
- package/src/tests/deepLoading.test.ts +8 -17
- package/src/tests/groupsAndAccounts.test.ts +429 -89
- package/src/tests/inbox.test.ts +24 -0
- package/src/tests/schema.test.ts +45 -5
- package/src/tests/utils.ts +7 -3
- package/src/types.ts +6 -0
- package/tsconfig.json +4 -1
- package/dist/chunk-5YDDEUNX.js.map +0 -1
@@ -611,26 +611,51 @@ export function splitNode(
|
|
611
611
|
}
|
612
612
|
}
|
613
613
|
|
614
|
+
/**
|
615
|
+
* Heading mark for rich text formatting.
|
616
|
+
*/
|
617
|
+
export class Heading extends Mark {
|
618
|
+
tag = co.literal("heading");
|
619
|
+
level = co.number;
|
620
|
+
}
|
621
|
+
|
622
|
+
/**
|
623
|
+
* Paragraph mark for rich text formatting.
|
624
|
+
*/
|
625
|
+
export class Paragraph extends Mark {
|
626
|
+
tag = co.literal("paragraph");
|
627
|
+
}
|
628
|
+
|
629
|
+
/**
|
630
|
+
* Link mark for rich text formatting.
|
631
|
+
*/
|
632
|
+
export class Link extends Mark {
|
633
|
+
tag = co.literal("link");
|
634
|
+
url = co.string;
|
635
|
+
}
|
636
|
+
|
637
|
+
/**
|
638
|
+
* Strong (bold) mark for rich text formatting.
|
639
|
+
*/
|
640
|
+
export class Strong extends Mark {
|
641
|
+
tag = co.literal("strong");
|
642
|
+
}
|
643
|
+
|
644
|
+
/**
|
645
|
+
* Emphasis (italic) mark for rich text formatting.
|
646
|
+
*/
|
647
|
+
export class Em extends Mark {
|
648
|
+
tag = co.literal("em");
|
649
|
+
}
|
650
|
+
|
614
651
|
/**
|
615
652
|
* Collection of predefined mark types for common text formatting.
|
616
653
|
* Includes marks for headings, paragraphs, links, and text styling.
|
617
654
|
*/
|
618
655
|
export const Marks = {
|
619
|
-
Heading
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
tag = co.literal("paragraph");
|
625
|
-
},
|
626
|
-
Link: class Link extends Mark {
|
627
|
-
tag = co.literal("link");
|
628
|
-
url = co.string;
|
629
|
-
},
|
630
|
-
Strong: class Strong extends Mark {
|
631
|
-
tag = co.literal("strong");
|
632
|
-
},
|
633
|
-
Em: class Italic extends Mark {
|
634
|
-
tag = co.literal("em");
|
635
|
-
},
|
656
|
+
Heading,
|
657
|
+
Paragraph,
|
658
|
+
Link,
|
659
|
+
Strong,
|
660
|
+
Em,
|
636
661
|
};
|
package/src/coValues/group.ts
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
import type {
|
2
2
|
AccountRole,
|
3
|
+
AgentID,
|
3
4
|
Everyone,
|
4
5
|
RawAccountID,
|
5
6
|
RawGroup,
|
6
7
|
Role,
|
7
8
|
} from "cojson";
|
9
|
+
import { activeAccountContext } from "../implementation/activeAccountContext.js";
|
8
10
|
import type {
|
9
11
|
CoValue,
|
10
12
|
CoValueClass,
|
@@ -16,14 +18,15 @@ import type {
|
|
16
18
|
} from "../internal.js";
|
17
19
|
import {
|
18
20
|
CoValueBase,
|
19
|
-
MembersSym,
|
20
21
|
Ref,
|
22
|
+
co,
|
21
23
|
ensureCoValueLoaded,
|
22
24
|
loadCoValueWithoutMe,
|
23
25
|
parseGroupCreateOptions,
|
24
26
|
subscribeToCoValueWithoutMe,
|
25
27
|
subscribeToExistingCoValue,
|
26
28
|
} from "../internal.js";
|
29
|
+
import { RegisteredAccount } from "../types.js";
|
27
30
|
import { AccountAndGroupProxyHandler, isControlledAccount } from "./account.js";
|
28
31
|
import { type Account } from "./account.js";
|
29
32
|
import { type CoMap } from "./coMap.js";
|
@@ -44,7 +47,6 @@ export class Group extends CoValueBase implements CoValue {
|
|
44
47
|
get _schema(): {
|
45
48
|
profile: Schema;
|
46
49
|
root: Schema;
|
47
|
-
[MembersSym]: RefEncoded<Account>;
|
48
50
|
} {
|
49
51
|
return (this.constructor as typeof Group)._schema;
|
50
52
|
}
|
@@ -52,10 +54,6 @@ export class Group extends CoValueBase implements CoValue {
|
|
52
54
|
this._schema = {
|
53
55
|
profile: "json" satisfies Schema,
|
54
56
|
root: "json" satisfies Schema,
|
55
|
-
[MembersSym]: {
|
56
|
-
ref: () => RegisteredSchemas["Account"],
|
57
|
-
optional: false,
|
58
|
-
} satisfies RefEncoded<Account>,
|
59
57
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
60
58
|
} as any;
|
61
59
|
Object.defineProperty(this.prototype, "_schema", {
|
@@ -65,7 +63,6 @@ export class Group extends CoValueBase implements CoValue {
|
|
65
63
|
|
66
64
|
declare profile: Profile | null;
|
67
65
|
declare root: CoMap | null;
|
68
|
-
declare [MembersSym]: Account | null;
|
69
66
|
|
70
67
|
get _refs(): {
|
71
68
|
profile: Ref<Profile> | undefined;
|
@@ -149,34 +146,73 @@ export class Group extends CoValueBase implements CoValue {
|
|
149
146
|
return this._raw.removeMember(member === "everyone" ? member : member._raw);
|
150
147
|
}
|
151
148
|
|
152
|
-
get members() {
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
149
|
+
get members(): Array<{
|
150
|
+
id: ID<RegisteredAccount>;
|
151
|
+
role: AccountRole;
|
152
|
+
ref: Ref<RegisteredAccount>;
|
153
|
+
account: RegisteredAccount;
|
154
|
+
}> {
|
155
|
+
const members = [];
|
156
|
+
|
157
|
+
const BaseAccountSchema =
|
158
|
+
(activeAccountContext.maybeGet()?.constructor as typeof Account) ||
|
159
|
+
RegisteredSchemas["Account"];
|
160
|
+
const refEncodedAccountSchema = {
|
161
|
+
ref: () => BaseAccountSchema,
|
162
|
+
optional: false,
|
163
|
+
} satisfies RefEncoded<RegisteredAccount>;
|
164
|
+
|
165
|
+
for (const accountID of this._raw.getAllMemberKeysSet()) {
|
166
|
+
if (!isAccountID(accountID)) continue;
|
167
|
+
|
168
|
+
const role = this._raw.roleOf(accountID);
|
169
|
+
|
170
|
+
if (
|
171
|
+
role === "admin" ||
|
172
|
+
role === "writer" ||
|
173
|
+
role === "reader" ||
|
174
|
+
role === "writeOnly"
|
175
|
+
) {
|
176
|
+
const ref = new Ref<RegisteredAccount>(
|
177
|
+
accountID as unknown as ID<RegisteredAccount>,
|
178
|
+
this._loadedAs,
|
179
|
+
refEncodedAccountSchema,
|
180
|
+
);
|
181
|
+
const accessRef = () => ref.accessFrom(this, "members." + accountID);
|
182
|
+
|
183
|
+
if (!ref.syncLoad()) {
|
184
|
+
console.warn("Account not loaded", accountID);
|
185
|
+
}
|
186
|
+
|
187
|
+
members.push({
|
188
|
+
id: accountID as unknown as ID<Account>,
|
173
189
|
role,
|
174
190
|
ref,
|
175
191
|
get account() {
|
176
|
-
|
192
|
+
// Accounts values are non-nullable because are loaded as dependencies
|
193
|
+
return accessRef() as RegisteredAccount;
|
177
194
|
},
|
178
|
-
};
|
179
|
-
}
|
195
|
+
});
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
return members;
|
200
|
+
}
|
201
|
+
|
202
|
+
getRoleOf(member: Everyone | ID<Account> | "me") {
|
203
|
+
if (member === "me") {
|
204
|
+
return this._raw.roleOf(
|
205
|
+
activeAccountContext.get().id as unknown as RawAccountID,
|
206
|
+
);
|
207
|
+
}
|
208
|
+
|
209
|
+
return this._raw.roleOf(
|
210
|
+
member === "everyone" ? member : (member as unknown as RawAccountID),
|
211
|
+
);
|
212
|
+
}
|
213
|
+
|
214
|
+
getParentGroups(): Array<Group> {
|
215
|
+
return this._raw.getParentGroups().map(({ group }) => Group.fromRaw(group));
|
180
216
|
}
|
181
217
|
|
182
218
|
extend(
|
@@ -187,6 +223,11 @@ export class Group extends CoValueBase implements CoValue {
|
|
187
223
|
return this;
|
188
224
|
}
|
189
225
|
|
226
|
+
async revokeExtend(parent: Group) {
|
227
|
+
await this._raw.revokeExtend(parent._raw);
|
228
|
+
return this;
|
229
|
+
}
|
230
|
+
|
190
231
|
/** @category Subscription & Loading */
|
191
232
|
static load<C extends Group, Depth>(
|
192
233
|
this: CoValueClass<C>,
|
@@ -268,3 +309,7 @@ export class Group extends CoValueBase implements CoValue {
|
|
268
309
|
}
|
269
310
|
|
270
311
|
RegisteredSchemas["Group"] = Group;
|
312
|
+
|
313
|
+
export function isAccountID(id: RawAccountID | AgentID): id is RawAccountID {
|
314
|
+
return id.startsWith("co_");
|
315
|
+
}
|
package/src/coValues/inbox.ts
CHANGED
@@ -332,6 +332,16 @@ export class InboxSender<I extends CoValue, O extends CoValue | undefined> {
|
|
332
332
|
throw new Error("Failed to load the inbox owner profile");
|
333
333
|
}
|
334
334
|
|
335
|
+
if (
|
336
|
+
inboxOwnerProfileRaw.group.roleOf(currentAccount._raw.id) !== "reader" &&
|
337
|
+
inboxOwnerProfileRaw.group.roleOf(currentAccount._raw.id) !== "writer" &&
|
338
|
+
inboxOwnerProfileRaw.group.roleOf(currentAccount._raw.id) !== "admin"
|
339
|
+
) {
|
340
|
+
throw new Error(
|
341
|
+
"Insufficient permissions to access the inbox, make sure its user profile is publicly readable.",
|
342
|
+
);
|
343
|
+
}
|
344
|
+
|
335
345
|
const inboxInvite = inboxOwnerProfileRaw.get("inboxInvite");
|
336
346
|
|
337
347
|
if (!inboxInvite) {
|
@@ -160,7 +160,7 @@ export function loadCoValueWithoutMe<V extends CoValue, Depth>(
|
|
160
160
|
id: ID<CoValue>,
|
161
161
|
asOrDepth: Account | AnonymousJazzAgent | (Depth & DepthsIn<V>),
|
162
162
|
depth?: Depth & DepthsIn<V>,
|
163
|
-
) {
|
163
|
+
): Promise<DeeplyLoaded<V, Depth> | undefined> {
|
164
164
|
if (isAccountInstance(asOrDepth) || isAnonymousAgentInstance(asOrDepth)) {
|
165
165
|
if (!depth) {
|
166
166
|
throw new Error(
|
package/src/coValues/profile.ts
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
import { CoID } from "cojson";
|
2
|
-
import { co } from "../internal.js";
|
3
|
-
import {
|
2
|
+
import { CoValueClass, co } from "../internal.js";
|
3
|
+
import { Account } from "./account.js";
|
4
|
+
import { CoMap, CoMapInit, Simplify } from "./coMap.js";
|
5
|
+
import { Group } from "./group.js";
|
4
6
|
import { InboxInvite, InboxRoot } from "./inbox.js";
|
5
7
|
|
6
8
|
/** @category Identity & Permissions */
|
@@ -8,4 +10,35 @@ export class Profile extends CoMap {
|
|
8
10
|
name = co.string;
|
9
11
|
inbox = co.optional.json<CoID<InboxRoot>>();
|
10
12
|
inboxInvite = co.optional.json<InboxInvite>();
|
13
|
+
|
14
|
+
override get _owner(): Group {
|
15
|
+
return super._owner as Group;
|
16
|
+
}
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Creates a new profile with the given initial values and owner.
|
20
|
+
*
|
21
|
+
* The owner (a Group) determines access rights to the Profile.
|
22
|
+
*
|
23
|
+
* @category Creation
|
24
|
+
*/
|
25
|
+
static override create<M extends CoMap>(
|
26
|
+
this: CoValueClass<M>,
|
27
|
+
init: Simplify<CoMapInit<M>>,
|
28
|
+
options?:
|
29
|
+
| {
|
30
|
+
owner: Group;
|
31
|
+
}
|
32
|
+
| Group,
|
33
|
+
) {
|
34
|
+
const owner =
|
35
|
+
options !== undefined && "owner" in options ? options.owner : options;
|
36
|
+
|
37
|
+
// We add some guardrails to ensure that the owner of a profile is a group
|
38
|
+
if ((owner as Group | Account | undefined)?._type === "Account") {
|
39
|
+
throw new Error("Profiles should be owned by a group");
|
40
|
+
}
|
41
|
+
|
42
|
+
return super.create<M>(init, options);
|
43
|
+
}
|
11
44
|
}
|
@@ -43,7 +43,8 @@ export class JazzContextManager<
|
|
43
43
|
protected context: PlatformSpecificContext<Acc> | undefined;
|
44
44
|
protected props: P | undefined;
|
45
45
|
protected authSecretStorage = new AuthSecretStorage();
|
46
|
-
protected
|
46
|
+
protected keepContextOpen = false;
|
47
|
+
protected contextPromise: Promise<void> | undefined;
|
47
48
|
|
48
49
|
constructor() {
|
49
50
|
KvStoreContext.getInstance().initialize(this.getKvStore());
|
@@ -54,6 +55,33 @@ export class JazzContextManager<
|
|
54
55
|
}
|
55
56
|
|
56
57
|
async createContext(props: P, authProps?: JazzContextManagerAuthProps) {
|
58
|
+
// We need to store the props here to block the double effect execution
|
59
|
+
// on React. Otherwise when calling propsChanged this.props is undefined.
|
60
|
+
this.props = props;
|
61
|
+
|
62
|
+
// Avoid race condition between the previous context and the new one
|
63
|
+
const { promise, resolve } = createResolvablePromise<void>();
|
64
|
+
|
65
|
+
const prevPromise = this.contextPromise;
|
66
|
+
this.contextPromise = promise;
|
67
|
+
|
68
|
+
await prevPromise;
|
69
|
+
|
70
|
+
try {
|
71
|
+
const result = await this.getNewContext(props, authProps);
|
72
|
+
await this.updateContext(props, result, authProps);
|
73
|
+
|
74
|
+
resolve();
|
75
|
+
} catch (error) {
|
76
|
+
resolve();
|
77
|
+
throw error;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
async getNewContext(
|
82
|
+
props: P,
|
83
|
+
authProps?: JazzContextManagerAuthProps,
|
84
|
+
): Promise<PlatformSpecificContext<Acc>> {
|
57
85
|
props;
|
58
86
|
authProps;
|
59
87
|
throw new Error("Not implemented");
|
@@ -64,9 +92,9 @@ export class JazzContextManager<
|
|
64
92
|
context: PlatformSpecificContext<Acc>,
|
65
93
|
authProps?: JazzContextManagerAuthProps,
|
66
94
|
) {
|
67
|
-
// When
|
95
|
+
// When keepContextOpen we don't want to close the previous context
|
68
96
|
// because we might need to handle the onAnonymousAccountDiscarded callback
|
69
|
-
if (!this.
|
97
|
+
if (!this.keepContextOpen) {
|
70
98
|
this.context?.done();
|
71
99
|
}
|
72
100
|
|
@@ -120,6 +148,18 @@ export class JazzContextManager<
|
|
120
148
|
this.context.done();
|
121
149
|
};
|
122
150
|
|
151
|
+
shouldMigrateAnonymousAccount = async () => {
|
152
|
+
if (!this.props?.onAnonymousAccountDiscarded) {
|
153
|
+
return false;
|
154
|
+
}
|
155
|
+
|
156
|
+
const prevCredentials = await this.authSecretStorage.get();
|
157
|
+
const wasAnonymous =
|
158
|
+
this.authSecretStorage.getIsAuthenticated(prevCredentials) === false;
|
159
|
+
|
160
|
+
return wasAnonymous;
|
161
|
+
};
|
162
|
+
|
123
163
|
/**
|
124
164
|
* Authenticates the user with the given credentials
|
125
165
|
*/
|
@@ -129,16 +169,15 @@ export class JazzContextManager<
|
|
129
169
|
}
|
130
170
|
|
131
171
|
const prevContext = this.context;
|
132
|
-
const
|
133
|
-
|
134
|
-
this.authSecretStorage.getIsAuthenticated(prevCredentials) === false;
|
172
|
+
const migratingAnonymousAccount =
|
173
|
+
await this.shouldMigrateAnonymousAccount();
|
135
174
|
|
136
|
-
this.
|
175
|
+
this.keepContextOpen = migratingAnonymousAccount;
|
137
176
|
await this.createContext(this.props, { credentials }).finally(() => {
|
138
|
-
this.
|
177
|
+
this.keepContextOpen = false;
|
139
178
|
});
|
140
179
|
|
141
|
-
if (
|
180
|
+
if (migratingAnonymousAccount) {
|
142
181
|
await this.handleAnonymousAccountMigration(prevContext);
|
143
182
|
}
|
144
183
|
};
|
@@ -152,21 +191,20 @@ export class JazzContextManager<
|
|
152
191
|
}
|
153
192
|
|
154
193
|
const prevContext = this.context;
|
155
|
-
const
|
156
|
-
|
157
|
-
this.authSecretStorage.getIsAuthenticated(prevCredentials) === false;
|
194
|
+
const migratingAnonymousAccount =
|
195
|
+
await this.shouldMigrateAnonymousAccount();
|
158
196
|
|
159
|
-
this.
|
197
|
+
this.keepContextOpen = migratingAnonymousAccount;
|
160
198
|
await this.createContext(this.props, {
|
161
199
|
newAccountProps: {
|
162
200
|
secret: accountSecret,
|
163
201
|
creationProps,
|
164
202
|
},
|
165
203
|
}).finally(() => {
|
166
|
-
this.
|
204
|
+
this.keepContextOpen = false;
|
167
205
|
});
|
168
206
|
|
169
|
-
if (
|
207
|
+
if (migratingAnonymousAccount) {
|
170
208
|
await this.handleAnonymousAccountMigration(prevContext);
|
171
209
|
}
|
172
210
|
|
@@ -235,3 +273,13 @@ export class JazzContextManager<
|
|
235
273
|
}
|
236
274
|
}
|
237
275
|
}
|
276
|
+
|
277
|
+
function createResolvablePromise<T>() {
|
278
|
+
let resolve!: (value: T) => void;
|
279
|
+
|
280
|
+
const promise = new Promise<T>((res) => {
|
281
|
+
resolve = res;
|
282
|
+
});
|
283
|
+
|
284
|
+
return { promise, resolve };
|
285
|
+
}
|
@@ -6,7 +6,6 @@ import {
|
|
6
6
|
CoValueFromRaw,
|
7
7
|
ItemsSym,
|
8
8
|
JazzToolsSymbol,
|
9
|
-
MembersSym,
|
10
9
|
SchemaInit,
|
11
10
|
isCoValueClass,
|
12
11
|
} from "../internal.js";
|
@@ -29,7 +28,7 @@ export type CoMarker = { readonly __co: unique symbol };
|
|
29
28
|
export type co<T> = T | (T & CoMarker);
|
30
29
|
export type IfCo<C, R> = C extends infer _A | infer B
|
31
30
|
? B extends CoMarker
|
32
|
-
? R extends JazzToolsSymbol // Exclude symbol properties like co.items
|
31
|
+
? R extends JazzToolsSymbol // Exclude symbol properties like co.items from the refs/init types
|
33
32
|
? never
|
34
33
|
: R
|
35
34
|
: never
|
@@ -100,7 +99,6 @@ export const co = {
|
|
100
99
|
},
|
101
100
|
ref,
|
102
101
|
items: ItemsSym as ItemsSym,
|
103
|
-
members: MembersSym as MembersSym,
|
104
102
|
optional,
|
105
103
|
};
|
106
104
|
|
package/src/testing.ts
CHANGED
@@ -237,12 +237,10 @@ export class TestJazzContextManager<
|
|
237
237
|
return context;
|
238
238
|
}
|
239
239
|
|
240
|
-
async
|
240
|
+
async getNewContext(
|
241
241
|
props: TestJazzContextManagerProps<Acc>,
|
242
242
|
authProps?: JazzContextManagerAuthProps,
|
243
243
|
) {
|
244
|
-
this.props = props;
|
245
|
-
|
246
244
|
if (!syncServer.current) {
|
247
245
|
throw new Error(
|
248
246
|
"You need to setup a test sync server with setupJazzTestSync to use the Auth functions",
|
@@ -260,20 +258,16 @@ export class TestJazzContextManager<
|
|
260
258
|
AccountSchema: props.AccountSchema,
|
261
259
|
});
|
262
260
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
done: () => {
|
269
|
-
context.done();
|
270
|
-
},
|
271
|
-
logOut: () => {
|
272
|
-
return context.logOut();
|
273
|
-
},
|
261
|
+
return {
|
262
|
+
me: context.account,
|
263
|
+
node: context.node,
|
264
|
+
done: () => {
|
265
|
+
context.done();
|
274
266
|
},
|
275
|
-
|
276
|
-
|
267
|
+
logOut: () => {
|
268
|
+
return context.logOut();
|
269
|
+
},
|
270
|
+
};
|
277
271
|
}
|
278
272
|
}
|
279
273
|
|
@@ -1,11 +1,10 @@
|
|
1
1
|
// @vitest-environment happy-dom
|
2
2
|
|
3
|
-
import { Account } from "jazz-tools";
|
4
|
-
import { ID } from "jazz-tools";
|
5
3
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
6
4
|
import { AuthSecretStorage } from "../auth/AuthSecretStorage";
|
7
5
|
import { InMemoryKVStore } from "../auth/InMemoryKVStore.js";
|
8
6
|
import KvStoreContext from "../auth/KvStoreContext";
|
7
|
+
import { Account, ID } from "../exports";
|
9
8
|
|
10
9
|
const kvStore = new InMemoryKVStore();
|
11
10
|
KvStoreContext.getInstance().initialize(kvStore);
|
@@ -35,7 +35,7 @@ class TestJazzContextManager<Acc extends Account> extends JazzContextManager<
|
|
35
35
|
AccountSchema?: AccountClass<Acc>;
|
36
36
|
}
|
37
37
|
> {
|
38
|
-
async
|
38
|
+
async getNewContext(
|
39
39
|
props: JazzContextManagerBaseProps<Acc> & {
|
40
40
|
defaultProfileName?: string;
|
41
41
|
AccountSchema?: AccountClass<Acc>;
|
@@ -53,20 +53,16 @@ class TestJazzContextManager<Acc extends Account> extends JazzContextManager<
|
|
53
53
|
AccountSchema: props.AccountSchema,
|
54
54
|
});
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
done: () => {
|
62
|
-
context.done();
|
63
|
-
},
|
64
|
-
logOut: async () => {
|
65
|
-
await context.logOut();
|
66
|
-
},
|
56
|
+
return {
|
57
|
+
me: context.account,
|
58
|
+
node: context.node,
|
59
|
+
done: () => {
|
60
|
+
context.done();
|
67
61
|
},
|
68
|
-
|
69
|
-
|
62
|
+
logOut: async () => {
|
63
|
+
await context.logOut();
|
64
|
+
},
|
65
|
+
};
|
70
66
|
}
|
71
67
|
}
|
72
68
|
|
@@ -127,6 +123,23 @@ describe("ContextManager", () => {
|
|
127
123
|
expect(getCurrentValue().me.id).toBe(credentials.accountID);
|
128
124
|
});
|
129
125
|
|
126
|
+
test("handles race conditions on the context creation", async () => {
|
127
|
+
const account = await createJazzTestAccount();
|
128
|
+
|
129
|
+
manager.createContext({});
|
130
|
+
|
131
|
+
const credentials = {
|
132
|
+
accountID: account.id,
|
133
|
+
accountSecret: account._raw.core.node.account.agentSecret,
|
134
|
+
provider: "test",
|
135
|
+
};
|
136
|
+
|
137
|
+
// Authenticate without waiting for the previous context to be created
|
138
|
+
await manager.authenticate(credentials);
|
139
|
+
|
140
|
+
expect(getCurrentValue().me.id).toBe(credentials.accountID);
|
141
|
+
});
|
142
|
+
|
130
143
|
test("calls onLogOut callback when logging out", async () => {
|
131
144
|
const onLogOut = vi.fn();
|
132
145
|
await manager.createContext({ onLogOut });
|
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
import { AgentSecret } from "cojson";
|
4
4
|
import { PureJSCrypto } from "cojson/crypto/PureJSCrypto";
|
5
|
+
import { assert, beforeEach, describe, expect, it, vi } from "vitest";
|
6
|
+
import { PassphraseAuth } from "../auth/PassphraseAuth";
|
5
7
|
import {
|
6
8
|
Account,
|
7
9
|
AuthSecretStorage,
|
8
10
|
ID,
|
9
11
|
InMemoryKVStore,
|
10
12
|
KvStoreContext,
|
11
|
-
} from "
|
12
|
-
import { assert, beforeEach, describe, expect, it, vi } from "vitest";
|
13
|
-
import { PassphraseAuth } from "../auth/PassphraseAuth";
|
13
|
+
} from "../exports";
|
14
14
|
import {
|
15
15
|
TestJazzContextManager,
|
16
16
|
createJazzTestAccount,
|
@@ -302,6 +302,10 @@ describe("PassphraseAuth with TestJazzContextManager", () => {
|
|
302
302
|
// Verify account was created
|
303
303
|
expect(accountId).toBeDefined();
|
304
304
|
|
305
|
+
await contextManager
|
306
|
+
.getCurrentValue()
|
307
|
+
?.node.syncManager.waitForAllCoValuesSync();
|
308
|
+
|
305
309
|
// Verify we can log in with the passphrase
|
306
310
|
await contextManager.logOut();
|
307
311
|
await passphraseAuth.logIn(passphrase);
|
package/src/tests/coMap.test.ts
CHANGED
@@ -10,7 +10,7 @@ import {
|
|
10
10
|
createJazzContextFromExistingCredentials,
|
11
11
|
isControlledAccount,
|
12
12
|
} from "../index.js";
|
13
|
-
import { setupTwoNodes
|
13
|
+
import { setupTwoNodes } from "./utils.js";
|
14
14
|
|
15
15
|
const connectedPeers = cojsonInternals.connectedPeers;
|
16
16
|
|
@@ -119,6 +119,25 @@ describe("Simple CoMap operations", async () => {
|
|
119
119
|
).toThrow();
|
120
120
|
});
|
121
121
|
|
122
|
+
test("testing toJSON on a CoMap with a Date field", () => {
|
123
|
+
const map = TestMap.create(
|
124
|
+
{
|
125
|
+
color: "red",
|
126
|
+
_height: 10,
|
127
|
+
birthday: new Date(),
|
128
|
+
},
|
129
|
+
{ owner: me },
|
130
|
+
);
|
131
|
+
|
132
|
+
expect(map.toJSON()).toMatchObject({
|
133
|
+
color: "red",
|
134
|
+
_height: 10,
|
135
|
+
birthday: expect.any(String),
|
136
|
+
_type: "CoMap",
|
137
|
+
id: expect.any(String),
|
138
|
+
});
|
139
|
+
});
|
140
|
+
|
122
141
|
test("setting optional date as undefined should not throw", () => {
|
123
142
|
const map = TestMap.create(
|
124
143
|
{
|
@@ -336,26 +355,6 @@ describe("Simple CoMap operations", async () => {
|
|
336
355
|
expect(mapWithEnum.child?.value).toEqual(5);
|
337
356
|
expect(mapWithEnum.child?.id).toBeDefined();
|
338
357
|
});
|
339
|
-
|
340
|
-
class SuperClassMap extends CoMap {
|
341
|
-
name = co.string;
|
342
|
-
}
|
343
|
-
|
344
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
345
|
-
class SubClassMap extends SuperClassMap {
|
346
|
-
name = co.literal("specificString");
|
347
|
-
value = co.number;
|
348
|
-
extra = co.ref(TestMap);
|
349
|
-
}
|
350
|
-
|
351
|
-
class GenericMapWithLoose<out T extends string = string> extends CoMap {
|
352
|
-
name = co.json<T>();
|
353
|
-
}
|
354
|
-
|
355
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
356
|
-
const loose: GenericMapWithLoose<string> = {} as GenericMapWithLoose<
|
357
|
-
"a" | "b"
|
358
|
-
>;
|
359
358
|
});
|
360
359
|
|
361
360
|
describe("CoMap resolution", async () => {
|