jazz-tools 0.9.23 → 0.10.1
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 +10 -12
- package/CHANGELOG.md +27 -0
- package/dist/{chunk-OJIEP4WE.js → chunk-24EJ3CKA.js} +566 -118
- package/dist/chunk-24EJ3CKA.js.map +1 -0
- package/dist/{index.web.js → index.js} +20 -9
- package/dist/index.js.map +1 -0
- package/dist/testing.js +125 -34
- package/dist/testing.js.map +1 -1
- package/package.json +11 -15
- package/src/auth/AuthSecretStorage.ts +109 -0
- package/src/auth/DemoAuth.ts +188 -0
- package/src/auth/InMemoryKVStore.ts +25 -0
- package/src/auth/KvStoreContext.ts +39 -0
- package/src/auth/PassphraseAuth.ts +113 -0
- package/src/coValues/account.ts +8 -3
- package/src/coValues/coFeed.ts +1 -1
- package/src/coValues/coList.ts +1 -1
- package/src/coValues/coMap.ts +1 -1
- package/src/coValues/group.ts +9 -8
- package/src/coValues/interfaces.ts +14 -5
- package/src/exports.ts +17 -3
- package/src/implementation/ContextManager.ts +178 -0
- package/src/implementation/activeAccountContext.ts +6 -1
- package/src/implementation/createContext.ts +173 -149
- package/src/implementation/schema.ts +3 -3
- package/src/index.ts +3 -0
- package/src/testing.ts +172 -34
- package/src/tests/AuthSecretStorage.test.ts +275 -0
- package/src/tests/ContextManager.test.ts +256 -0
- package/src/tests/DemoAuth.test.ts +269 -0
- package/src/tests/PassphraseAuth.test.ts +152 -0
- package/src/tests/coFeed.test.ts +48 -42
- package/src/tests/coList.test.ts +26 -24
- package/src/tests/coMap.test.ts +25 -23
- package/src/tests/coPlainText.test.ts +25 -23
- package/src/tests/coRichText.test.ts +24 -23
- package/src/tests/createContext.test.ts +339 -0
- package/src/tests/deepLoading.test.ts +44 -45
- package/src/tests/fixtures.ts +2050 -0
- package/src/tests/groupsAndAccounts.test.ts +3 -3
- package/src/tests/schema.test.ts +1 -1
- package/src/tests/schemaUnion.test.ts +2 -2
- package/src/tests/subscribe.test.ts +43 -10
- package/src/tests/testing.test.ts +56 -0
- package/src/tests/utils.ts +13 -13
- package/src/types.ts +54 -0
- package/tsconfig.json +3 -1
- package/tsup.config.ts +1 -2
- package/dist/chunk-OJIEP4WE.js.map +0 -1
- package/dist/index.native.js +0 -75
- package/dist/index.native.js.map +0 -1
- package/dist/index.web.js.map +0 -1
- package/src/index.native.ts +0 -6
- package/src/index.web.ts +0 -3
- package/tsconfig.native.json +0 -5
- package/tsconfig.web.json +0 -5
@@ -0,0 +1,188 @@
|
|
1
|
+
import { AgentSecret } from "cojson";
|
2
|
+
import { Account } from "../coValues/account.js";
|
3
|
+
import { ID } from "../internal.js";
|
4
|
+
import { AuthenticateAccountFunction } from "../types.js";
|
5
|
+
import { AuthSecretStorage } from "./AuthSecretStorage.js";
|
6
|
+
import { KvStore, KvStoreContext } from "./KvStoreContext.js";
|
7
|
+
|
8
|
+
type StorageData = {
|
9
|
+
accountID: ID<Account>;
|
10
|
+
accountSecret: AgentSecret;
|
11
|
+
secretSeed?: number[];
|
12
|
+
};
|
13
|
+
|
14
|
+
/**
|
15
|
+
* `DemoAuth` provides a `JazzAuth` object for demo authentication.
|
16
|
+
*
|
17
|
+
* Demo authentication is useful for quickly testing your app, as it allows you to create new accounts and log in as existing ones.
|
18
|
+
*
|
19
|
+
* ```
|
20
|
+
* import { DemoAuth } from "jazz-tools";
|
21
|
+
*
|
22
|
+
* const auth = new DemoAuth(jazzContext.authenticate, new AuthSecretStorage());
|
23
|
+
* ```
|
24
|
+
*
|
25
|
+
* @category Auth Providers
|
26
|
+
*/
|
27
|
+
export class DemoAuth {
|
28
|
+
constructor(
|
29
|
+
private authenticate: AuthenticateAccountFunction,
|
30
|
+
private authSecretStorage: AuthSecretStorage,
|
31
|
+
) {}
|
32
|
+
|
33
|
+
logIn = async (username: string) => {
|
34
|
+
const existingUsers = await this.getExisitingUsersWithData();
|
35
|
+
const storageData = existingUsers[username];
|
36
|
+
|
37
|
+
if (!storageData?.accountID) {
|
38
|
+
throw new Error("User not found");
|
39
|
+
}
|
40
|
+
|
41
|
+
await this.authenticate({
|
42
|
+
accountID: storageData.accountID,
|
43
|
+
accountSecret: storageData.accountSecret,
|
44
|
+
});
|
45
|
+
|
46
|
+
await this.authSecretStorage.set({
|
47
|
+
accountID: storageData.accountID,
|
48
|
+
accountSecret: storageData.accountSecret,
|
49
|
+
secretSeed: storageData.secretSeed
|
50
|
+
? new Uint8Array(storageData.secretSeed)
|
51
|
+
: undefined,
|
52
|
+
provider: "demo",
|
53
|
+
});
|
54
|
+
};
|
55
|
+
|
56
|
+
signUp = async (username: string) => {
|
57
|
+
const existingUsers = await this.getExistingUsers();
|
58
|
+
if (existingUsers.includes(username)) {
|
59
|
+
throw new Error("User already registered");
|
60
|
+
}
|
61
|
+
|
62
|
+
const credentials = await this.authSecretStorage.get();
|
63
|
+
|
64
|
+
if (!credentials) {
|
65
|
+
throw new Error("No credentials found");
|
66
|
+
}
|
67
|
+
|
68
|
+
const currentAccount = await Account.getMe().ensureLoaded({
|
69
|
+
profile: {},
|
70
|
+
});
|
71
|
+
|
72
|
+
currentAccount.profile.name = username;
|
73
|
+
|
74
|
+
await this.authSecretStorage.set({
|
75
|
+
accountID: credentials.accountID,
|
76
|
+
accountSecret: credentials.accountSecret,
|
77
|
+
secretSeed: credentials.secretSeed
|
78
|
+
? new Uint8Array(credentials.secretSeed)
|
79
|
+
: undefined,
|
80
|
+
provider: "demo",
|
81
|
+
});
|
82
|
+
|
83
|
+
await this.addToExistingUsers(username, {
|
84
|
+
accountID: credentials.accountID,
|
85
|
+
accountSecret: credentials.accountSecret,
|
86
|
+
secretSeed: credentials.secretSeed
|
87
|
+
? Array.from(credentials.secretSeed)
|
88
|
+
: undefined,
|
89
|
+
});
|
90
|
+
};
|
91
|
+
|
92
|
+
private async addToExistingUsers(username: string, data: StorageData) {
|
93
|
+
const existingUsers = await this.getExisitingUsersWithData();
|
94
|
+
|
95
|
+
if (existingUsers[username]) {
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
|
99
|
+
existingUsers[username] = data;
|
100
|
+
|
101
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
102
|
+
await kvStore.set("demo-auth-users", JSON.stringify(existingUsers));
|
103
|
+
}
|
104
|
+
|
105
|
+
private async getExisitingUsersWithData() {
|
106
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
107
|
+
await migrateExistingUsers(kvStore);
|
108
|
+
|
109
|
+
const existingUsers = await kvStore.get("demo-auth-users");
|
110
|
+
return existingUsers ? JSON.parse(existingUsers) : {};
|
111
|
+
}
|
112
|
+
|
113
|
+
getExistingUsers = async () => {
|
114
|
+
return Object.keys(await this.getExisitingUsersWithData());
|
115
|
+
};
|
116
|
+
}
|
117
|
+
|
118
|
+
export function encodeUsername(username: string) {
|
119
|
+
return btoa(username)
|
120
|
+
.replace(/=/g, "-")
|
121
|
+
.replace(/\+/g, "_")
|
122
|
+
.replace(/\//g, ".");
|
123
|
+
}
|
124
|
+
|
125
|
+
async function getStorageVersion(kvStore: KvStore) {
|
126
|
+
try {
|
127
|
+
const version = await kvStore.get("demo-auth-storage-version");
|
128
|
+
return version ? parseInt(version) : 1;
|
129
|
+
} catch (error) {
|
130
|
+
return 1;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
async function setStorageVersion(kvStore: KvStore, version: number) {
|
135
|
+
await kvStore.set("demo-auth-storage-version", version.toString());
|
136
|
+
}
|
137
|
+
|
138
|
+
async function getExistingUsersList(kvStore: KvStore) {
|
139
|
+
const existingUsers = await kvStore.get("demo-auth-existing-users");
|
140
|
+
return existingUsers ? existingUsers.split(",") : [];
|
141
|
+
}
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Migrates existing users keys to work with any storage.
|
145
|
+
*/
|
146
|
+
async function migrateExistingUsers(kvStore: KvStore) {
|
147
|
+
if ((await getStorageVersion(kvStore)) < 2) {
|
148
|
+
const existingUsers = await getExistingUsersList(kvStore);
|
149
|
+
|
150
|
+
for (const username of existingUsers) {
|
151
|
+
const legacyKey = `demo-auth-existing-users-${username}`;
|
152
|
+
const storageData = await kvStore.get(legacyKey);
|
153
|
+
if (storageData) {
|
154
|
+
await kvStore.set(
|
155
|
+
`demo-auth-existing-users-${encodeUsername(username)}`,
|
156
|
+
storageData,
|
157
|
+
);
|
158
|
+
await kvStore.delete(legacyKey);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
await setStorageVersion(kvStore, 2);
|
163
|
+
}
|
164
|
+
|
165
|
+
if ((await getStorageVersion(kvStore)) < 3) {
|
166
|
+
const existingUsersList = await getExistingUsersList(kvStore);
|
167
|
+
|
168
|
+
const existingUsers: Record<string, StorageData> = {};
|
169
|
+
const keysToDelete: string[] = ["demo-auth-existing-users"];
|
170
|
+
|
171
|
+
for (const username of existingUsersList) {
|
172
|
+
const key = `demo-auth-existing-users-${encodeUsername(username)}`;
|
173
|
+
const storageData = await kvStore.get(key);
|
174
|
+
if (storageData) {
|
175
|
+
existingUsers[username] = JSON.parse(storageData);
|
176
|
+
keysToDelete.push(key);
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
await kvStore.set("demo-auth-users", JSON.stringify(existingUsers));
|
181
|
+
|
182
|
+
for (const key of keysToDelete) {
|
183
|
+
await kvStore.delete(key);
|
184
|
+
}
|
185
|
+
|
186
|
+
await setStorageVersion(kvStore, 3);
|
187
|
+
}
|
188
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { KvStore } from "./KvStoreContext.js";
|
2
|
+
|
3
|
+
export class InMemoryKVStore implements KvStore {
|
4
|
+
private store: Record<string, string> = {};
|
5
|
+
|
6
|
+
async get(key: string) {
|
7
|
+
const data = this.store[key];
|
8
|
+
|
9
|
+
if (!data) return null;
|
10
|
+
|
11
|
+
return data;
|
12
|
+
}
|
13
|
+
|
14
|
+
async set(key: string, value: string) {
|
15
|
+
this.store[key] = value;
|
16
|
+
}
|
17
|
+
|
18
|
+
async delete(key: string) {
|
19
|
+
delete this.store[key];
|
20
|
+
}
|
21
|
+
|
22
|
+
async clearAll() {
|
23
|
+
this.store = {};
|
24
|
+
}
|
25
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
export interface KvStore {
|
2
|
+
get(key: string): Promise<string | null>;
|
3
|
+
set(key: string, value: string): Promise<void>;
|
4
|
+
delete(key: string): Promise<void>;
|
5
|
+
clearAll(): Promise<void>;
|
6
|
+
}
|
7
|
+
|
8
|
+
export class KvStoreContext {
|
9
|
+
private static instance: KvStoreContext;
|
10
|
+
private storageInstance: KvStore | null = null;
|
11
|
+
|
12
|
+
private constructor() {}
|
13
|
+
|
14
|
+
public static getInstance(): KvStoreContext {
|
15
|
+
if (!KvStoreContext.instance) {
|
16
|
+
KvStoreContext.instance = new KvStoreContext();
|
17
|
+
}
|
18
|
+
return KvStoreContext.instance;
|
19
|
+
}
|
20
|
+
|
21
|
+
public isInitialized(): boolean {
|
22
|
+
return this.storageInstance !== null;
|
23
|
+
}
|
24
|
+
|
25
|
+
public initialize(store: KvStore): void {
|
26
|
+
if (!this.storageInstance) {
|
27
|
+
this.storageInstance = store;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
public getStorage(): KvStore {
|
32
|
+
if (!this.storageInstance) {
|
33
|
+
throw new Error("Storage instance is not initialized.");
|
34
|
+
}
|
35
|
+
return this.storageInstance;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
export default KvStoreContext;
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import * as bip39 from "@scure/bip39";
|
2
|
+
import { entropyToMnemonic } from "@scure/bip39";
|
3
|
+
import { CryptoProvider, cojsonInternals } from "cojson";
|
4
|
+
import { Account } from "../coValues/account.js";
|
5
|
+
import type { ID } from "../internal.js";
|
6
|
+
import type { AuthenticateAccountFunction } from "../types.js";
|
7
|
+
import { AuthSecretStorage } from "./AuthSecretStorage.js";
|
8
|
+
|
9
|
+
/**
|
10
|
+
* `PassphraseAuth` provides a `JazzAuth` object for passphrase authentication.
|
11
|
+
*
|
12
|
+
* ```ts
|
13
|
+
* import { PassphraseAuth } from "jazz-tools";
|
14
|
+
*
|
15
|
+
* const auth = new PassphraseAuth(crypto, jazzContext.authenticate, new AuthSecretStorage(), wordlist);
|
16
|
+
* ```
|
17
|
+
*
|
18
|
+
* @category Auth Providers
|
19
|
+
*/
|
20
|
+
export class PassphraseAuth {
|
21
|
+
passphrase: string = "";
|
22
|
+
|
23
|
+
constructor(
|
24
|
+
private crypto: CryptoProvider,
|
25
|
+
private authenticate: AuthenticateAccountFunction,
|
26
|
+
private authSecretStorage: AuthSecretStorage,
|
27
|
+
public wordlist: string[],
|
28
|
+
) {}
|
29
|
+
|
30
|
+
logIn = async (passphrase: string) => {
|
31
|
+
const { crypto, authenticate } = this;
|
32
|
+
|
33
|
+
let secretSeed;
|
34
|
+
|
35
|
+
try {
|
36
|
+
secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);
|
37
|
+
} catch (e) {
|
38
|
+
throw new Error("Invalid passphrase");
|
39
|
+
}
|
40
|
+
|
41
|
+
const accountSecret = crypto.agentSecretFromSecretSeed(secretSeed);
|
42
|
+
|
43
|
+
const accountID = cojsonInternals.idforHeader(
|
44
|
+
cojsonInternals.accountHeaderForInitialAgentSecret(accountSecret, crypto),
|
45
|
+
crypto,
|
46
|
+
) as ID<Account>;
|
47
|
+
|
48
|
+
await authenticate({
|
49
|
+
accountID,
|
50
|
+
accountSecret,
|
51
|
+
});
|
52
|
+
|
53
|
+
await this.authSecretStorage.set({
|
54
|
+
accountID,
|
55
|
+
secretSeed,
|
56
|
+
accountSecret,
|
57
|
+
provider: "passphrase",
|
58
|
+
});
|
59
|
+
|
60
|
+
this.passphrase = passphrase;
|
61
|
+
this.notify();
|
62
|
+
};
|
63
|
+
|
64
|
+
signUp = async () => {
|
65
|
+
const credentials = await this.authSecretStorage.get();
|
66
|
+
|
67
|
+
if (!credentials || !credentials.secretSeed) {
|
68
|
+
throw new Error("No credentials found");
|
69
|
+
}
|
70
|
+
|
71
|
+
const passphrase = entropyToMnemonic(credentials.secretSeed, this.wordlist);
|
72
|
+
|
73
|
+
await this.authSecretStorage.set({
|
74
|
+
accountID: credentials.accountID,
|
75
|
+
secretSeed: credentials.secretSeed,
|
76
|
+
accountSecret: credentials.accountSecret,
|
77
|
+
provider: "passphrase",
|
78
|
+
});
|
79
|
+
|
80
|
+
return passphrase;
|
81
|
+
};
|
82
|
+
|
83
|
+
getCurrentAccountPassphrase = async () => {
|
84
|
+
const credentials = await this.authSecretStorage.get();
|
85
|
+
|
86
|
+
if (!credentials || !credentials.secretSeed) {
|
87
|
+
throw new Error("No credentials found");
|
88
|
+
}
|
89
|
+
|
90
|
+
return entropyToMnemonic(credentials.secretSeed, this.wordlist);
|
91
|
+
};
|
92
|
+
|
93
|
+
loadCurrentAccountPassphrase = async () => {
|
94
|
+
const passphrase = await this.getCurrentAccountPassphrase();
|
95
|
+
this.passphrase = passphrase;
|
96
|
+
this.notify();
|
97
|
+
};
|
98
|
+
|
99
|
+
listeners = new Set<() => void>();
|
100
|
+
subscribe = (callback: () => void) => {
|
101
|
+
this.listeners.add(callback);
|
102
|
+
|
103
|
+
return () => {
|
104
|
+
this.listeners.delete(callback);
|
105
|
+
};
|
106
|
+
};
|
107
|
+
|
108
|
+
notify() {
|
109
|
+
for (const listener of this.listeners) {
|
110
|
+
listener();
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
package/src/coValues/account.ts
CHANGED
@@ -42,6 +42,11 @@ import { createInboxRoot } from "./inbox.js";
|
|
42
42
|
import { Profile } from "./profile.js";
|
43
43
|
import { RegisteredSchemas } from "./registeredSchemas.js";
|
44
44
|
|
45
|
+
export type AccountCreationProps = {
|
46
|
+
name: string;
|
47
|
+
onboarding?: boolean;
|
48
|
+
};
|
49
|
+
|
45
50
|
/** @category Identity & Permissions */
|
46
51
|
export class Account extends CoValueBase implements CoValue {
|
47
52
|
declare id: ID<this>;
|
@@ -253,7 +258,7 @@ export class Account extends CoValueBase implements CoValue {
|
|
253
258
|
return this.toJSON();
|
254
259
|
}
|
255
260
|
|
256
|
-
async applyMigration(creationProps?:
|
261
|
+
async applyMigration(creationProps?: AccountCreationProps) {
|
257
262
|
if (creationProps) {
|
258
263
|
const profileGroup = RegisteredSchemas["Group"].create({ owner: this });
|
259
264
|
profileGroup.addMember("everyone", "reader");
|
@@ -278,7 +283,7 @@ export class Account extends CoValueBase implements CoValue {
|
|
278
283
|
}
|
279
284
|
|
280
285
|
// Placeholder method for subclasses to override
|
281
|
-
migrate(creationProps?:
|
286
|
+
migrate(creationProps?: AccountCreationProps) {
|
282
287
|
creationProps; // To avoid unused parameter warning
|
283
288
|
}
|
284
289
|
|
@@ -339,7 +344,7 @@ export class Account extends CoValueBase implements CoValue {
|
|
339
344
|
ensureLoaded<A extends Account, Depth>(
|
340
345
|
this: A,
|
341
346
|
depth: Depth & DepthsIn<A>,
|
342
|
-
): Promise<DeeplyLoaded<A, Depth
|
347
|
+
): Promise<DeeplyLoaded<A, Depth>> {
|
343
348
|
return ensureCoValueLoaded(this, depth);
|
344
349
|
}
|
345
350
|
|
package/src/coValues/coFeed.ts
CHANGED
@@ -391,7 +391,7 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
391
391
|
ensureLoaded<S extends CoFeed, Depth>(
|
392
392
|
this: S,
|
393
393
|
depth: Depth & DepthsIn<S>,
|
394
|
-
): Promise<DeeplyLoaded<S, Depth
|
394
|
+
): Promise<DeeplyLoaded<S, Depth>> {
|
395
395
|
return ensureCoValueLoaded(this, depth);
|
396
396
|
}
|
397
397
|
|
package/src/coValues/coList.ts
CHANGED
@@ -449,7 +449,7 @@ export class CoList<Item = any> extends Array<Item> implements CoValue {
|
|
449
449
|
ensureLoaded<L extends CoList, Depth>(
|
450
450
|
this: L,
|
451
451
|
depth: Depth & DepthsIn<L>,
|
452
|
-
): Promise<DeeplyLoaded<L, Depth
|
452
|
+
): Promise<DeeplyLoaded<L, Depth>> {
|
453
453
|
return ensureCoValueLoaded(this, depth);
|
454
454
|
}
|
455
455
|
|
package/src/coValues/coMap.ts
CHANGED
@@ -542,7 +542,7 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
542
542
|
ensureLoaded<M extends CoMap, Depth>(
|
543
543
|
this: M,
|
544
544
|
depth: Depth & DepthsIn<M>,
|
545
|
-
): Promise<DeeplyLoaded<M, Depth
|
545
|
+
): Promise<DeeplyLoaded<M, Depth>> {
|
546
546
|
return ensureCoValueLoaded(this, depth);
|
547
547
|
}
|
548
548
|
|
package/src/coValues/group.ts
CHANGED
@@ -139,16 +139,14 @@ export class Group extends CoValueBase implements CoValue {
|
|
139
139
|
return this._raw.myRole();
|
140
140
|
}
|
141
141
|
|
142
|
-
addMember(member: Everyone, role: "writer" | "reader"):
|
143
|
-
addMember(member: Account, role: AccountRole):
|
142
|
+
addMember(member: Everyone, role: "writer" | "reader"): void;
|
143
|
+
addMember(member: Account, role: AccountRole): void;
|
144
144
|
addMember(member: Everyone | Account, role: AccountRole) {
|
145
145
|
this._raw.addMember(member === "everyone" ? member : member._raw, role);
|
146
|
-
return this;
|
147
146
|
}
|
148
147
|
|
149
148
|
removeMember(member: Everyone | Account) {
|
150
|
-
this._raw.removeMember(member === "everyone" ? member : member._raw);
|
151
|
-
return this;
|
149
|
+
return this._raw.removeMember(member === "everyone" ? member : member._raw);
|
152
150
|
}
|
153
151
|
|
154
152
|
get members() {
|
@@ -181,8 +179,11 @@ export class Group extends CoValueBase implements CoValue {
|
|
181
179
|
});
|
182
180
|
}
|
183
181
|
|
184
|
-
extend(
|
185
|
-
|
182
|
+
extend(
|
183
|
+
parent: Group,
|
184
|
+
roleMapping?: "reader" | "writer" | "admin" | "inherit",
|
185
|
+
) {
|
186
|
+
this._raw.extend(parent._raw, roleMapping);
|
186
187
|
return this;
|
187
188
|
}
|
188
189
|
|
@@ -243,7 +244,7 @@ export class Group extends CoValueBase implements CoValue {
|
|
243
244
|
ensureLoaded<G extends Group, Depth>(
|
244
245
|
this: G,
|
245
246
|
depth: Depth & DepthsIn<G>,
|
246
|
-
): Promise<DeeplyLoaded<G, Depth
|
247
|
+
): Promise<DeeplyLoaded<G, Depth>> {
|
247
248
|
return ensureCoValueLoaded(this, depth);
|
248
249
|
}
|
249
250
|
|
@@ -196,16 +196,22 @@ export function loadCoValue<V extends CoValue, Depth>(
|
|
196
196
|
});
|
197
197
|
}
|
198
198
|
|
199
|
-
export function ensureCoValueLoaded<V extends CoValue, Depth>(
|
199
|
+
export async function ensureCoValueLoaded<V extends CoValue, Depth>(
|
200
200
|
existing: V,
|
201
201
|
depth: Depth & DepthsIn<V>,
|
202
|
-
): Promise<DeeplyLoaded<V, Depth
|
203
|
-
|
202
|
+
): Promise<DeeplyLoaded<V, Depth>> {
|
203
|
+
const response = await loadCoValue(
|
204
204
|
existing.constructor as CoValueClass<V>,
|
205
205
|
existing.id,
|
206
206
|
existing._loadedAs,
|
207
207
|
depth,
|
208
208
|
);
|
209
|
+
|
210
|
+
if (!response) {
|
211
|
+
throw new Error("Failed to deeply load CoValue " + existing.id);
|
212
|
+
}
|
213
|
+
|
214
|
+
return response;
|
209
215
|
}
|
210
216
|
|
211
217
|
export function subscribeToCoValueWithoutMe<V extends CoValue, Depth>(
|
@@ -301,7 +307,7 @@ export function subscribeToCoValue<V extends CoValue, Depth>(
|
|
301
307
|
export function createCoValueObservable<V extends CoValue, Depth>(options?: {
|
302
308
|
syncResolution?: boolean;
|
303
309
|
}) {
|
304
|
-
let currentValue: DeeplyLoaded<V, Depth> | undefined = undefined;
|
310
|
+
let currentValue: DeeplyLoaded<V, Depth> | undefined | null = undefined;
|
305
311
|
let subscriberCount = 0;
|
306
312
|
|
307
313
|
function subscribe(
|
@@ -323,7 +329,10 @@ export function createCoValueObservable<V extends CoValue, Depth>(options?: {
|
|
323
329
|
currentValue = value;
|
324
330
|
listener();
|
325
331
|
},
|
326
|
-
|
332
|
+
() => {
|
333
|
+
currentValue = null;
|
334
|
+
onUnavailable?.();
|
335
|
+
},
|
327
336
|
options?.syncResolution,
|
328
337
|
);
|
329
338
|
|
package/src/exports.ts
CHANGED
@@ -18,6 +18,7 @@ export {
|
|
18
18
|
Account,
|
19
19
|
isControlledAccount,
|
20
20
|
type AccountClass,
|
21
|
+
type AccountCreationProps,
|
21
22
|
} from "./coValues/account.js";
|
22
23
|
export {
|
23
24
|
BinaryCoStream,
|
@@ -49,6 +50,17 @@ export {
|
|
49
50
|
subscribeToCoValue,
|
50
51
|
} from "./internal.js";
|
51
52
|
|
53
|
+
export {
|
54
|
+
JazzContextManager,
|
55
|
+
type JazzContextManagerAuthProps,
|
56
|
+
} from "./implementation/ContextManager.js";
|
57
|
+
|
58
|
+
export { AuthSecretStorage } from "./auth/AuthSecretStorage.js";
|
59
|
+
export { KvStoreContext, type KvStore } from "./auth/KvStoreContext.js";
|
60
|
+
export { InMemoryKVStore } from "./auth/InMemoryKVStore.js";
|
61
|
+
export { DemoAuth } from "./auth/DemoAuth.js";
|
62
|
+
export { PassphraseAuth } from "./auth/PassphraseAuth.js";
|
63
|
+
|
52
64
|
export {
|
53
65
|
createInviteLink,
|
54
66
|
parseInviteLink,
|
@@ -58,11 +70,13 @@ export {
|
|
58
70
|
export {
|
59
71
|
AnonymousJazzAgent,
|
60
72
|
createAnonymousJazzContext,
|
73
|
+
createJazzContextFromExistingCredentials,
|
74
|
+
createJazzContextForNewAccount,
|
61
75
|
createJazzContext,
|
62
|
-
ephemeralCredentialsAuth,
|
63
|
-
fixedCredentialsAuth,
|
64
76
|
randomSessionProvider,
|
65
|
-
type AuthMethod,
|
66
77
|
type AuthResult,
|
67
78
|
type Credentials,
|
79
|
+
type JazzContextWithAccount,
|
68
80
|
} from "./internal.js";
|
81
|
+
|
82
|
+
export type * from "./types.js";
|