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.
- package/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +18 -0
- package/dist/{chunk-DXCQRDRG.js → chunk-TSEO4KAO.js} +56 -9
- package/dist/chunk-TSEO4KAO.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/testing.js +21 -13
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
- package/src/auth/AuthSecretStorage.ts +45 -4
- package/src/implementation/ContextManager.ts +23 -4
- package/src/implementation/createContext.ts +0 -3
- package/src/testing.ts +22 -12
- package/src/tests/AuthSecretStorage.test.ts +227 -69
- package/src/tests/ContextManager.test.ts +56 -10
- package/src/types.ts +2 -0
- package/dist/chunk-DXCQRDRG.js.map +0 -1
@@ -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(
|
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
|
-
|
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(
|
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("
|
153
|
-
|
154
|
-
|
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
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
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
|
-
|
268
|
-
|
283
|
+
describe("isAuthenticated", () => {
|
284
|
+
it("should return false when no data exists", async () => {
|
285
|
+
expect(authSecretStorage.isAuthenticated).toBe(false);
|
286
|
+
});
|
269
287
|
|
270
|
-
|
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
|
-
|
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(
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
context.
|
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
|
-
|
63
|
-
|
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> =
|