jazz-tools 0.10.5 → 0.10.7

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.
@@ -13,12 +13,12 @@ KvStoreContext.getInstance().initialize(kvStore);
13
13
  let authSecretStorage = new AuthSecretStorage();
14
14
 
15
15
  describe("AuthSecretStorage", () => {
16
- beforeEach(() => {
17
- kvStore.clearAll();
18
- authSecretStorage = new AuthSecretStorage();
19
- });
20
-
21
16
  describe("migrate", () => {
17
+ beforeEach(() => {
18
+ kvStore.clearAll();
19
+ authSecretStorage = new AuthSecretStorage();
20
+ });
21
+
22
22
  it("should migrate demo auth secret", async () => {
23
23
  const demoSecret = JSON.stringify({
24
24
  accountID: "demo123",
@@ -28,25 +28,62 @@ describe("AuthSecretStorage", () => {
28
28
 
29
29
  await authSecretStorage.migrate();
30
30
 
31
- expect(await kvStore.get("jazz-logged-in-secret")).toBe(demoSecret);
31
+ expect(await kvStore.get("jazz-logged-in-secret")).toBe(
32
+ JSON.stringify({
33
+ accountID: "demo123",
34
+ accountSecret: "secret123",
35
+ provider: "demo",
36
+ }),
37
+ );
32
38
  expect(await kvStore.get("demo-auth-logged-in-secret")).toBeNull();
33
39
  });
34
40
 
35
41
  it("should migrate clerk auth secret", async () => {
36
42
  const clerkSecret = JSON.stringify({
37
43
  accountID: "clerk123",
38
- accountSecret: "secret123",
44
+ secret: "secret123",
39
45
  });
40
46
  await kvStore.set("jazz-clerk-auth", clerkSecret);
41
47
 
42
48
  await authSecretStorage.migrate();
43
49
 
44
- expect(await kvStore.get("jazz-logged-in-secret")).toBe(clerkSecret);
50
+ expect(await kvStore.get("jazz-logged-in-secret")).toBe(
51
+ JSON.stringify({
52
+ accountID: "clerk123",
53
+ accountSecret: "secret123",
54
+ provider: "clerk",
55
+ }),
56
+ );
57
+ expect(await kvStore.get("jazz-clerk-auth")).toBeNull();
58
+ });
59
+
60
+ it("should migrate auth wrong secret key to accountSecret", async () => {
61
+ const clerkSecret = JSON.stringify({
62
+ accountID: "clerk123",
63
+ secret: "secret123",
64
+ provider: "clerk",
65
+ });
66
+ await kvStore.set("jazz-logged-in-secret", clerkSecret);
67
+
68
+ await authSecretStorage.migrate();
69
+
70
+ expect(await kvStore.get("jazz-logged-in-secret")).toBe(
71
+ JSON.stringify({
72
+ accountID: "clerk123",
73
+ accountSecret: "secret123",
74
+ provider: "clerk",
75
+ }),
76
+ );
45
77
  expect(await kvStore.get("jazz-clerk-auth")).toBeNull();
46
78
  });
47
79
  });
48
80
 
49
81
  describe("get", () => {
82
+ beforeEach(() => {
83
+ kvStore.clearAll();
84
+ authSecretStorage = new AuthSecretStorage();
85
+ });
86
+
50
87
  it("should return null when no data exists", async () => {
51
88
  expect(await authSecretStorage.get()).toBeNull();
52
89
  });
@@ -100,6 +137,11 @@ describe("AuthSecretStorage", () => {
100
137
  });
101
138
 
102
139
  describe("set", () => {
140
+ beforeEach(() => {
141
+ kvStore.clearAll();
142
+ authSecretStorage = new AuthSecretStorage();
143
+ });
144
+
103
145
  it("should set credentials with secretSeed", async () => {
104
146
  const payload = {
105
147
  accountID: "test123" as ID<Account>,
@@ -133,61 +175,14 @@ describe("AuthSecretStorage", () => {
133
175
  const stored = JSON.parse((await kvStore.get("jazz-logged-in-secret"))!);
134
176
  expect(stored).toEqual(payload);
135
177
  });
136
-
137
- it("should emit update event when setting credentials", async () => {
138
- const handler = vi.fn();
139
- authSecretStorage.onUpdate(handler);
140
-
141
- await authSecretStorage.set({
142
- accountID: "test123" as ID<Account>,
143
- accountSecret:
144
- "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
145
- provider: "passphrase",
146
- });
147
-
148
- expect(handler).toHaveBeenCalled();
149
- });
150
178
  });
151
179
 
152
- describe("isAuthenticated", () => {
153
- it("should return false when no data exists", async () => {
154
- expect(authSecretStorage.isAuthenticated).toBe(false);
155
- });
156
-
157
- it("should return false for anonymous credentials", async () => {
158
- await authSecretStorage.set({
159
- accountID: "test123" as ID<Account>,
160
- accountSecret:
161
- "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
162
- secretSeed: new Uint8Array([1, 2, 3]),
163
- provider: "anonymous",
164
- });
165
- expect(authSecretStorage.isAuthenticated).toBe(false);
166
- });
167
-
168
- it("should return true for non-anonymous credentials", async () => {
169
- await authSecretStorage.set({
170
- accountID: "test123" as ID<Account>,
171
- accountSecret:
172
- "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
173
- secretSeed: new Uint8Array([1, 2, 3]),
174
- provider: "demo",
175
- });
176
- expect(authSecretStorage.isAuthenticated).toBe(true);
177
- });
178
-
179
- it("should return true when the provider is missing", async () => {
180
- await authSecretStorage.set({
181
- accountID: "test123" as ID<Account>,
182
- accountSecret:
183
- "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
184
- secretSeed: new Uint8Array([1, 2, 3]),
185
- } as any);
186
- expect(authSecretStorage.isAuthenticated).toBe(true);
180
+ describe("onUpdate", () => {
181
+ beforeEach(() => {
182
+ kvStore.clearAll();
183
+ authSecretStorage = new AuthSecretStorage();
187
184
  });
188
- });
189
185
 
190
- describe("onUpdate", () => {
191
186
  it("should add and remove event listener", () => {
192
187
  const handler = vi.fn();
193
188
 
@@ -243,6 +238,11 @@ describe("AuthSecretStorage", () => {
243
238
  });
244
239
 
245
240
  describe("clear", () => {
241
+ beforeEach(() => {
242
+ kvStore.clearAll();
243
+ authSecretStorage = new AuthSecretStorage();
244
+ });
245
+
246
246
  it("should remove stored credentials", async () => {
247
247
  await authSecretStorage.set({
248
248
  accountID: "test123" as ID<Account>,
@@ -255,21 +255,179 @@ describe("AuthSecretStorage", () => {
255
255
 
256
256
  expect(await authSecretStorage.get()).toBeNull();
257
257
  });
258
+ });
258
259
 
259
- it("should emit update event when clearing", async () => {
260
- await authSecretStorage.set({
261
- accountID: "test123" as ID<Account>,
262
- accountSecret:
263
- "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
264
- provider: "passphrase",
260
+ describe("notify=true", () => {
261
+ beforeEach(() => {
262
+ kvStore.clearAll();
263
+ authSecretStorage = new AuthSecretStorage();
264
+ authSecretStorage.notify = true;
265
+ });
266
+
267
+ describe("set", () => {
268
+ it("should emit update event when setting credentials", async () => {
269
+ const handler = vi.fn();
270
+ authSecretStorage.onUpdate(handler);
271
+
272
+ await authSecretStorage.set({
273
+ accountID: "test123" as ID<Account>,
274
+ accountSecret:
275
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
276
+ provider: "passphrase",
277
+ });
278
+
279
+ expect(handler).toHaveBeenCalled();
265
280
  });
281
+ });
266
282
 
267
- const handler = vi.fn();
268
- authSecretStorage.onUpdate(handler);
283
+ describe("isAuthenticated", () => {
284
+ it("should return false when no data exists", async () => {
285
+ expect(authSecretStorage.isAuthenticated).toBe(false);
286
+ });
269
287
 
270
- await authSecretStorage.clear();
288
+ it("should return false for anonymous credentials", async () => {
289
+ await authSecretStorage.set({
290
+ accountID: "test123" as ID<Account>,
291
+ accountSecret:
292
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
293
+ secretSeed: new Uint8Array([1, 2, 3]),
294
+ provider: "anonymous",
295
+ });
296
+ expect(authSecretStorage.isAuthenticated).toBe(false);
297
+ });
298
+
299
+ it("should return true for non-anonymous credentials", async () => {
300
+ await authSecretStorage.set({
301
+ accountID: "test123" as ID<Account>,
302
+ accountSecret:
303
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
304
+ secretSeed: new Uint8Array([1, 2, 3]),
305
+ provider: "demo",
306
+ });
307
+ expect(authSecretStorage.isAuthenticated).toBe(true);
308
+ });
309
+
310
+ it("should return true when the provider is missing", async () => {
311
+ await authSecretStorage.set({
312
+ accountID: "test123" as ID<Account>,
313
+ accountSecret:
314
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
315
+ secretSeed: new Uint8Array([1, 2, 3]),
316
+ } as any);
317
+ expect(authSecretStorage.isAuthenticated).toBe(true);
318
+ });
319
+ });
271
320
 
272
- expect(handler).toHaveBeenCalled();
321
+ describe("clear", () => {
322
+ it("should emit update event when clearing", async () => {
323
+ await authSecretStorage.set({
324
+ accountID: "test123" as ID<Account>,
325
+ accountSecret:
326
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
327
+ provider: "passphrase",
328
+ });
329
+
330
+ const handler = vi.fn();
331
+ authSecretStorage.onUpdate(handler);
332
+
333
+ await authSecretStorage.clear();
334
+
335
+ expect(handler).toHaveBeenCalled();
336
+ });
337
+ });
338
+ });
339
+
340
+ describe("notify=false", () => {
341
+ beforeEach(() => {
342
+ kvStore.clearAll();
343
+ authSecretStorage = new AuthSecretStorage();
344
+ });
345
+
346
+ describe("set", () => {
347
+ it("should not emit update event when setting credentials", async () => {
348
+ const handler = vi.fn();
349
+ authSecretStorage.onUpdate(handler);
350
+
351
+ await authSecretStorage.set({
352
+ accountID: "test123" as ID<Account>,
353
+ accountSecret:
354
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
355
+ provider: "passphrase",
356
+ });
357
+
358
+ expect(handler).not.toHaveBeenCalled();
359
+ });
360
+ });
361
+
362
+ describe("isAuthenticated", () => {
363
+ it("should return false when no data exists", async () => {
364
+ expect(authSecretStorage.isAuthenticated).toBe(false);
365
+ });
366
+
367
+ it("should return false for anonymous credentials", async () => {
368
+ await authSecretStorage.set({
369
+ accountID: "test123" as ID<Account>,
370
+ accountSecret:
371
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
372
+ secretSeed: new Uint8Array([1, 2, 3]),
373
+ provider: "anonymous",
374
+ });
375
+ expect(authSecretStorage.isAuthenticated).toBe(false);
376
+ });
377
+
378
+ it("should return true for non-anonymous credentials", async () => {
379
+ await authSecretStorage.set({
380
+ accountID: "test123" as ID<Account>,
381
+ accountSecret:
382
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
383
+ secretSeed: new Uint8Array([1, 2, 3]),
384
+ provider: "demo",
385
+ });
386
+ expect(authSecretStorage.isAuthenticated).toBe(false);
387
+ authSecretStorage.emitUpdate({
388
+ accountID: "test123" as ID<Account>,
389
+ accountSecret:
390
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
391
+ secretSeed: new Uint8Array([1, 2, 3]),
392
+ provider: "demo",
393
+ });
394
+ expect(authSecretStorage.isAuthenticated).toBe(true);
395
+ });
396
+
397
+ it("should return true when the provider is missing", async () => {
398
+ await authSecretStorage.set({
399
+ accountID: "test123" as ID<Account>,
400
+ accountSecret:
401
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
402
+ secretSeed: new Uint8Array([1, 2, 3]),
403
+ } as any);
404
+ expect(authSecretStorage.isAuthenticated).toBe(false);
405
+ authSecretStorage.emitUpdate({
406
+ accountID: "test123" as ID<Account>,
407
+ accountSecret:
408
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
409
+ secretSeed: new Uint8Array([1, 2, 3]),
410
+ } as any);
411
+ expect(authSecretStorage.isAuthenticated).toBe(true);
412
+ });
413
+ });
414
+
415
+ describe("clear", () => {
416
+ it("should not emit update event when clearing", async () => {
417
+ await authSecretStorage.set({
418
+ accountID: "test123" as ID<Account>,
419
+ accountSecret:
420
+ "secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
421
+ provider: "passphrase",
422
+ });
423
+
424
+ const handler = vi.fn();
425
+ authSecretStorage.onUpdate(handler);
426
+
427
+ await authSecretStorage.clear();
428
+
429
+ expect(handler).not.toHaveBeenCalled();
430
+ });
273
431
  });
274
432
  });
275
433
  });
@@ -26,6 +26,7 @@ import {
26
26
  setupJazzTestSync,
27
27
  } from "../testing";
28
28
 
29
+ // @ts-ignore Typescript in VSCode doesn't like top level await
29
30
  const Crypto = await WasmCrypto.create();
30
31
 
31
32
  class TestJazzContextManager<Acc extends Account> extends JazzContextManager<
@@ -53,16 +54,20 @@ class TestJazzContextManager<Acc extends Account> extends JazzContextManager<
53
54
  AccountSchema: props.AccountSchema,
54
55
  });
55
56
 
56
- this.updateContext(props, {
57
- me: context.account,
58
- node: context.node,
59
- done: () => {
60
- context.done();
57
+ await this.updateContext(
58
+ props,
59
+ {
60
+ me: context.account,
61
+ node: context.node,
62
+ done: () => {
63
+ context.done();
64
+ },
65
+ logOut: async () => {
66
+ await context.logOut();
67
+ },
61
68
  },
62
- logOut: async () => {
63
- await context.logOut();
64
- },
65
- });
69
+ authProps,
70
+ );
66
71
  }
67
72
  }
68
73
 
@@ -199,7 +204,6 @@ describe("ContextManager", () => {
199
204
  test("the migration should be applied correctly on existing accounts ", async () => {
200
205
  class AccountRoot extends CoMap {
201
206
  value = co.string;
202
- transferredRoot = co.optional.ref(AccountRoot);
203
207
  }
204
208
 
205
209
  let lastRootId: string | undefined;
@@ -236,6 +240,48 @@ describe("ContextManager", () => {
236
240
  expect(me.root.id).toBe(lastRootId);
237
241
  });
238
242
 
243
+ test("the migration should be applied correctly on existing accounts (2)", async () => {
244
+ class AccountRoot extends CoMap {
245
+ value = co.number;
246
+ }
247
+
248
+ class CustomAccount extends Account {
249
+ root = co.ref(AccountRoot);
250
+
251
+ async migrate(this: CustomAccount) {
252
+ if (this.root === undefined) {
253
+ this.root = AccountRoot.create({
254
+ value: 1,
255
+ });
256
+ } else {
257
+ const { root } = await this.ensureLoaded({ root: {} });
258
+
259
+ root.value = 2;
260
+ }
261
+ }
262
+ }
263
+ const customManager = new TestJazzContextManager<CustomAccount>();
264
+
265
+ // Create initial anonymous context
266
+ await customManager.createContext({
267
+ AccountSchema: CustomAccount,
268
+ });
269
+
270
+ const account = (
271
+ customManager.getCurrentValue() as JazzAuthContext<CustomAccount>
272
+ ).me;
273
+
274
+ await customManager.authenticate({
275
+ accountID: account.id,
276
+ accountSecret: account._raw.core.node.account.agentSecret,
277
+ provider: "test",
278
+ });
279
+
280
+ const me = await CustomAccount.getMe().ensureLoaded({ root: {} });
281
+
282
+ expect(me.root.value).toBe(2);
283
+ });
284
+
239
285
  test("onAnonymousAccountDiscarded should work on transfering data between accounts", async () => {
240
286
  class AccountRoot extends CoMap {
241
287
  value = co.string;
package/src/types.ts CHANGED
@@ -24,6 +24,7 @@ export type JazzAuthContext<Acc extends Account> = {
24
24
  authenticate: AuthenticateAccountFunction;
25
25
  logOut: () => Promise<void>;
26
26
  done: () => void;
27
+ isAuthenticated?: boolean;
27
28
  };
28
29
 
29
30
  export type JazzGuestContext = {
@@ -32,6 +33,7 @@ export type JazzGuestContext = {
32
33
  authenticate: AuthenticateAccountFunction;
33
34
  logOut: () => void;
34
35
  done: () => void;
36
+ isAuthenticated?: boolean;
35
37
  };
36
38
 
37
39
  export type JazzContextType<Acc extends Account> =