jazz-tools 0.10.12 → 0.10.14

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/dist/index.js CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  parseInviteLink,
36
36
  randomSessionProvider,
37
37
  subscribeToCoValue
38
- } from "./chunk-RL7HVQ5Q.js";
38
+ } from "./chunk-5YDDEUNX.js";
39
39
 
40
40
  // src/index.ts
41
41
  import { MAX_RECOMMENDED_TX_SIZE, cojsonInternals } from "cojson";
package/dist/testing.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  createAnonymousJazzContext,
6
6
  createJazzContext,
7
7
  randomSessionProvider
8
- } from "./chunk-RL7HVQ5Q.js";
8
+ } from "./chunk-5YDDEUNX.js";
9
9
 
10
10
  // src/testing.ts
11
11
  import { LocalNode } from "cojson";
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "type": "module",
19
19
  "license": "MIT",
20
- "version": "0.10.12",
20
+ "version": "0.10.14",
21
21
  "dependencies": {
22
22
  "@scure/bip39": "^1.3.0",
23
23
  "cojson": "0.10.8"
@@ -16,7 +16,6 @@ export type AuthSetPayload = {
16
16
  export class AuthSecretStorage {
17
17
  private listeners: Set<(isAuthenticated: boolean) => void>;
18
18
  public isAuthenticated: boolean;
19
- notify = false;
20
19
 
21
20
  constructor() {
22
21
  this.listeners = new Set();
@@ -97,7 +96,7 @@ export class AuthSecretStorage {
97
96
  };
98
97
  }
99
98
 
100
- async set(payload: AuthSetPayload) {
99
+ async setWithoutNotify(payload: AuthSetPayload) {
101
100
  const kvStore = KvStoreContext.getInstance().getStorage();
102
101
  await kvStore.set(
103
102
  STORAGE_KEY,
@@ -110,10 +109,11 @@ export class AuthSecretStorage {
110
109
  provider: payload.provider,
111
110
  }),
112
111
  );
112
+ }
113
113
 
114
- if (this.notify) {
115
- this.emitUpdate(payload);
116
- }
114
+ async set(payload: AuthSetPayload) {
115
+ this.setWithoutNotify(payload);
116
+ this.emitUpdate(payload);
117
117
  }
118
118
 
119
119
  getIsAuthenticated(data: AuthCredentials | null): boolean {
@@ -139,12 +139,13 @@ export class AuthSecretStorage {
139
139
  }
140
140
  }
141
141
 
142
- async clear() {
142
+ async clearWithoutNotify() {
143
143
  const kvStore = KvStoreContext.getInstance().getStorage();
144
144
  await kvStore.delete(STORAGE_KEY);
145
+ }
145
146
 
146
- if (this.notify) {
147
- this.emitUpdate(null);
148
- }
147
+ async clear() {
148
+ await this.clearWithoutNotify();
149
+ this.emitUpdate(null);
149
150
  }
150
151
  }
@@ -3,7 +3,10 @@ import { entropyToMnemonic } from "@scure/bip39";
3
3
  import { CryptoProvider, cojsonInternals } from "cojson";
4
4
  import { Account } from "../coValues/account.js";
5
5
  import type { ID } from "../internal.js";
6
- import type { AuthenticateAccountFunction } from "../types.js";
6
+ import type {
7
+ AuthenticateAccountFunction,
8
+ RegisterAccountFunction,
9
+ } from "../types.js";
7
10
  import { AuthSecretStorage } from "./AuthSecretStorage.js";
8
11
 
9
12
  /**
@@ -23,6 +26,7 @@ export class PassphraseAuth {
23
26
  constructor(
24
27
  private crypto: CryptoProvider,
25
28
  private authenticate: AuthenticateAccountFunction,
29
+ private register: RegisterAccountFunction,
26
30
  private authSecretStorage: AuthSecretStorage,
27
31
  public wordlist: string[],
28
32
  ) {}
@@ -61,7 +65,7 @@ export class PassphraseAuth {
61
65
  this.notify();
62
66
  };
63
67
 
64
- signUp = async () => {
68
+ signUp = async (name?: string) => {
65
69
  const credentials = await this.authSecretStorage.get();
66
70
 
67
71
  if (!credentials || !credentials.secretSeed) {
@@ -77,9 +81,32 @@ export class PassphraseAuth {
77
81
  provider: "passphrase",
78
82
  });
79
83
 
84
+ if (name?.trim()) {
85
+ const currentAccount = await Account.getMe().ensureLoaded({
86
+ profile: {},
87
+ });
88
+
89
+ currentAccount.profile.name = name;
90
+ }
91
+
80
92
  return passphrase;
81
93
  };
82
94
 
95
+ registerNewAccount = async (passphrase: string, name: string) => {
96
+ const secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);
97
+ const accountSecret = this.crypto.agentSecretFromSecretSeed(secretSeed);
98
+ const accountID = await this.register(accountSecret, { name });
99
+
100
+ await this.authSecretStorage.set({
101
+ accountID,
102
+ secretSeed,
103
+ accountSecret,
104
+ provider: "passphrase",
105
+ });
106
+
107
+ return accountID;
108
+ };
109
+
83
110
  getCurrentAccountPassphrase = async () => {
84
111
  const credentials = await this.authSecretStorage.get();
85
112
 
@@ -90,6 +117,10 @@ export class PassphraseAuth {
90
117
  return entropyToMnemonic(credentials.secretSeed, this.wordlist);
91
118
  };
92
119
 
120
+ generateRandomPassphrase = () => {
121
+ return entropyToMnemonic(this.crypto.newRandomSecretSeed(), this.wordlist);
122
+ };
123
+
93
124
  loadCurrentAccountPassphrase = async () => {
94
125
  const passphrase = await this.getCurrentAccountPassphrase();
95
126
  this.passphrase = passphrase;
@@ -43,10 +43,6 @@ export class JazzContextManager<
43
43
  protected context: PlatformSpecificContext<Acc> | undefined;
44
44
  protected props: P | undefined;
45
45
  protected authSecretStorage = new AuthSecretStorage();
46
- protected authSecretStorageWithNotify = Object.assign(
47
- Object.create(this.authSecretStorage),
48
- { notify: true },
49
- );
50
46
  protected authenticating = false;
51
47
 
52
48
  constructor() {
@@ -80,6 +76,7 @@ export class JazzContextManager<
80
76
  ...context,
81
77
  node: context.node,
82
78
  authenticate: this.authenticate,
79
+ register: this.register,
83
80
  logOut: this.logOut,
84
81
  };
85
82
 
@@ -102,9 +99,7 @@ export class JazzContextManager<
102
99
  }
103
100
 
104
101
  getAuthSecretStorage() {
105
- // External updates of the auth secret storage are notified by default (e.g. when registering a new Auth provider)
106
- // We skip internal notify to ensure that the isAuthenticated changes are notified along with the context updates
107
- return this.authSecretStorageWithNotify;
102
+ return this.authSecretStorage;
108
103
  }
109
104
 
110
105
  logOut = async () => {
@@ -143,14 +138,59 @@ export class JazzContextManager<
143
138
  this.authenticating = false;
144
139
  });
145
140
 
141
+ if (wasAnonymous) {
142
+ await this.handleAnonymousAccountMigration(prevContext);
143
+ }
144
+ };
145
+
146
+ register = async (
147
+ accountSecret: AgentSecret,
148
+ creationProps: { name: string },
149
+ ) => {
150
+ if (!this.props) {
151
+ throw new Error("Props required");
152
+ }
153
+
154
+ const prevContext = this.context;
155
+ const prevCredentials = await this.authSecretStorage.get();
156
+ const wasAnonymous =
157
+ this.authSecretStorage.getIsAuthenticated(prevCredentials) === false;
158
+
159
+ this.authenticating = true;
160
+ await this.createContext(this.props, {
161
+ newAccountProps: {
162
+ secret: accountSecret,
163
+ creationProps,
164
+ },
165
+ }).finally(() => {
166
+ this.authenticating = false;
167
+ });
168
+
169
+ if (wasAnonymous) {
170
+ await this.handleAnonymousAccountMigration(prevContext);
171
+ }
172
+
173
+ if (this.context && "me" in this.context) {
174
+ return this.context.me.id;
175
+ }
176
+
177
+ throw new Error("The registration hasn't created a new account");
178
+ };
179
+
180
+ private async handleAnonymousAccountMigration(
181
+ prevContext: PlatformSpecificContext<Acc> | undefined,
182
+ ) {
183
+ if (!this.props) {
184
+ throw new Error("Props required");
185
+ }
186
+
146
187
  const currentContext = this.context;
147
188
 
148
189
  if (
149
190
  prevContext &&
150
191
  currentContext &&
151
192
  "me" in prevContext &&
152
- "me" in currentContext &&
153
- wasAnonymous
193
+ "me" in currentContext
154
194
  ) {
155
195
  // Using a direct connection to make coValue transfer almost synchronous
156
196
  const [prevAccountAsPeer, currentAccountAsPeer] =
@@ -178,7 +218,7 @@ export class JazzContextManager<
178
218
  }
179
219
 
180
220
  prevContext?.done();
181
- };
221
+ }
182
222
 
183
223
  listeners = new Set<() => void>();
184
224
  subscribe = (callback: () => void) => {
@@ -219,7 +219,7 @@ export async function createJazzContext<Acc extends Account>(options: {
219
219
  AccountSchema: options.AccountSchema,
220
220
  sessionProvider: options.sessionProvider,
221
221
  onLogOut: () => {
222
- authSecretStorage.clear();
222
+ authSecretStorage.clearWithoutNotify();
223
223
  },
224
224
  });
225
225
  } else {
@@ -240,12 +240,12 @@ export async function createJazzContext<Acc extends Account>(options: {
240
240
  crypto,
241
241
  AccountSchema: options.AccountSchema,
242
242
  onLogOut: async () => {
243
- await authSecretStorage.clear();
243
+ await authSecretStorage.clearWithoutNotify();
244
244
  },
245
245
  });
246
246
 
247
247
  if (!options.newAccountProps) {
248
- await authSecretStorage.set({
248
+ await authSecretStorage.setWithoutNotify({
249
249
  accountID: context.account.id,
250
250
  secretSeed,
251
251
  accountSecret: context.node.account.agentSecret,
@@ -257,11 +257,10 @@ describe("AuthSecretStorage", () => {
257
257
  });
258
258
  });
259
259
 
260
- describe("notify=true", () => {
260
+ describe("notify", () => {
261
261
  beforeEach(() => {
262
262
  kvStore.clearAll();
263
263
  authSecretStorage = new AuthSecretStorage();
264
- authSecretStorage.notify = true;
265
264
  });
266
265
 
267
266
  describe("set", () => {
@@ -337,7 +336,7 @@ describe("AuthSecretStorage", () => {
337
336
  });
338
337
  });
339
338
 
340
- describe("notify=false", () => {
339
+ describe("without notify", () => {
341
340
  beforeEach(() => {
342
341
  kvStore.clearAll();
343
342
  authSecretStorage = new AuthSecretStorage();
@@ -348,7 +347,7 @@ describe("AuthSecretStorage", () => {
348
347
  const handler = vi.fn();
349
348
  authSecretStorage.onUpdate(handler);
350
349
 
351
- await authSecretStorage.set({
350
+ await authSecretStorage.setWithoutNotify({
352
351
  accountID: "test123" as ID<Account>,
353
352
  accountSecret:
354
353
  "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
@@ -365,7 +364,7 @@ describe("AuthSecretStorage", () => {
365
364
  });
366
365
 
367
366
  it("should return false for anonymous credentials", async () => {
368
- await authSecretStorage.set({
367
+ await authSecretStorage.setWithoutNotify({
369
368
  accountID: "test123" as ID<Account>,
370
369
  accountSecret:
371
370
  "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
@@ -376,7 +375,7 @@ describe("AuthSecretStorage", () => {
376
375
  });
377
376
 
378
377
  it("should return true for non-anonymous credentials", async () => {
379
- await authSecretStorage.set({
378
+ await authSecretStorage.setWithoutNotify({
380
379
  accountID: "test123" as ID<Account>,
381
380
  accountSecret:
382
381
  "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
@@ -395,7 +394,7 @@ describe("AuthSecretStorage", () => {
395
394
  });
396
395
 
397
396
  it("should return true when the provider is missing", async () => {
398
- await authSecretStorage.set({
397
+ await authSecretStorage.setWithoutNotify({
399
398
  accountID: "test123" as ID<Account>,
400
399
  accountSecret:
401
400
  "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
@@ -414,7 +413,7 @@ describe("AuthSecretStorage", () => {
414
413
 
415
414
  describe("clear", () => {
416
415
  it("should not emit update event when clearing", async () => {
417
- await authSecretStorage.set({
416
+ await authSecretStorage.setWithoutNotify({
418
417
  accountID: "test123" as ID<Account>,
419
418
  accountSecret:
420
419
  "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
@@ -424,7 +423,7 @@ describe("AuthSecretStorage", () => {
424
423
  const handler = vi.fn();
425
424
  authSecretStorage.onUpdate(handler);
426
425
 
427
- await authSecretStorage.clear();
426
+ await authSecretStorage.clearWithoutNotify();
428
427
 
429
428
  expect(handler).not.toHaveBeenCalled();
430
429
  });
@@ -338,4 +338,53 @@ describe("ContextManager", () => {
338
338
 
339
339
  expect(me.root.transferredRoot?.value).toBe("Hello");
340
340
  });
341
+
342
+ test("handles registration of new account", async () => {
343
+ const onAnonymousAccountDiscarded = vi.fn();
344
+ await manager.createContext({ onAnonymousAccountDiscarded });
345
+
346
+ const secret = Crypto.newRandomAgentSecret();
347
+ const accountId = await manager.register(secret, { name: "Test User" });
348
+
349
+ expect(accountId).toBeDefined();
350
+ const context = getCurrentValue();
351
+ expect(context.me.profile?.name).toBe("Test User");
352
+ expect(context.me.id).toBe(accountId);
353
+ });
354
+
355
+ test("calls onAnonymousAccountDiscarded when registering from anonymous user", async () => {
356
+ const onAnonymousAccountDiscarded = vi.fn();
357
+ await manager.createContext({ onAnonymousAccountDiscarded });
358
+ const anonymousAccount = getCurrentValue().me;
359
+
360
+ const secret = Crypto.newRandomAgentSecret();
361
+ await manager.register(secret, { name: "Test User" });
362
+
363
+ expect(onAnonymousAccountDiscarded).toHaveBeenCalledWith(anonymousAccount);
364
+ });
365
+
366
+ test("does not call onAnonymousAccountDiscarded when registering from authenticated user", async () => {
367
+ const onAnonymousAccountDiscarded = vi.fn();
368
+ const account = await createJazzTestAccount();
369
+
370
+ await manager.getAuthSecretStorage().set({
371
+ accountID: account.id,
372
+ accountSecret: account._raw.core.node.account.agentSecret,
373
+ provider: "test",
374
+ });
375
+
376
+ await manager.createContext({ onAnonymousAccountDiscarded });
377
+
378
+ const secret = Crypto.newRandomAgentSecret();
379
+ await manager.register(secret, { name: "New User" });
380
+
381
+ expect(onAnonymousAccountDiscarded).not.toHaveBeenCalled();
382
+ });
383
+
384
+ test("throws error when registering without props", async () => {
385
+ const secret = Crypto.newRandomAgentSecret();
386
+ await expect(
387
+ manager.register(secret, { name: "Test User" }),
388
+ ).rejects.toThrow("Props required");
389
+ });
341
390
  });
@@ -1,7 +1,7 @@
1
1
  // @vitest-environment happy-dom
2
2
 
3
- import { mnemonicToEntropy } from "@scure/bip39";
4
3
  import { AgentSecret } from "cojson";
4
+ import { PureJSCrypto } from "cojson/crypto/PureJSCrypto";
5
5
  import {
6
6
  Account,
7
7
  AuthSecretStorage,
@@ -9,31 +9,41 @@ import {
9
9
  InMemoryKVStore,
10
10
  KvStoreContext,
11
11
  } from "jazz-tools";
12
- import { beforeEach, describe, expect, it, vi } from "vitest";
12
+ import { assert, beforeEach, describe, expect, it, vi } from "vitest";
13
13
  import { PassphraseAuth } from "../auth/PassphraseAuth";
14
- import { createJazzTestAccount } from "../testing";
15
- import { TestJSCrypto } from "../testing";
14
+ import {
15
+ TestJazzContextManager,
16
+ createJazzTestAccount,
17
+ setupJazzTestSync,
18
+ } from "../testing";
16
19
  import { testWordlist } from "./fixtures";
17
20
 
18
21
  // Initialize KV store for tests
19
22
  KvStoreContext.getInstance().initialize(new InMemoryKVStore());
20
23
 
24
+ beforeEach(async () => {
25
+ await setupJazzTestSync();
26
+ });
27
+
21
28
  describe("PassphraseAuth", () => {
22
- let crypto: TestJSCrypto;
29
+ let crypto: PureJSCrypto;
23
30
  let mockAuthenticate: any;
31
+ let mockRegister: any;
24
32
  let authSecretStorage: AuthSecretStorage;
25
33
  let passphraseAuth: PassphraseAuth;
34
+ let account: Account;
26
35
 
27
36
  beforeEach(async () => {
28
37
  // Reset storage
29
38
  KvStoreContext.getInstance().getStorage().clearAll();
30
39
 
31
40
  // Set up crypto and mocks
32
- crypto = await TestJSCrypto.create();
41
+ crypto = await PureJSCrypto.create();
33
42
  mockAuthenticate = vi.fn();
43
+ mockRegister = vi.fn();
34
44
  authSecretStorage = new AuthSecretStorage();
35
45
 
36
- await createJazzTestAccount({
46
+ account = await createJazzTestAccount({
37
47
  isCurrentActiveAccount: true,
38
48
  });
39
49
 
@@ -41,6 +51,7 @@ describe("PassphraseAuth", () => {
41
51
  passphraseAuth = new PassphraseAuth(
42
52
  crypto,
43
53
  mockAuthenticate,
54
+ mockRegister,
44
55
  authSecretStorage,
45
56
  testWordlist,
46
57
  );
@@ -121,6 +132,39 @@ describe("PassphraseAuth", () => {
121
132
  "No credentials found",
122
133
  );
123
134
  });
135
+
136
+ it("should set account name when provided during signup", async () => {
137
+ const storageData = {
138
+ accountID: "test-account-id" as ID<Account>,
139
+ accountSecret: "test-secret" as AgentSecret,
140
+ secretSeed: new Uint8Array([
141
+ 173, 58, 235, 40, 67, 188, 236, 11, 107, 237, 97, 23, 182, 49, 188,
142
+ 63, 237, 52, 27, 84, 142, 66, 244, 149, 243, 114, 203, 164, 115, 239,
143
+ 175, 194,
144
+ ]),
145
+ provider: "anonymous",
146
+ };
147
+
148
+ await authSecretStorage.set(storageData);
149
+
150
+ const testName = "Test User";
151
+ await passphraseAuth.signUp(testName);
152
+
153
+ // Verify the account name was set
154
+ const { profile } = await account.ensureLoaded({
155
+ profile: {},
156
+ });
157
+ expect(profile.name).toBe(testName);
158
+
159
+ // Verify storage was updated correctly
160
+ const storedData = await authSecretStorage.get();
161
+ expect(storedData).toEqual({
162
+ accountID: storageData.accountID,
163
+ accountSecret: storageData.accountSecret,
164
+ secretSeed: storageData.secretSeed,
165
+ provider: "passphrase",
166
+ });
167
+ });
124
168
  });
125
169
 
126
170
  describe("getCurrentAccountPassphrase", () => {
@@ -150,3 +194,153 @@ describe("PassphraseAuth", () => {
150
194
  });
151
195
  });
152
196
  });
197
+
198
+ // Initialize KV store for tests
199
+ KvStoreContext.getInstance().initialize(new InMemoryKVStore());
200
+
201
+ describe("PassphraseAuth with TestJazzContextManager", () => {
202
+ let crypto: PureJSCrypto;
203
+ let contextManager: TestJazzContextManager<any>;
204
+ let authSecretStorage: AuthSecretStorage;
205
+ let passphraseAuth: PassphraseAuth;
206
+
207
+ beforeEach(async () => {
208
+ // Reset storage
209
+ KvStoreContext.getInstance().getStorage().clearAll();
210
+
211
+ const account = await createJazzTestAccount({
212
+ isCurrentActiveAccount: true,
213
+ });
214
+
215
+ // Set up crypto and context manager
216
+ crypto = await PureJSCrypto.create();
217
+ contextManager = TestJazzContextManager.fromAccountOrGuest(account);
218
+ authSecretStorage = contextManager.getAuthSecretStorage();
219
+
220
+ // Create initial context
221
+ await contextManager.createContext({});
222
+
223
+ // Create PassphraseAuth instance
224
+ passphraseAuth = new PassphraseAuth(
225
+ crypto,
226
+ contextManager.authenticate,
227
+ contextManager.register,
228
+ authSecretStorage,
229
+ testWordlist,
230
+ );
231
+ });
232
+
233
+ describe("logIn", () => {
234
+ it("should successfully log in with valid passphrase", async () => {
235
+ // First sign up to create initial credentials
236
+ const passphrase = await passphraseAuth.signUp();
237
+
238
+ // Log out
239
+ await contextManager.logOut();
240
+
241
+ // Log back in with passphrase
242
+ await passphraseAuth.logIn(passphrase);
243
+
244
+ // Verify we're logged in
245
+ const context = contextManager.getCurrentValue();
246
+
247
+ assert(context && "me" in context);
248
+
249
+ // Verify storage was updated
250
+ const storedData = await authSecretStorage.get();
251
+ expect(storedData?.provider).toBe("passphrase");
252
+ });
253
+
254
+ it("should throw error with invalid passphrase", async () => {
255
+ await expect(passphraseAuth.logIn("invalid words here")).rejects.toThrow(
256
+ "Invalid passphrase",
257
+ );
258
+ });
259
+ });
260
+
261
+ describe("signUp", () => {
262
+ it("should successfully sign up new user", async () => {
263
+ expect(authSecretStorage.isAuthenticated).toBe(false);
264
+
265
+ const passphrase = await passphraseAuth.signUp();
266
+
267
+ expect(authSecretStorage.isAuthenticated).toBe(true);
268
+
269
+ // Verify passphrase format
270
+ expect(passphrase.split(" ").length).toBeGreaterThan(0);
271
+
272
+ // Verify storage was updated
273
+ const storedData = await authSecretStorage.get();
274
+ expect(storedData?.provider).toBe("passphrase");
275
+
276
+ // Verify we can log in with the passphrase
277
+ await contextManager.logOut();
278
+ await passphraseAuth.logIn(passphrase);
279
+ const context = contextManager.getCurrentValue();
280
+ assert(context && "me" in context);
281
+ expect(context.me).toBeDefined();
282
+ });
283
+
284
+ it("should throw error when no credentials found", async () => {
285
+ await authSecretStorage.clear();
286
+ await expect(passphraseAuth.signUp()).rejects.toThrow(
287
+ "No credentials found",
288
+ );
289
+ });
290
+ });
291
+
292
+ describe("registerNewAccount", () => {
293
+ it("should successfully register new account with passphrase", async () => {
294
+ expect(authSecretStorage.isAuthenticated).toBe(false);
295
+
296
+ const passphrase = passphraseAuth.generateRandomPassphrase();
297
+ const accountId = await passphraseAuth.registerNewAccount(
298
+ passphrase,
299
+ "Test User",
300
+ );
301
+
302
+ // Verify account was created
303
+ expect(accountId).toBeDefined();
304
+
305
+ // Verify we can log in with the passphrase
306
+ await contextManager.logOut();
307
+ await passphraseAuth.logIn(passphrase);
308
+
309
+ const context = contextManager.getCurrentValue();
310
+
311
+ assert(context && "me" in context);
312
+ expect(context.me.id).toBe(accountId);
313
+ expect(context.me.profile?.name).toBe("Test User");
314
+
315
+ expect(authSecretStorage.isAuthenticated).toBe(true);
316
+
317
+ const credentials = await authSecretStorage.get();
318
+ assert(credentials);
319
+ expect(credentials.accountID).toBe(accountId);
320
+ expect(credentials.provider).toBe("passphrase");
321
+ });
322
+
323
+ it("should throw error with invalid passphrase during registration", async () => {
324
+ await expect(
325
+ passphraseAuth.registerNewAccount("invalid words", "Test User"),
326
+ ).rejects.toThrow();
327
+ });
328
+ });
329
+
330
+ describe("getCurrentAccountPassphrase", () => {
331
+ it("should return current user passphrase when credentials exist", async () => {
332
+ const originalPassphrase = await passphraseAuth.signUp();
333
+ const retrievedPassphrase =
334
+ await passphraseAuth.getCurrentAccountPassphrase();
335
+
336
+ expect(retrievedPassphrase).toBe(originalPassphrase);
337
+ });
338
+
339
+ it("should throw error when no credentials found", async () => {
340
+ await authSecretStorage.clear();
341
+ await expect(
342
+ passphraseAuth.getCurrentAccountPassphrase(),
343
+ ).rejects.toThrow("No credentials found");
344
+ });
345
+ });
346
+ });
package/src/types.ts CHANGED
@@ -12,6 +12,7 @@ export type AuthCredentials = {
12
12
  export type AuthenticateAccountFunction = (
13
13
  credentials: AuthCredentials,
14
14
  ) => Promise<void>;
15
+
15
16
  export type RegisterAccountFunction = (
16
17
  accountSecret: AgentSecret,
17
18
  creationProps: { name: string },
@@ -22,6 +23,7 @@ export type JazzAuthContext<Acc extends Account> = {
22
23
  me: Acc;
23
24
  node: LocalNode;
24
25
  authenticate: AuthenticateAccountFunction;
26
+ register: RegisterAccountFunction;
25
27
  logOut: () => Promise<void>;
26
28
  done: () => void;
27
29
  isAuthenticated?: boolean;
@@ -31,6 +33,7 @@ export type JazzGuestContext = {
31
33
  guest: AnonymousJazzAgent;
32
34
  node: LocalNode;
33
35
  authenticate: AuthenticateAccountFunction;
36
+ register: RegisterAccountFunction;
34
37
  logOut: () => void;
35
38
  done: () => void;
36
39
  isAuthenticated?: boolean;
package/tsconfig.json CHANGED
@@ -12,5 +12,5 @@
12
12
  "esModuleInterop": true
13
13
  },
14
14
  "include": ["./src/**/*.ts"],
15
- "exclude": ["./node_modules", "./src/tests"]
15
+ "exclude": ["./node_modules"]
16
16
  }