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
@@ -9,8 +9,12 @@ var ActiveAccountContext = class {
9
9
  this.guestMode = false;
10
10
  }
11
11
  setGuestMode() {
12
+ this.activeAccount = null;
12
13
  this.guestMode = true;
13
14
  }
15
+ maybeGet() {
16
+ return this.activeAccount;
17
+ }
14
18
  get() {
15
19
  if (!this.activeAccount) {
16
20
  if (this.guestMode) {
@@ -414,128 +418,136 @@ import {
414
418
  var RegisteredSchemas = {};
415
419
 
416
420
  // src/implementation/createContext.ts
417
- var fixedCredentialsAuth = (credentials) => {
421
+ async function randomSessionProvider(accountID, crypto) {
418
422
  return {
419
- start: async () => ({
420
- type: "existing",
421
- credentials,
422
- saveCredentials: async () => {
423
- },
424
- onSuccess: () => {
425
- },
426
- onError: () => {
427
- },
428
- logOut: () => {
429
- }
430
- })
423
+ sessionID: crypto.newRandomSessionID(accountID),
424
+ sessionDone: () => {
425
+ }
431
426
  };
432
- };
433
- var ephemeralCredentialsAuth = () => {
427
+ }
428
+ async function createJazzContextFromExistingCredentials({
429
+ credentials,
430
+ peersToLoadFrom,
431
+ crypto,
432
+ AccountSchema: PropsAccountSchema,
433
+ sessionProvider,
434
+ onLogOut
435
+ }) {
436
+ const { sessionID, sessionDone } = await sessionProvider(
437
+ credentials.accountID,
438
+ crypto
439
+ );
440
+ const CurrentAccountSchema = PropsAccountSchema ?? RegisteredSchemas["Account"];
441
+ const node = await LocalNode.withLoadedAccount({
442
+ accountID: credentials.accountID,
443
+ accountSecret: credentials.secret,
444
+ sessionID,
445
+ peersToLoadFrom,
446
+ crypto
447
+ });
448
+ const account = CurrentAccountSchema.fromNode(node);
449
+ activeAccountContext.set(account);
450
+ await account.applyMigration();
434
451
  return {
435
- start: async () => ({
436
- type: "new",
437
- creationProps: { name: "Ephemeral" },
438
- saveCredentials: async () => {
439
- },
440
- onSuccess: () => {
441
- },
442
- onError: () => {
443
- },
444
- logOut: () => {
445
- }
446
- })
452
+ node,
453
+ account,
454
+ done: () => {
455
+ node.gracefulShutdown();
456
+ sessionDone();
457
+ },
458
+ logOut: async () => {
459
+ node.gracefulShutdown();
460
+ sessionDone();
461
+ await onLogOut?.();
462
+ }
447
463
  };
448
- };
449
- async function randomSessionProvider(accountID, crypto) {
464
+ }
465
+ async function createJazzContextForNewAccount({
466
+ creationProps,
467
+ initialAgentSecret,
468
+ peersToLoadFrom,
469
+ crypto,
470
+ AccountSchema: PropsAccountSchema,
471
+ onLogOut
472
+ }) {
473
+ const CurrentAccountSchema = PropsAccountSchema ?? RegisteredSchemas["Account"];
474
+ const { node } = await LocalNode.withNewlyCreatedAccount({
475
+ creationProps,
476
+ peersToLoadFrom,
477
+ crypto,
478
+ initialAgentSecret,
479
+ migration: async (rawAccount, _node, creationProps2) => {
480
+ const account2 = new CurrentAccountSchema({
481
+ fromRaw: rawAccount
482
+ });
483
+ activeAccountContext.set(account2);
484
+ await account2.applyMigration(creationProps2);
485
+ }
486
+ });
487
+ const account = CurrentAccountSchema.fromNode(node);
488
+ activeAccountContext.set(account);
450
489
  return {
451
- sessionID: crypto.newRandomSessionID(accountID),
452
- sessionDone: () => {
490
+ node,
491
+ account,
492
+ done: () => {
493
+ node.gracefulShutdown();
494
+ },
495
+ logOut: async () => {
496
+ node.gracefulShutdown();
497
+ await onLogOut?.();
453
498
  }
454
499
  };
455
500
  }
456
501
  async function createJazzContext(options) {
457
- if (!("auth" in options)) {
458
- return createAnonymousJazzContext({
502
+ const crypto = options.crypto;
503
+ let context;
504
+ const authSecretStorage = options.authSecretStorage;
505
+ await authSecretStorage.migrate();
506
+ const credentials = options.credentials ?? await authSecretStorage.get();
507
+ if (credentials && !options.newAccountProps) {
508
+ context = await createJazzContextFromExistingCredentials({
509
+ credentials: {
510
+ accountID: credentials.accountID,
511
+ secret: credentials.accountSecret
512
+ },
459
513
  peersToLoadFrom: options.peersToLoadFrom,
460
- crypto: options.crypto
461
- });
462
- }
463
- const { auth, sessionProvider, peersToLoadFrom, crypto } = options;
464
- const AccountSchema = options.AccountSchema ?? RegisteredSchemas["Account"];
465
- const authResult = await auth.start(crypto);
466
- if (authResult.type === "existing") {
467
- const { sessionID, sessionDone } = await sessionProvider(
468
- authResult.credentials.accountID,
469
- crypto
470
- );
471
- const node = await LocalNode.withLoadedAccount({
472
- accountID: authResult.credentials.accountID,
473
- accountSecret: authResult.credentials.secret,
474
- sessionID,
475
- peersToLoadFrom,
476
514
  crypto,
477
- migration: async (rawAccount, _node, creationProps) => {
478
- const account2 = new AccountSchema({
479
- fromRaw: rawAccount
480
- });
481
- activeAccountContext.set(account2);
482
- await account2.applyMigration(creationProps);
515
+ AccountSchema: options.AccountSchema,
516
+ sessionProvider: options.sessionProvider,
517
+ onLogOut: () => {
518
+ authSecretStorage.clear();
483
519
  }
484
520
  });
485
- const account = AccountSchema.fromNode(node);
486
- activeAccountContext.set(account);
487
- if (authResult.saveCredentials) {
488
- await authResult.saveCredentials({
489
- accountID: node.account.id,
490
- secret: node.account.agentSecret
491
- });
492
- }
493
- authResult.onSuccess();
494
- return {
495
- account,
496
- done: () => {
497
- node.gracefulShutdown();
498
- sessionDone();
499
- },
500
- logOut: () => {
501
- node.gracefulShutdown();
502
- sessionDone();
503
- authResult.logOut();
504
- }
521
+ authSecretStorage.emitUpdate(credentials);
522
+ } else {
523
+ const secretSeed = options.crypto.newRandomSecretSeed();
524
+ const initialAgentSecret = options.newAccountProps?.secret ?? crypto.agentSecretFromSecretSeed(secretSeed);
525
+ const creationProps = options.newAccountProps?.creationProps ?? {
526
+ name: options.defaultProfileName ?? "Anonymous user"
505
527
  };
506
- } else if (authResult.type === "new") {
507
- const { node } = await LocalNode.withNewlyCreatedAccount({
508
- creationProps: authResult.creationProps,
509
- peersToLoadFrom,
528
+ context = await createJazzContextForNewAccount({
529
+ creationProps,
530
+ initialAgentSecret,
531
+ peersToLoadFrom: options.peersToLoadFrom,
510
532
  crypto,
511
- initialAgentSecret: authResult.initialSecret,
512
- migration: async (rawAccount, _node, creationProps) => {
513
- const account2 = new AccountSchema({
514
- fromRaw: rawAccount
515
- });
516
- activeAccountContext.set(account2);
517
- await account2.applyMigration(creationProps);
533
+ AccountSchema: options.AccountSchema,
534
+ onLogOut: async () => {
535
+ await authSecretStorage.clear();
518
536
  }
519
537
  });
520
- const account = AccountSchema.fromNode(node);
521
- activeAccountContext.set(account);
522
- await authResult.saveCredentials({
523
- accountID: node.account.id,
524
- secret: node.account.agentSecret
525
- });
526
- authResult.onSuccess();
527
- return {
528
- account,
529
- done: () => {
530
- node.gracefulShutdown();
531
- },
532
- logOut: () => {
533
- node.gracefulShutdown();
534
- authResult.logOut();
535
- }
536
- };
538
+ if (!options.newAccountProps) {
539
+ await authSecretStorage.set({
540
+ accountID: context.account.id,
541
+ secretSeed,
542
+ accountSecret: context.node.account.agentSecret,
543
+ provider: "anonymous"
544
+ });
545
+ }
537
546
  }
538
- throw new Error("Invalid auth result");
547
+ return {
548
+ ...context,
549
+ authSecretStorage
550
+ };
539
551
  }
540
552
  async function createAnonymousJazzContext({
541
553
  peersToLoadFrom,
@@ -556,7 +568,7 @@ async function createAnonymousJazzContext({
556
568
  agent: new AnonymousJazzAgent(node),
557
569
  done: () => {
558
570
  },
559
- logOut: () => {
571
+ logOut: async () => {
560
572
  }
561
573
  };
562
574
  }
@@ -723,13 +735,17 @@ function loadCoValue(cls, id, as, depth) {
723
735
  );
724
736
  });
725
737
  }
726
- function ensureCoValueLoaded(existing, depth) {
727
- return loadCoValue(
738
+ async function ensureCoValueLoaded(existing, depth) {
739
+ const response = await loadCoValue(
728
740
  existing.constructor,
729
741
  existing.id,
730
742
  existing._loadedAs,
731
743
  depth
732
744
  );
745
+ if (!response) {
746
+ throw new Error("Failed to deeply load CoValue " + existing.id);
747
+ }
748
+ return response;
733
749
  }
734
750
  function subscribeToCoValueWithoutMe(cls, id, asOrDepth, depthOrListener, listener) {
735
751
  if (isAccountInstance(asOrDepth) || isAnonymousAgentInstance(asOrDepth)) {
@@ -806,7 +822,10 @@ function createCoValueObservable(options) {
806
822
  currentValue = value;
807
823
  listener();
808
824
  },
809
- onUnavailable,
825
+ () => {
826
+ currentValue = null;
827
+ onUnavailable?.();
828
+ },
810
829
  options?.syncResolution
811
830
  );
812
831
  return () => {
@@ -2699,11 +2718,9 @@ var _Group = class _Group extends CoValueBase {
2699
2718
  }
2700
2719
  addMember(member, role) {
2701
2720
  this._raw.addMember(member === "everyone" ? member : member._raw, role);
2702
- return this;
2703
2721
  }
2704
2722
  removeMember(member) {
2705
- this._raw.removeMember(member === "everyone" ? member : member._raw);
2706
- return this;
2723
+ return this._raw.removeMember(member === "everyone" ? member : member._raw);
2707
2724
  }
2708
2725
  get members() {
2709
2726
  return this._raw.keys().filter((key) => {
@@ -2727,8 +2744,8 @@ var _Group = class _Group extends CoValueBase {
2727
2744
  };
2728
2745
  });
2729
2746
  }
2730
- extend(parent) {
2731
- this._raw.extend(parent._raw);
2747
+ extend(parent, roleMapping) {
2748
+ this._raw.extend(parent._raw, roleMapping);
2732
2749
  return this;
2733
2750
  }
2734
2751
  static load(id, asOrDepth, depth) {
@@ -3378,8 +3395,433 @@ var SchemaUnion = class _SchemaUnion extends CoValueBase {
3378
3395
  }
3379
3396
  };
3380
3397
 
3381
- // src/implementation/invites.ts
3398
+ // src/auth/KvStoreContext.ts
3399
+ var KvStoreContext = class _KvStoreContext {
3400
+ constructor() {
3401
+ this.storageInstance = null;
3402
+ }
3403
+ static getInstance() {
3404
+ if (!_KvStoreContext.instance) {
3405
+ _KvStoreContext.instance = new _KvStoreContext();
3406
+ }
3407
+ return _KvStoreContext.instance;
3408
+ }
3409
+ isInitialized() {
3410
+ return this.storageInstance !== null;
3411
+ }
3412
+ initialize(store) {
3413
+ if (!this.storageInstance) {
3414
+ this.storageInstance = store;
3415
+ }
3416
+ }
3417
+ getStorage() {
3418
+ if (!this.storageInstance) {
3419
+ throw new Error("Storage instance is not initialized.");
3420
+ }
3421
+ return this.storageInstance;
3422
+ }
3423
+ };
3424
+ var KvStoreContext_default = KvStoreContext;
3425
+
3426
+ // src/auth/AuthSecretStorage.ts
3427
+ var STORAGE_KEY = "jazz-logged-in-secret";
3428
+ var AuthSecretStorage = class {
3429
+ constructor() {
3430
+ this.listeners = /* @__PURE__ */ new Set();
3431
+ this.isAuthenticated = false;
3432
+ }
3433
+ async migrate() {
3434
+ const kvStore = KvStoreContext_default.getInstance().getStorage();
3435
+ if (!await kvStore.get(STORAGE_KEY)) {
3436
+ const demoAuthSecret = await kvStore.get("demo-auth-logged-in-secret");
3437
+ if (demoAuthSecret) {
3438
+ await kvStore.set(STORAGE_KEY, demoAuthSecret);
3439
+ await kvStore.delete("demo-auth-logged-in-secret");
3440
+ }
3441
+ const clerkAuthSecret = await kvStore.get("jazz-clerk-auth");
3442
+ if (clerkAuthSecret) {
3443
+ await kvStore.set(STORAGE_KEY, clerkAuthSecret);
3444
+ await kvStore.delete("jazz-clerk-auth");
3445
+ }
3446
+ }
3447
+ }
3448
+ async get() {
3449
+ const kvStore = KvStoreContext_default.getInstance().getStorage();
3450
+ const data = await kvStore.get(STORAGE_KEY);
3451
+ if (!data) return null;
3452
+ const parsed = JSON.parse(data);
3453
+ if (!parsed.accountID || !parsed.accountSecret) {
3454
+ throw new Error("Invalid auth secret storage data");
3455
+ }
3456
+ return {
3457
+ accountID: parsed.accountID,
3458
+ secretSeed: parsed.secretSeed ? new Uint8Array(parsed.secretSeed) : void 0,
3459
+ accountSecret: parsed.accountSecret,
3460
+ provider: parsed.provider
3461
+ };
3462
+ }
3463
+ async set(payload) {
3464
+ const kvStore = KvStoreContext_default.getInstance().getStorage();
3465
+ await kvStore.set(
3466
+ STORAGE_KEY,
3467
+ JSON.stringify({
3468
+ accountID: payload.accountID,
3469
+ secretSeed: payload.secretSeed ? Array.from(payload.secretSeed) : void 0,
3470
+ accountSecret: payload.accountSecret,
3471
+ provider: payload.provider
3472
+ })
3473
+ );
3474
+ this.emitUpdate(payload);
3475
+ }
3476
+ getIsAuthenticated(data) {
3477
+ if (!data) return false;
3478
+ return data.provider !== "anonymous";
3479
+ }
3480
+ onUpdate(handler) {
3481
+ this.listeners.add(handler);
3482
+ return () => {
3483
+ this.listeners.delete(handler);
3484
+ };
3485
+ }
3486
+ emitUpdate(data) {
3487
+ const isAuthenticated = this.getIsAuthenticated(data);
3488
+ if (this.isAuthenticated === isAuthenticated) return;
3489
+ this.isAuthenticated = isAuthenticated;
3490
+ for (const listener of this.listeners) {
3491
+ listener(this.isAuthenticated);
3492
+ }
3493
+ }
3494
+ async clear() {
3495
+ const kvStore = KvStoreContext_default.getInstance().getStorage();
3496
+ await kvStore.delete(STORAGE_KEY);
3497
+ this.emitUpdate(null);
3498
+ }
3499
+ };
3500
+
3501
+ // src/auth/InMemoryKVStore.ts
3502
+ var InMemoryKVStore = class {
3503
+ constructor() {
3504
+ this.store = {};
3505
+ }
3506
+ async get(key) {
3507
+ const data = this.store[key];
3508
+ if (!data) return null;
3509
+ return data;
3510
+ }
3511
+ async set(key, value) {
3512
+ this.store[key] = value;
3513
+ }
3514
+ async delete(key) {
3515
+ delete this.store[key];
3516
+ }
3517
+ async clearAll() {
3518
+ this.store = {};
3519
+ }
3520
+ };
3521
+
3522
+ // src/implementation/ContextManager.ts
3382
3523
  import { cojsonInternals as cojsonInternals4 } from "cojson";
3524
+ var JazzContextManager = class {
3525
+ constructor() {
3526
+ this.authSecretStorage = new AuthSecretStorage();
3527
+ this.authenticating = false;
3528
+ this.logOut = async () => {
3529
+ if (!this.context || !this.props) {
3530
+ return;
3531
+ }
3532
+ await this.context.logOut();
3533
+ this.props.onLogOut?.();
3534
+ return this.createContext(this.props);
3535
+ };
3536
+ this.done = () => {
3537
+ if (!this.context) {
3538
+ return;
3539
+ }
3540
+ this.context.done();
3541
+ };
3542
+ this.authenticate = async (credentials) => {
3543
+ if (!this.props) {
3544
+ throw new Error("Props required");
3545
+ }
3546
+ const prevContext = this.context;
3547
+ const prevCredentials = await this.authSecretStorage.get();
3548
+ const wasAnonymous = this.authSecretStorage.getIsAuthenticated(prevCredentials) === false;
3549
+ this.authenticating = true;
3550
+ await this.createContext(this.props, { credentials }).finally(() => {
3551
+ this.authenticating = false;
3552
+ });
3553
+ const currentContext = this.context;
3554
+ if (prevContext && currentContext && "me" in prevContext && "me" in currentContext && wasAnonymous) {
3555
+ const [prevAccountAsPeer, currentAccountAsPeer] = cojsonInternals4.connectedPeers(
3556
+ prevContext.me.id,
3557
+ currentContext.me.id,
3558
+ {
3559
+ peer1role: "client",
3560
+ peer2role: "server"
3561
+ }
3562
+ );
3563
+ prevContext.node.syncManager.addPeer(currentAccountAsPeer);
3564
+ currentContext.node.syncManager.addPeer(prevAccountAsPeer);
3565
+ try {
3566
+ await this.props.onAnonymousAccountDiscarded?.(prevContext.me);
3567
+ await prevContext.me.waitForAllCoValuesSync();
3568
+ } catch (error) {
3569
+ console.error("Error onAnonymousAccountDiscarded", error);
3570
+ }
3571
+ prevAccountAsPeer.outgoing.close();
3572
+ currentAccountAsPeer.outgoing.close();
3573
+ }
3574
+ prevContext?.done();
3575
+ };
3576
+ this.listeners = /* @__PURE__ */ new Set();
3577
+ this.subscribe = (callback) => {
3578
+ this.listeners.add(callback);
3579
+ return () => {
3580
+ this.listeners.delete(callback);
3581
+ };
3582
+ };
3583
+ KvStoreContext.getInstance().initialize(this.getKvStore());
3584
+ }
3585
+ getKvStore() {
3586
+ return new InMemoryKVStore();
3587
+ }
3588
+ async createContext(props, authProps) {
3589
+ props;
3590
+ authProps;
3591
+ throw new Error("Not implemented");
3592
+ }
3593
+ updateContext(props, context) {
3594
+ if (!this.authenticating) {
3595
+ this.context?.done();
3596
+ }
3597
+ this.context = context;
3598
+ this.props = props;
3599
+ this.value = {
3600
+ ...context,
3601
+ node: context.node,
3602
+ authenticate: this.authenticate,
3603
+ logOut: this.logOut
3604
+ };
3605
+ this.notify();
3606
+ }
3607
+ propsChanged(props) {
3608
+ props;
3609
+ throw new Error("Not implemented");
3610
+ }
3611
+ getCurrentValue() {
3612
+ return this.value;
3613
+ }
3614
+ getAuthSecretStorage() {
3615
+ return this.authSecretStorage;
3616
+ }
3617
+ notify() {
3618
+ for (const listener of this.listeners) {
3619
+ listener();
3620
+ }
3621
+ }
3622
+ };
3623
+
3624
+ // src/auth/DemoAuth.ts
3625
+ var DemoAuth = class {
3626
+ constructor(authenticate, authSecretStorage) {
3627
+ this.authenticate = authenticate;
3628
+ this.authSecretStorage = authSecretStorage;
3629
+ this.logIn = async (username) => {
3630
+ const existingUsers = await this.getExisitingUsersWithData();
3631
+ const storageData = existingUsers[username];
3632
+ if (!storageData?.accountID) {
3633
+ throw new Error("User not found");
3634
+ }
3635
+ await this.authenticate({
3636
+ accountID: storageData.accountID,
3637
+ accountSecret: storageData.accountSecret
3638
+ });
3639
+ await this.authSecretStorage.set({
3640
+ accountID: storageData.accountID,
3641
+ accountSecret: storageData.accountSecret,
3642
+ secretSeed: storageData.secretSeed ? new Uint8Array(storageData.secretSeed) : void 0,
3643
+ provider: "demo"
3644
+ });
3645
+ };
3646
+ this.signUp = async (username) => {
3647
+ const existingUsers = await this.getExistingUsers();
3648
+ if (existingUsers.includes(username)) {
3649
+ throw new Error("User already registered");
3650
+ }
3651
+ const credentials = await this.authSecretStorage.get();
3652
+ if (!credentials) {
3653
+ throw new Error("No credentials found");
3654
+ }
3655
+ const currentAccount = await Account.getMe().ensureLoaded({
3656
+ profile: {}
3657
+ });
3658
+ currentAccount.profile.name = username;
3659
+ await this.authSecretStorage.set({
3660
+ accountID: credentials.accountID,
3661
+ accountSecret: credentials.accountSecret,
3662
+ secretSeed: credentials.secretSeed ? new Uint8Array(credentials.secretSeed) : void 0,
3663
+ provider: "demo"
3664
+ });
3665
+ await this.addToExistingUsers(username, {
3666
+ accountID: credentials.accountID,
3667
+ accountSecret: credentials.accountSecret,
3668
+ secretSeed: credentials.secretSeed ? Array.from(credentials.secretSeed) : void 0
3669
+ });
3670
+ };
3671
+ this.getExistingUsers = async () => {
3672
+ return Object.keys(await this.getExisitingUsersWithData());
3673
+ };
3674
+ }
3675
+ async addToExistingUsers(username, data) {
3676
+ const existingUsers = await this.getExisitingUsersWithData();
3677
+ if (existingUsers[username]) {
3678
+ return;
3679
+ }
3680
+ existingUsers[username] = data;
3681
+ const kvStore = KvStoreContext.getInstance().getStorage();
3682
+ await kvStore.set("demo-auth-users", JSON.stringify(existingUsers));
3683
+ }
3684
+ async getExisitingUsersWithData() {
3685
+ const kvStore = KvStoreContext.getInstance().getStorage();
3686
+ await migrateExistingUsers(kvStore);
3687
+ const existingUsers = await kvStore.get("demo-auth-users");
3688
+ return existingUsers ? JSON.parse(existingUsers) : {};
3689
+ }
3690
+ };
3691
+ function encodeUsername(username) {
3692
+ return btoa(username).replace(/=/g, "-").replace(/\+/g, "_").replace(/\//g, ".");
3693
+ }
3694
+ async function getStorageVersion(kvStore) {
3695
+ try {
3696
+ const version = await kvStore.get("demo-auth-storage-version");
3697
+ return version ? parseInt(version) : 1;
3698
+ } catch (error) {
3699
+ return 1;
3700
+ }
3701
+ }
3702
+ async function setStorageVersion(kvStore, version) {
3703
+ await kvStore.set("demo-auth-storage-version", version.toString());
3704
+ }
3705
+ async function getExistingUsersList(kvStore) {
3706
+ const existingUsers = await kvStore.get("demo-auth-existing-users");
3707
+ return existingUsers ? existingUsers.split(",") : [];
3708
+ }
3709
+ async function migrateExistingUsers(kvStore) {
3710
+ if (await getStorageVersion(kvStore) < 2) {
3711
+ const existingUsers = await getExistingUsersList(kvStore);
3712
+ for (const username of existingUsers) {
3713
+ const legacyKey = `demo-auth-existing-users-${username}`;
3714
+ const storageData = await kvStore.get(legacyKey);
3715
+ if (storageData) {
3716
+ await kvStore.set(
3717
+ `demo-auth-existing-users-${encodeUsername(username)}`,
3718
+ storageData
3719
+ );
3720
+ await kvStore.delete(legacyKey);
3721
+ }
3722
+ }
3723
+ await setStorageVersion(kvStore, 2);
3724
+ }
3725
+ if (await getStorageVersion(kvStore) < 3) {
3726
+ const existingUsersList = await getExistingUsersList(kvStore);
3727
+ const existingUsers = {};
3728
+ const keysToDelete = ["demo-auth-existing-users"];
3729
+ for (const username of existingUsersList) {
3730
+ const key = `demo-auth-existing-users-${encodeUsername(username)}`;
3731
+ const storageData = await kvStore.get(key);
3732
+ if (storageData) {
3733
+ existingUsers[username] = JSON.parse(storageData);
3734
+ keysToDelete.push(key);
3735
+ }
3736
+ }
3737
+ await kvStore.set("demo-auth-users", JSON.stringify(existingUsers));
3738
+ for (const key of keysToDelete) {
3739
+ await kvStore.delete(key);
3740
+ }
3741
+ await setStorageVersion(kvStore, 3);
3742
+ }
3743
+ }
3744
+
3745
+ // src/auth/PassphraseAuth.ts
3746
+ import * as bip39 from "@scure/bip39";
3747
+ import { entropyToMnemonic } from "@scure/bip39";
3748
+ import { cojsonInternals as cojsonInternals5 } from "cojson";
3749
+ var PassphraseAuth = class {
3750
+ constructor(crypto, authenticate, authSecretStorage, wordlist) {
3751
+ this.crypto = crypto;
3752
+ this.authenticate = authenticate;
3753
+ this.authSecretStorage = authSecretStorage;
3754
+ this.wordlist = wordlist;
3755
+ this.passphrase = "";
3756
+ this.logIn = async (passphrase) => {
3757
+ const { crypto, authenticate } = this;
3758
+ let secretSeed;
3759
+ try {
3760
+ secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);
3761
+ } catch (e) {
3762
+ throw new Error("Invalid passphrase");
3763
+ }
3764
+ const accountSecret = crypto.agentSecretFromSecretSeed(secretSeed);
3765
+ const accountID = cojsonInternals5.idforHeader(
3766
+ cojsonInternals5.accountHeaderForInitialAgentSecret(accountSecret, crypto),
3767
+ crypto
3768
+ );
3769
+ await authenticate({
3770
+ accountID,
3771
+ accountSecret
3772
+ });
3773
+ await this.authSecretStorage.set({
3774
+ accountID,
3775
+ secretSeed,
3776
+ accountSecret,
3777
+ provider: "passphrase"
3778
+ });
3779
+ this.passphrase = passphrase;
3780
+ this.notify();
3781
+ };
3782
+ this.signUp = async () => {
3783
+ const credentials = await this.authSecretStorage.get();
3784
+ if (!credentials || !credentials.secretSeed) {
3785
+ throw new Error("No credentials found");
3786
+ }
3787
+ const passphrase = entropyToMnemonic(credentials.secretSeed, this.wordlist);
3788
+ await this.authSecretStorage.set({
3789
+ accountID: credentials.accountID,
3790
+ secretSeed: credentials.secretSeed,
3791
+ accountSecret: credentials.accountSecret,
3792
+ provider: "passphrase"
3793
+ });
3794
+ return passphrase;
3795
+ };
3796
+ this.getCurrentAccountPassphrase = async () => {
3797
+ const credentials = await this.authSecretStorage.get();
3798
+ if (!credentials || !credentials.secretSeed) {
3799
+ throw new Error("No credentials found");
3800
+ }
3801
+ return entropyToMnemonic(credentials.secretSeed, this.wordlist);
3802
+ };
3803
+ this.loadCurrentAccountPassphrase = async () => {
3804
+ const passphrase = await this.getCurrentAccountPassphrase();
3805
+ this.passphrase = passphrase;
3806
+ this.notify();
3807
+ };
3808
+ this.listeners = /* @__PURE__ */ new Set();
3809
+ this.subscribe = (callback) => {
3810
+ this.listeners.add(callback);
3811
+ return () => {
3812
+ this.listeners.delete(callback);
3813
+ };
3814
+ };
3815
+ }
3816
+ notify() {
3817
+ for (const listener of this.listeners) {
3818
+ listener();
3819
+ }
3820
+ }
3821
+ };
3822
+
3823
+ // src/implementation/invites.ts
3824
+ import { cojsonInternals as cojsonInternals6 } from "cojson";
3383
3825
  function createInviteLink(value, role, baseURL, valueHint) {
3384
3826
  const coValueCore = value._raw.core;
3385
3827
  let currentCoValue = coValueCore;
@@ -3390,7 +3832,7 @@ function createInviteLink(value, role, baseURL, valueHint) {
3390
3832
  if (ruleset.type !== "group" || meta?.type === "account") {
3391
3833
  throw new Error("Can't create invite link for object without group");
3392
3834
  }
3393
- const group = cojsonInternals4.expectGroup(currentCoValue.getCurrentContent());
3835
+ const group = cojsonInternals6.expectGroup(currentCoValue.getCurrentContent());
3394
3836
  const inviteSecret = group.createInvite(role);
3395
3837
  return `${baseURL}#/invite/${valueHint ? valueHint + "/" : ""}${value.id}/${inviteSecret}`;
3396
3838
  }
@@ -3442,9 +3884,9 @@ export {
3442
3884
  createCoValueObservable,
3443
3885
  Encoders,
3444
3886
  co,
3445
- fixedCredentialsAuth,
3446
- ephemeralCredentialsAuth,
3447
3887
  randomSessionProvider,
3888
+ createJazzContextFromExistingCredentials,
3889
+ createJazzContextForNewAccount,
3448
3890
  createJazzContext,
3449
3891
  createAnonymousJazzContext,
3450
3892
  Inbox,
@@ -3462,9 +3904,15 @@ export {
3462
3904
  Marks,
3463
3905
  ImageDefinition,
3464
3906
  SchemaUnion,
3907
+ KvStoreContext,
3908
+ AuthSecretStorage,
3909
+ InMemoryKVStore,
3910
+ JazzContextManager,
3911
+ DemoAuth,
3912
+ PassphraseAuth,
3465
3913
  createInviteLink,
3466
3914
  parseInviteLink,
3467
3915
  consumeInviteLink
3468
3916
  };
3469
3917
  /* istanbul ignore file -- @preserve */
3470
- //# sourceMappingURL=chunk-OJIEP4WE.js.map
3918
+ //# sourceMappingURL=chunk-UBD75Z27.js.map