jazz-tools 0.9.23 → 0.10.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.
Files changed (45) hide show
  1. package/.turbo/turbo-build.log +11 -11
  2. package/CHANGELOG.md +19 -0
  3. package/dist/{chunk-OJIEP4WE.js → chunk-UBD75Z27.js} +566 -118
  4. package/dist/chunk-UBD75Z27.js.map +1 -0
  5. package/dist/index.native.js +17 -5
  6. package/dist/index.native.js.map +1 -1
  7. package/dist/index.web.js +17 -5
  8. package/dist/index.web.js.map +1 -1
  9. package/dist/testing.js +124 -33
  10. package/dist/testing.js.map +1 -1
  11. package/package.json +5 -3
  12. package/src/auth/AuthSecretStorage.ts +109 -0
  13. package/src/auth/DemoAuth.ts +188 -0
  14. package/src/auth/InMemoryKVStore.ts +25 -0
  15. package/src/auth/KvStoreContext.ts +39 -0
  16. package/src/auth/PassphraseAuth.ts +113 -0
  17. package/src/coValues/account.ts +8 -3
  18. package/src/coValues/coFeed.ts +1 -1
  19. package/src/coValues/coList.ts +1 -1
  20. package/src/coValues/coMap.ts +1 -1
  21. package/src/coValues/group.ts +9 -8
  22. package/src/coValues/interfaces.ts +14 -5
  23. package/src/exports.ts +17 -3
  24. package/src/implementation/ContextManager.ts +178 -0
  25. package/src/implementation/activeAccountContext.ts +6 -1
  26. package/src/implementation/createContext.ts +173 -149
  27. package/src/testing.ts +171 -33
  28. package/src/tests/AuthSecretStorage.test.ts +275 -0
  29. package/src/tests/ContextManager.test.ts +256 -0
  30. package/src/tests/DemoAuth.test.ts +269 -0
  31. package/src/tests/PassphraseAuth.test.ts +152 -0
  32. package/src/tests/coFeed.test.ts +44 -39
  33. package/src/tests/coList.test.ts +21 -20
  34. package/src/tests/coMap.test.ts +21 -20
  35. package/src/tests/coPlainText.test.ts +21 -20
  36. package/src/tests/coRichText.test.ts +21 -20
  37. package/src/tests/createContext.test.ts +339 -0
  38. package/src/tests/deepLoading.test.ts +41 -42
  39. package/src/tests/fixtures.ts +2050 -0
  40. package/src/tests/groupsAndAccounts.test.ts +2 -2
  41. package/src/tests/subscribe.test.ts +42 -9
  42. package/src/tests/testing.test.ts +56 -0
  43. package/src/tests/utils.ts +11 -11
  44. package/src/types.ts +54 -0
  45. package/dist/chunk-OJIEP4WE.js.map +0 -1
@@ -0,0 +1,256 @@
1
+ import { WasmCrypto } from "cojson";
2
+ import { beforeEach, describe, expect, test, vi } from "vitest";
3
+ import {
4
+ Account,
5
+ AccountClass,
6
+ AuthSecretStorage,
7
+ CoMap,
8
+ Group,
9
+ InMemoryKVStore,
10
+ JazzAuthContext,
11
+ KvStoreContext,
12
+ co,
13
+ } from "../exports";
14
+ import {
15
+ JazzContextManager,
16
+ JazzContextManagerAuthProps,
17
+ JazzContextManagerBaseProps,
18
+ } from "../implementation/ContextManager";
19
+ import {
20
+ createJazzContext,
21
+ randomSessionProvider,
22
+ } from "../implementation/createContext";
23
+ import {
24
+ createJazzTestAccount,
25
+ getPeerConnectedToTestSyncServer,
26
+ setupJazzTestSync,
27
+ } from "../testing";
28
+
29
+ const Crypto = await WasmCrypto.create();
30
+
31
+ class TestJazzContextManager<Acc extends Account> extends JazzContextManager<
32
+ Acc,
33
+ JazzContextManagerBaseProps<Acc> & {
34
+ defaultProfileName?: string;
35
+ AccountSchema?: AccountClass<Acc>;
36
+ }
37
+ > {
38
+ async createContext(
39
+ props: JazzContextManagerBaseProps<Acc> & {
40
+ defaultProfileName?: string;
41
+ AccountSchema?: AccountClass<Acc>;
42
+ },
43
+ authProps?: JazzContextManagerAuthProps,
44
+ ) {
45
+ const context = await createJazzContext<Acc>({
46
+ credentials: authProps?.credentials,
47
+ defaultProfileName: props.defaultProfileName,
48
+ newAccountProps: authProps?.newAccountProps,
49
+ peersToLoadFrom: [getPeerConnectedToTestSyncServer()],
50
+ crypto: Crypto,
51
+ sessionProvider: randomSessionProvider,
52
+ authSecretStorage: this.getAuthSecretStorage(),
53
+ AccountSchema: props.AccountSchema,
54
+ });
55
+
56
+ this.updateContext(props, {
57
+ me: context.account,
58
+ node: context.node,
59
+ done: () => {
60
+ context.done();
61
+ },
62
+ logOut: () => {
63
+ context.logOut();
64
+ },
65
+ });
66
+ }
67
+ }
68
+
69
+ describe("ContextManager", () => {
70
+ let manager: TestJazzContextManager<Account>;
71
+ let authSecretStorage: AuthSecretStorage;
72
+
73
+ function getCurrentValue() {
74
+ return manager.getCurrentValue() as JazzAuthContext<Account>;
75
+ }
76
+
77
+ beforeEach(async () => {
78
+ KvStoreContext.getInstance().initialize(new InMemoryKVStore());
79
+ authSecretStorage = new AuthSecretStorage();
80
+ await authSecretStorage.clear();
81
+ await setupJazzTestSync();
82
+
83
+ manager = new TestJazzContextManager<Account>();
84
+ });
85
+
86
+ test("creates new context when initialized", async () => {
87
+ await manager.createContext({});
88
+
89
+ const context = getCurrentValue();
90
+
91
+ expect(context.me.profile?.name).toBe("Anonymous user");
92
+ expect(context.node).toBeDefined();
93
+ expect(manager.getCurrentValue()).toBeDefined();
94
+ });
95
+
96
+ test("creates new context when initialized with default profile name", async () => {
97
+ await manager.createContext({
98
+ defaultProfileName: "Test User",
99
+ });
100
+
101
+ const context = getCurrentValue();
102
+
103
+ expect(context.me.profile?.name).toBe("Test User");
104
+ expect(context.node).toBeDefined();
105
+ expect(manager.getCurrentValue()).toBeDefined();
106
+ });
107
+
108
+ test("handles authentication with credentials", async () => {
109
+ const account = await createJazzTestAccount();
110
+
111
+ // First create an initial context to get credentials
112
+ await manager.createContext({});
113
+
114
+ const credentials = {
115
+ accountID: account.id,
116
+ accountSecret: account._raw.core.node.account.agentSecret,
117
+ provider: "test",
118
+ };
119
+
120
+ // Authenticate with those credentials
121
+ await manager.authenticate(credentials);
122
+
123
+ expect(getCurrentValue().me.id).toBe(credentials.accountID);
124
+ });
125
+
126
+ test("calls onLogOut callback when logging out", async () => {
127
+ const onLogOut = vi.fn();
128
+ await manager.createContext({ onLogOut });
129
+
130
+ await manager.logOut();
131
+
132
+ expect(onLogOut).toHaveBeenCalled();
133
+ });
134
+
135
+ test("notifies listeners of context changes", async () => {
136
+ const listener = vi.fn();
137
+ manager.subscribe(listener);
138
+
139
+ await manager.createContext({});
140
+
141
+ expect(listener).toHaveBeenCalled();
142
+ });
143
+
144
+ test("cleans up context when done", async () => {
145
+ await manager.createContext({});
146
+
147
+ const context = manager.getCurrentValue();
148
+ expect(context).toBeDefined();
149
+
150
+ manager.done();
151
+
152
+ // Should still have context, just cleaned up
153
+ expect(manager.getCurrentValue()).toBe(context);
154
+ });
155
+
156
+ test("calls onAnonymousAccountDiscarded when authenticating from anonymous user", async () => {
157
+ const onAnonymousAccountDiscarded = vi.fn();
158
+ const account = await createJazzTestAccount();
159
+
160
+ // Create initial anonymous context
161
+ await manager.createContext({ onAnonymousAccountDiscarded });
162
+ const anonymousAccount = getCurrentValue().me;
163
+
164
+ // Authenticate with credentials
165
+ await manager.authenticate({
166
+ accountID: account.id,
167
+ accountSecret: account._raw.core.node.account.agentSecret,
168
+ provider: "test",
169
+ });
170
+
171
+ // Verify callback was called with the anonymous account
172
+ expect(onAnonymousAccountDiscarded).toHaveBeenCalledWith(anonymousAccount);
173
+ });
174
+
175
+ test("does not call onAnonymousAccountDiscarded when authenticating from authenticated user", async () => {
176
+ const onAnonymousAccountDiscarded = vi.fn();
177
+ const account = await createJazzTestAccount();
178
+
179
+ await manager.getAuthSecretStorage().set({
180
+ accountID: account.id,
181
+ accountSecret: account._raw.core.node.account.agentSecret,
182
+ provider: "test",
183
+ });
184
+
185
+ // Create initial authenticated context
186
+ await manager.createContext({ onAnonymousAccountDiscarded });
187
+
188
+ // Authenticate with same credentials
189
+ await manager.authenticate({
190
+ accountID: account.id,
191
+ accountSecret: account._raw.core.node.account.agentSecret,
192
+ provider: "test",
193
+ });
194
+
195
+ // Verify callback was not called
196
+ expect(onAnonymousAccountDiscarded).not.toHaveBeenCalled();
197
+ });
198
+
199
+ test("onAnonymousAccountDiscarded should work on transfering data between accounts", async () => {
200
+ class AccountRoot extends CoMap {
201
+ value = co.string;
202
+ transferredRoot = co.optional.ref(AccountRoot);
203
+ }
204
+
205
+ class CustomAccount extends Account {
206
+ root = co.ref(AccountRoot);
207
+
208
+ migrate() {
209
+ if (this.root === undefined) {
210
+ this.root = AccountRoot.create({
211
+ value: "Hello",
212
+ });
213
+ }
214
+ }
215
+ }
216
+
217
+ const onAnonymousAccountDiscarded = async (
218
+ anonymousAccount: CustomAccount,
219
+ ) => {
220
+ const anonymousAccountWithRoot = await anonymousAccount.ensureLoaded({
221
+ root: {},
222
+ });
223
+
224
+ const meWithRoot = await CustomAccount.getMe().ensureLoaded({ root: {} });
225
+
226
+ const rootToTransfer = anonymousAccountWithRoot.root;
227
+
228
+ await rootToTransfer._owner.castAs(Group).addMember(meWithRoot, "admin");
229
+
230
+ meWithRoot.root.transferredRoot = rootToTransfer;
231
+ };
232
+
233
+ const customManager = new TestJazzContextManager<CustomAccount>();
234
+
235
+ // Create initial anonymous context
236
+ await customManager.createContext({
237
+ onAnonymousAccountDiscarded,
238
+ AccountSchema: CustomAccount,
239
+ });
240
+
241
+ const account = await createJazzTestAccount({
242
+ isCurrentActiveAccount: true,
243
+ AccountSchema: CustomAccount,
244
+ });
245
+
246
+ await customManager.authenticate({
247
+ accountID: account.id,
248
+ accountSecret: account._raw.core.node.account.agentSecret,
249
+ provider: "test",
250
+ });
251
+
252
+ const me = await CustomAccount.getMe().ensureLoaded({ root: {} });
253
+
254
+ expect(me.root.transferredRoot?.value).toBe("Hello");
255
+ });
256
+ });
@@ -0,0 +1,269 @@
1
+ import { AgentSecret } from "cojson";
2
+ import { beforeEach, describe, expect, test, vi } from "vitest";
3
+ import { AuthSecretStorage } from "../auth/AuthSecretStorage";
4
+ import { DemoAuth } from "../auth/DemoAuth";
5
+ import { InMemoryKVStore } from "../auth/InMemoryKVStore";
6
+ import { KvStoreContext } from "../auth/KvStoreContext";
7
+ import { Account } from "../coValues/account";
8
+ import { ID } from "../internal";
9
+ import { createJazzTestAccount } from "../testing";
10
+
11
+ // Initialize KV store for tests
12
+ const kvStore = new InMemoryKVStore();
13
+ KvStoreContext.getInstance().initialize(kvStore);
14
+
15
+ describe("DemoAuth", () => {
16
+ let mockAuthenticate: any;
17
+ let authSecretStorage: AuthSecretStorage;
18
+ let demoAuth: DemoAuth;
19
+
20
+ beforeEach(async () => {
21
+ // Reset mock authenticate
22
+ mockAuthenticate = vi.fn();
23
+
24
+ // Clear KV store
25
+ kvStore.clearAll();
26
+
27
+ // Create new AuthSecretStorage instance
28
+ authSecretStorage = new AuthSecretStorage();
29
+
30
+ await createJazzTestAccount({
31
+ isCurrentActiveAccount: true,
32
+ });
33
+
34
+ // Create DemoAuth instance
35
+ demoAuth = new DemoAuth(mockAuthenticate, authSecretStorage);
36
+ });
37
+
38
+ describe("logIn", () => {
39
+ test("should successfully log in existing user", async () => {
40
+ const testUser = "testUser";
41
+
42
+ const credentials = {
43
+ accountID: "new-account-id" as ID<Account>,
44
+ accountSecret: "new-secret" as AgentSecret,
45
+ secretSeed: new Uint8Array([1, 2, 3]),
46
+ provider: "anonymous",
47
+ };
48
+
49
+ await authSecretStorage.set(credentials);
50
+
51
+ await demoAuth.signUp(testUser);
52
+
53
+ await demoAuth.logIn(testUser);
54
+
55
+ expect(mockAuthenticate).toHaveBeenCalledWith({
56
+ accountID: credentials.accountID,
57
+ accountSecret: credentials.accountSecret,
58
+ });
59
+
60
+ const storedData = await authSecretStorage.get();
61
+ expect(storedData).toEqual({
62
+ accountID: credentials.accountID,
63
+ accountSecret: credentials.accountSecret,
64
+ secretSeed: credentials.secretSeed,
65
+ provider: "demo",
66
+ });
67
+ });
68
+
69
+ test("should throw error for non-existent user", async () => {
70
+ await expect(demoAuth.logIn("nonexistentUser")).rejects.toThrow(
71
+ "User not found",
72
+ );
73
+ });
74
+ });
75
+
76
+ describe("signUp", () => {
77
+ test("should successfully sign up new user", async () => {
78
+ const testUser = "newUser";
79
+ const credentials = {
80
+ accountID: "new-account-id" as ID<Account>,
81
+ accountSecret: "new-secret" as AgentSecret,
82
+ secretSeed: new Uint8Array([1, 2, 3]),
83
+ };
84
+
85
+ await authSecretStorage.set({
86
+ ...credentials,
87
+ provider: "anonymous",
88
+ });
89
+
90
+ await demoAuth.signUp(testUser);
91
+
92
+ const storedData = await authSecretStorage.get();
93
+ expect(storedData).toEqual({
94
+ ...credentials,
95
+ provider: "demo",
96
+ });
97
+ });
98
+
99
+ test("should throw error for existing username", async () => {
100
+ const testUser = "existingUser";
101
+ await kvStore.set("demo-auth-storage-version", "3");
102
+ await kvStore.set(
103
+ "demo-auth-users",
104
+ JSON.stringify({
105
+ [testUser]: {
106
+ accountID: "existing-account-id" as ID<Account>,
107
+ accountSecret: "existing-secret" as AgentSecret,
108
+ secretSeed: [1, 2, 3],
109
+ },
110
+ }),
111
+ );
112
+
113
+ await expect(demoAuth.signUp(testUser)).rejects.toThrow(
114
+ "User already registered",
115
+ );
116
+ });
117
+
118
+ test("should throw error when no credentials found", async () => {
119
+ await expect(demoAuth.signUp("newUser")).rejects.toThrow(
120
+ "No credentials found",
121
+ );
122
+ });
123
+ });
124
+
125
+ describe("DemoAuth Storage Migration", () => {
126
+ test("should migrate from version 1 to version 3", async () => {
127
+ // Set up version 1 data
128
+ const testUser = "test@example.com";
129
+ const storageData = {
130
+ accountID: "test-account-id" as ID<Account>,
131
+ accountSecret: "test-secret" as AgentSecret,
132
+ secretSeed: [1, 2, 3],
133
+ };
134
+
135
+ // Store data in old format
136
+ await kvStore.set("demo-auth-existing-users", testUser);
137
+ await kvStore.set(
138
+ `demo-auth-existing-users-${testUser}`,
139
+ JSON.stringify(storageData),
140
+ );
141
+
142
+ // Trigger migration by getting existing users
143
+ await demoAuth.getExistingUsers();
144
+
145
+ // Verify migration
146
+ const version = await kvStore.get("demo-auth-storage-version");
147
+ expect(version).toBe("3");
148
+
149
+ // Old key should be deleted
150
+ const oldData = await kvStore.get(`demo-auth-existing-users-${testUser}`);
151
+ expect(oldData).toBeNull();
152
+
153
+ // New encoded key should exist
154
+ const newData = await kvStore.get("demo-auth-users");
155
+ expect(JSON.parse(newData!)).toEqual({
156
+ [testUser]: storageData,
157
+ });
158
+ });
159
+
160
+ test("should migrate from version 2 to version 3 (new storage format)", async () => {
161
+ // Set up version 2 data
162
+ const testUser = "test@example.com";
163
+ const encodedUsername = btoa(testUser)
164
+ .replace(/=/g, "-")
165
+ .replace(/\+/g, "_")
166
+ .replace(/\//g, ".");
167
+
168
+ const storageData = {
169
+ accountID: "test-account-id" as ID<Account>,
170
+ accountSecret: "test-secret" as AgentSecret,
171
+ secretSeed: [1, 2, 3],
172
+ };
173
+
174
+ // Store data in version 2 format
175
+ await kvStore.set("demo-auth-storage-version", "2");
176
+ await kvStore.set("demo-auth-existing-users", testUser);
177
+ await kvStore.set(
178
+ `demo-auth-existing-users-${encodedUsername}`,
179
+ JSON.stringify(storageData),
180
+ );
181
+
182
+ // Trigger migration by getting existing users
183
+ await demoAuth.getExistingUsers();
184
+
185
+ // Verify migration
186
+ const version = await kvStore.get("demo-auth-storage-version");
187
+ expect(version).toBe("3");
188
+
189
+ // Old keys should be deleted
190
+ const oldListData = await kvStore.get("demo-auth-existing-users");
191
+ expect(oldListData).toBeNull();
192
+
193
+ const oldUserData = await kvStore.get(
194
+ `demo-auth-existing-users-${encodedUsername}`,
195
+ );
196
+ expect(oldUserData).toBeNull();
197
+
198
+ // New storage format should be used
199
+ const newData = await kvStore.get("demo-auth-users");
200
+ expect(JSON.parse(newData!)).toEqual({
201
+ [testUser]: storageData,
202
+ });
203
+ });
204
+
205
+ test("should handle new users management after migration", async () => {
206
+ // Add a test user
207
+ const testUser = "newuser";
208
+ await authSecretStorage.set({
209
+ accountID: "test-id" as ID<Account>,
210
+ accountSecret: "test-secret" as AgentSecret,
211
+ secretSeed: new Uint8Array([1, 2, 3]),
212
+ provider: "anonymous",
213
+ });
214
+
215
+ // Sign up new user
216
+ await demoAuth.signUp(testUser);
217
+
218
+ // Verify user is stored in new format
219
+ const usersData = await kvStore.get("demo-auth-users");
220
+ const users = JSON.parse(usersData!);
221
+
222
+ expect(Object.keys(users)).toContain(testUser);
223
+ expect(users[testUser]).toEqual({
224
+ accountID: "test-id",
225
+ accountSecret: "test-secret",
226
+ secretSeed: [1, 2, 3],
227
+ });
228
+
229
+ // Verify we can get existing users
230
+ const existingUsers = await demoAuth.getExistingUsers();
231
+ expect(existingUsers).toEqual([testUser]);
232
+
233
+ // Verify we can log in with the stored user
234
+ await demoAuth.logIn(testUser);
235
+ const storedAuth = await authSecretStorage.get();
236
+ expect(storedAuth).toEqual({
237
+ accountID: "test-id",
238
+ accountSecret: "test-secret",
239
+ secretSeed: new Uint8Array([1, 2, 3]),
240
+ provider: "demo",
241
+ });
242
+ });
243
+
244
+ test("should handle multiple users in new storage format", async () => {
245
+ // Set up initial auth data
246
+ await authSecretStorage.set({
247
+ accountID: "test-id" as ID<Account>,
248
+ accountSecret: "test-secret" as AgentSecret,
249
+ secretSeed: new Uint8Array([1, 2, 3]),
250
+ provider: "anonymous",
251
+ });
252
+
253
+ // Add multiple users
254
+ const users = ["user1", "user2", "user3"];
255
+ for (const user of users) {
256
+ await demoAuth.signUp(user);
257
+ }
258
+
259
+ // Verify all users are stored
260
+ const existingUsers = await demoAuth.getExistingUsers();
261
+ expect(existingUsers.sort()).toEqual(users.sort());
262
+
263
+ // Verify we can't add duplicate users
264
+ await expect(demoAuth.signUp("user1")).rejects.toThrow(
265
+ "User already registered",
266
+ );
267
+ });
268
+ });
269
+ });
@@ -0,0 +1,152 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ import { mnemonicToEntropy } from "@scure/bip39";
4
+ import { AgentSecret } from "cojson";
5
+ import {
6
+ Account,
7
+ AuthSecretStorage,
8
+ ID,
9
+ InMemoryKVStore,
10
+ KvStoreContext,
11
+ } from "jazz-tools";
12
+ import { beforeEach, describe, expect, it, vi } from "vitest";
13
+ import { PassphraseAuth } from "../auth/PassphraseAuth";
14
+ import { createJazzTestAccount } from "../testing";
15
+ import { TestJSCrypto } from "../testing";
16
+ import { testWordlist } from "./fixtures";
17
+
18
+ // Initialize KV store for tests
19
+ KvStoreContext.getInstance().initialize(new InMemoryKVStore());
20
+
21
+ describe("PassphraseAuth", () => {
22
+ let crypto: TestJSCrypto;
23
+ let mockAuthenticate: any;
24
+ let authSecretStorage: AuthSecretStorage;
25
+ let passphraseAuth: PassphraseAuth;
26
+
27
+ beforeEach(async () => {
28
+ // Reset storage
29
+ KvStoreContext.getInstance().getStorage().clearAll();
30
+
31
+ // Set up crypto and mocks
32
+ crypto = await TestJSCrypto.create();
33
+ mockAuthenticate = vi.fn();
34
+ authSecretStorage = new AuthSecretStorage();
35
+
36
+ await createJazzTestAccount({
37
+ isCurrentActiveAccount: true,
38
+ });
39
+
40
+ // Create PassphraseAuth instance
41
+ passphraseAuth = new PassphraseAuth(
42
+ crypto,
43
+ mockAuthenticate,
44
+ authSecretStorage,
45
+ testWordlist,
46
+ );
47
+ });
48
+
49
+ describe("logIn", () => {
50
+ it("should successfully log in with valid passphrase", async () => {
51
+ const storageData = {
52
+ accountID: "test-account-id" as ID<Account>,
53
+ accountSecret: "test-secret" as AgentSecret,
54
+ secretSeed: new Uint8Array([
55
+ 173, 58, 235, 40, 67, 188, 236, 11, 107, 237, 97, 23, 182, 49, 188,
56
+ 63, 237, 52, 27, 84, 142, 66, 244, 149, 243, 114, 203, 164, 115, 239,
57
+ 175, 194,
58
+ ]),
59
+ provider: "anonymous",
60
+ };
61
+
62
+ await authSecretStorage.set(storageData);
63
+
64
+ // Generate a valid passphrase
65
+ const passphrase = await passphraseAuth.getCurrentAccountPassphrase();
66
+
67
+ await passphraseAuth.logIn(passphrase);
68
+
69
+ expect(mockAuthenticate).toHaveBeenCalledWith({
70
+ accountID: expect.any(String),
71
+ accountSecret: expect.any(String),
72
+ });
73
+
74
+ const storedData = await authSecretStorage.get();
75
+ expect(storedData).toEqual({
76
+ accountID: expect.any(String),
77
+ accountSecret: expect.any(String),
78
+ secretSeed: storageData.secretSeed,
79
+ provider: "passphrase",
80
+ });
81
+ });
82
+
83
+ it("should throw error with invalid passphrase", async () => {
84
+ await expect(passphraseAuth.logIn("invalid words here")).rejects.toThrow(
85
+ "Invalid passphrase",
86
+ );
87
+ });
88
+ });
89
+
90
+ describe("signUp", () => {
91
+ it("should successfully sign up new user", async () => {
92
+ const storageData = {
93
+ accountID: "test-account-id" as ID<Account>,
94
+ accountSecret: "test-secret" as AgentSecret,
95
+ secretSeed: new Uint8Array([
96
+ 173, 58, 235, 40, 67, 188, 236, 11, 107, 237, 97, 23, 182, 49, 188,
97
+ 63, 237, 52, 27, 84, 142, 66, 244, 149, 243, 114, 203, 164, 115, 239,
98
+ 175, 194,
99
+ ]),
100
+ provider: "anonymous",
101
+ };
102
+
103
+ await authSecretStorage.set(storageData);
104
+
105
+ const passphrase = await passphraseAuth.signUp();
106
+
107
+ const storedData = await authSecretStorage.get();
108
+ expect(storedData).toEqual({
109
+ accountID: storageData.accountID,
110
+ accountSecret: storageData.accountSecret,
111
+ secretSeed: storageData.secretSeed,
112
+ provider: "passphrase",
113
+ });
114
+ expect(passphrase).toMatchInlineSnapshot(
115
+ `"pudding struggle skate manual solution aisle quick promote bless ranch humor lemon spy asset fall sign virus question syrup nuclear elbow water sample garden"`,
116
+ );
117
+ });
118
+
119
+ it("should throw error when no credentials found", async () => {
120
+ await expect(passphraseAuth.signUp()).rejects.toThrow(
121
+ "No credentials found",
122
+ );
123
+ });
124
+ });
125
+
126
+ describe("getCurrentAccountPassphrase", () => {
127
+ it("should return current user passphrase when credentials exist", async () => {
128
+ const storageData = {
129
+ accountID: "test-account-id" as ID<Account>,
130
+ accountSecret: "test-secret" as AgentSecret,
131
+ secretSeed: crypto.newRandomSecretSeed(),
132
+ provider: "anonymous",
133
+ };
134
+
135
+ await authSecretStorage.set(storageData);
136
+
137
+ // First sign up to create valid credentials
138
+ const originalPassphrase = await passphraseAuth.signUp();
139
+
140
+ // Then get the current passphrase
141
+ const retrievedPassphrase =
142
+ await passphraseAuth.getCurrentAccountPassphrase();
143
+ expect(retrievedPassphrase).toBe(originalPassphrase);
144
+ });
145
+
146
+ it("should throw error when no credentials found", async () => {
147
+ await expect(
148
+ passphraseAuth.getCurrentAccountPassphrase(),
149
+ ).rejects.toThrow("No credentials found");
150
+ });
151
+ });
152
+ });