jazz-tools 0.18.5 → 0.18.6

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 (59) hide show
  1. package/.turbo/turbo-build.log +53 -53
  2. package/CHANGELOG.md +16 -0
  3. package/dist/better-auth/auth/client.d.ts.map +1 -1
  4. package/dist/better-auth/auth/client.js +7 -1
  5. package/dist/better-auth/auth/client.js.map +1 -1
  6. package/dist/better-auth/auth/react.d.ts +0 -2145
  7. package/dist/better-auth/auth/react.d.ts.map +1 -1
  8. package/dist/better-auth/auth/react.js +2 -14
  9. package/dist/better-auth/auth/react.js.map +1 -1
  10. package/dist/better-auth/auth/server.d.ts.map +1 -1
  11. package/dist/better-auth/auth/server.js +73 -22
  12. package/dist/better-auth/auth/server.js.map +1 -1
  13. package/dist/better-auth/auth/tests/react.test.d.ts +2 -0
  14. package/dist/better-auth/auth/tests/react.test.d.ts.map +1 -0
  15. package/dist/{chunk-3LE7N6TH.js → chunk-45VKEOXG.js} +123 -81
  16. package/dist/chunk-45VKEOXG.js.map +1 -0
  17. package/dist/index.js +1 -1
  18. package/dist/inspector/{custom-element-WCY6D3QJ.js → custom-element-IBHKHN27.js} +19 -69
  19. package/dist/inspector/custom-element-IBHKHN27.js.map +1 -0
  20. package/dist/inspector/index.d.ts +5 -1
  21. package/dist/inspector/index.d.ts.map +1 -1
  22. package/dist/inspector/index.js +18 -17
  23. package/dist/inspector/index.js.map +1 -1
  24. package/dist/inspector/register-custom-element.js +1 -1
  25. package/dist/inspector/viewer/new-app.d.ts +0 -3
  26. package/dist/inspector/viewer/new-app.d.ts.map +1 -1
  27. package/dist/react-core/index.js +3 -1
  28. package/dist/react-core/index.js.map +1 -1
  29. package/dist/testing.js +2 -2
  30. package/dist/testing.js.map +1 -1
  31. package/dist/tools/coValues/inbox.d.ts +5 -5
  32. package/dist/tools/coValues/inbox.d.ts.map +1 -1
  33. package/dist/worker/index.d.ts +8 -2
  34. package/dist/worker/index.d.ts.map +1 -1
  35. package/dist/worker/index.js +7 -3
  36. package/dist/worker/index.js.map +1 -1
  37. package/package.json +4 -4
  38. package/src/better-auth/auth/client.ts +8 -2
  39. package/src/better-auth/auth/react.tsx +2 -51
  40. package/src/better-auth/auth/server.ts +94 -24
  41. package/src/better-auth/auth/tests/client.test.ts +92 -4
  42. package/src/better-auth/auth/tests/react.test.tsx +43 -0
  43. package/src/better-auth/auth/tests/server.test.ts +276 -98
  44. package/src/inspector/custom-element.tsx +1 -1
  45. package/src/inspector/index.tsx +44 -0
  46. package/src/inspector/viewer/new-app.tsx +0 -18
  47. package/src/tools/coValues/inbox.ts +190 -108
  48. package/src/tools/testing.ts +1 -1
  49. package/src/tools/tests/coFeed.test.ts +33 -22
  50. package/src/tools/tests/coList.test.ts +6 -4
  51. package/src/tools/tests/coMap.test.ts +13 -5
  52. package/src/tools/tests/exportImport.test.ts +3 -1
  53. package/src/tools/tests/groupsAndAccounts.test.ts +56 -44
  54. package/src/tools/tests/inbox.test.ts +293 -31
  55. package/src/worker/index.ts +15 -5
  56. package/tsup.config.ts +1 -1
  57. package/dist/chunk-3LE7N6TH.js.map +0 -1
  58. package/dist/inspector/custom-element-WCY6D3QJ.js.map +0 -1
  59. package/src/inspector/index.ts +0 -23
package/dist/testing.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  createAnonymousJazzContext,
7
7
  createJazzContext,
8
8
  randomSessionProvider
9
- } from "./chunk-3LE7N6TH.js";
9
+ } from "./chunk-45VKEOXG.js";
10
10
 
11
11
  // src/tools/testing.ts
12
12
  import { LocalNode } from "cojson";
@@ -37,7 +37,7 @@ function getPeerConnectedToTestSyncServer() {
37
37
  Math.random().toString(),
38
38
  Math.random().toString(),
39
39
  {
40
- peer1role: "server",
40
+ peer1role: "client",
41
41
  peer2role: "server"
42
42
  }
43
43
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tools/testing.ts"],"sourcesContent":["import { LocalNode } from \"cojson\";\nimport { cojsonInternals } from \"cojson\";\nimport { PureJSCrypto } from \"cojson/dist/crypto/PureJSCrypto\";\nimport {\n Account,\n AccountClass,\n type AnonymousJazzAgent,\n AuthCredentials,\n CoValueFromRaw,\n CoreAccountSchema,\n InstanceOfSchema,\n JazzContextManager,\n JazzContextManagerAuthProps,\n JazzContextManagerBaseProps,\n activeAccountContext,\n coValueClassFromCoValueClassOrSchema,\n createAnonymousJazzContext,\n createJazzContext,\n randomSessionProvider,\n} from \"./internal.js\";\n\nconst syncServer: { current: LocalNode | null; asyncPeers: boolean } = {\n current: null,\n asyncPeers: false,\n};\n\nexport class TestJSCrypto extends PureJSCrypto {\n static async create() {\n if (\"navigator\" in globalThis && navigator.userAgent?.includes(\"jsdom\")) {\n // Mocking crypto seal & encrypt to make it work with JSDom. Getting \"Error: Uint8Array expected\" there\n const crypto = new PureJSCrypto();\n\n crypto.seal = (options) =>\n `sealed_U${cojsonInternals.stableStringify(options.message)}` as any;\n crypto.unseal = (sealed) =>\n JSON.parse(sealed.substring(\"sealed_U\".length));\n crypto.encrypt = (message) =>\n `encrypted_U${cojsonInternals.stableStringify(message)}` as any;\n crypto.decryptRaw = (encrypted) =>\n encrypted.substring(\"encrypted_U\".length) as any;\n\n return crypto;\n }\n\n // For non-jsdom environments, we use the real crypto\n return new PureJSCrypto();\n }\n}\n\nexport function getPeerConnectedToTestSyncServer() {\n if (!syncServer.current) {\n throw new Error(\"Sync server not initialized\");\n }\n\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(\n Math.random().toString(),\n Math.random().toString(),\n {\n peer1role: \"server\",\n peer2role: \"server\",\n },\n );\n\n if (syncServer.asyncPeers) {\n const push = aPeer.outgoing.push;\n\n aPeer.outgoing.push = (message) => {\n setTimeout(() => {\n push.call(aPeer.outgoing, message);\n });\n };\n\n bPeer.outgoing.push = (message) => {\n setTimeout(() => {\n push.call(bPeer.outgoing, message);\n });\n };\n }\n\n syncServer.current.syncManager.addPeer(aPeer);\n\n return bPeer;\n}\n\nconst SecretSeedMap = new Map<string, Uint8Array>();\nlet isMigrationActive = false;\n\nexport async function createJazzTestAccount<\n S extends\n | (AccountClass<Account> & CoValueFromRaw<Account>)\n | CoreAccountSchema,\n>(options?: {\n isCurrentActiveAccount?: boolean;\n AccountSchema?: S;\n creationProps?: Record<string, unknown>;\n}): Promise<InstanceOfSchema<S>> {\n const AccountClass = options?.AccountSchema\n ? coValueClassFromCoValueClassOrSchema(options.AccountSchema)\n : Account;\n const peers = [];\n if (syncServer.current) {\n peers.push(getPeerConnectedToTestSyncServer());\n }\n\n const crypto = await TestJSCrypto.create();\n const secretSeed = crypto.newRandomSecretSeed();\n\n const { node } = await LocalNode.withNewlyCreatedAccount({\n creationProps: {\n name: \"Test Account\",\n ...options?.creationProps,\n },\n initialAgentSecret: crypto.agentSecretFromSecretSeed(secretSeed),\n crypto,\n peersToLoadFrom: peers,\n migration: async (rawAccount, _node, creationProps) => {\n if (isMigrationActive) {\n throw new Error(\n \"It is not possible to create multiple accounts in parallel inside the test environment.\",\n );\n }\n\n isMigrationActive = true;\n\n // @ts-expect-error - AccountClass doesn't infer the fromRaw static method\n const account = AccountClass.fromRaw(rawAccount) as InstanceOfSchema<S>;\n\n // We need to set the account as current because the migration\n // will probably rely on the global me\n const prevActiveAccount = activeAccountContext.maybeGet();\n activeAccountContext.set(account);\n\n await account.applyMigration?.(creationProps);\n\n if (!options?.isCurrentActiveAccount) {\n activeAccountContext.set(prevActiveAccount);\n }\n\n isMigrationActive = false;\n },\n });\n\n const account = AccountClass.fromNode(node);\n SecretSeedMap.set(account.$jazz.id, secretSeed);\n\n if (options?.isCurrentActiveAccount) {\n activeAccountContext.set(account);\n }\n\n return account as InstanceOfSchema<S>;\n}\n\nexport function setActiveAccount(account: Account) {\n activeAccountContext.set(account);\n}\n\n/**\n * Run a callback without an active account.\n *\n * Takes care of restoring the active account after the callback is run.\n *\n * If the callback returns a promise, waits for it before restoring the active account.\n *\n * @param callback - The callback to run.\n * @returns The result of the callback.\n */\nexport function runWithoutActiveAccount<Result>(\n callback: () => Result,\n): Result {\n const me = Account.getMe();\n activeAccountContext.set(null);\n const result = callback();\n\n if (result instanceof Promise) {\n return result.finally(() => {\n activeAccountContext.set(me);\n return result;\n }) as Result;\n }\n\n activeAccountContext.set(me);\n return result;\n}\n\nexport async function createJazzTestGuest() {\n const ctx = await createAnonymousJazzContext({\n crypto: await PureJSCrypto.create(),\n peersToLoadFrom: [],\n });\n\n return {\n guest: ctx.agent,\n };\n}\n\nexport type TestJazzContextManagerProps<Acc extends Account> =\n JazzContextManagerBaseProps<Acc> & {\n defaultProfileName?: string;\n AccountSchema?: AccountClass<Acc> & CoValueFromRaw<Acc>;\n isAuthenticated?: boolean;\n };\n\nexport class TestJazzContextManager<\n Acc extends Account,\n> extends JazzContextManager<Acc, TestJazzContextManagerProps<Acc>> {\n static fromAccountOrGuest<Acc extends Account>(\n account?: Acc | { guest: AnonymousJazzAgent },\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n if (account && \"guest\" in account) {\n return this.fromGuest<Acc>(account, props);\n }\n\n return this.fromAccount<Acc>(account ?? (Account.getMe() as Acc), props);\n }\n\n static fromAccount<Acc extends Account>(\n account: Acc,\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n const context = new TestJazzContextManager<Acc>();\n\n const provider = props?.isAuthenticated ? \"testProvider\" : \"anonymous\";\n const storage = context.getAuthSecretStorage();\n const node = account.$jazz.localNode;\n\n const credentials = {\n accountID: account.$jazz.id,\n accountSecret: node.getCurrentAgent().agentSecret,\n secretSeed: SecretSeedMap.get(account.$jazz.id),\n provider,\n } satisfies AuthCredentials;\n\n storage.set(credentials);\n\n context.updateContext(\n {\n AccountSchema: account.constructor as AccountClass<Acc> &\n CoValueFromRaw<Acc>,\n ...props,\n },\n {\n me: account,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n await storage.clear();\n node.gracefulShutdown();\n },\n },\n {\n credentials,\n },\n );\n\n return context;\n }\n\n static fromGuest<Acc extends Account>(\n { guest }: { guest: AnonymousJazzAgent },\n props: TestJazzContextManagerProps<Acc> = {},\n ) {\n const context = new TestJazzContextManager<Acc>();\n const node = guest.node;\n\n context.updateContext(props, {\n guest,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n node.gracefulShutdown();\n },\n });\n\n return context;\n }\n\n async getNewContext(\n props: TestJazzContextManagerProps<Acc>,\n authProps?: JazzContextManagerAuthProps,\n ) {\n if (!syncServer.current) {\n throw new Error(\n \"You need to setup a test sync server with setupJazzTestSync to use the Auth functions\",\n );\n }\n\n const context = await createJazzContext({\n credentials: authProps?.credentials,\n defaultProfileName: props.defaultProfileName,\n newAccountProps: authProps?.newAccountProps,\n peersToLoadFrom: [getPeerConnectedToTestSyncServer()],\n crypto: await TestJSCrypto.create(),\n sessionProvider: randomSessionProvider,\n authSecretStorage: this.getAuthSecretStorage(),\n AccountSchema: props.AccountSchema,\n });\n\n return {\n me: context.account,\n node: context.node,\n done: () => {\n context.done();\n },\n logOut: () => {\n return context.logOut();\n },\n };\n }\n}\n\nexport async function linkAccounts(\n a: Account,\n b: Account,\n aRole: \"server\" | \"client\" = \"server\",\n bRole: \"server\" | \"client\" = \"server\",\n) {\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(\n b.$jazz.id,\n a.$jazz.id,\n {\n peer1role: aRole,\n peer2role: bRole,\n },\n );\n\n a.$jazz.localNode.syncManager.addPeer(aPeer);\n b.$jazz.localNode.syncManager.addPeer(bPeer);\n\n await a.$jazz.waitForAllCoValuesSync();\n await b.$jazz.waitForAllCoValuesSync();\n}\n\nexport async function setupJazzTestSync({\n asyncPeers = false,\n}: {\n asyncPeers?: boolean;\n} = {}) {\n if (syncServer.current) {\n syncServer.current.gracefulShutdown();\n }\n\n const account = await Account.create({\n creationProps: {\n name: \"Test Account\",\n },\n crypto: await TestJSCrypto.create(),\n });\n\n syncServer.current = account.$jazz.localNode;\n syncServer.asyncPeers = asyncPeers;\n\n return account;\n}\n"],"mappings":"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","names":["AccountClass","account"]}
1
+ {"version":3,"sources":["../src/tools/testing.ts"],"sourcesContent":["import { LocalNode } from \"cojson\";\nimport { cojsonInternals } from \"cojson\";\nimport { PureJSCrypto } from \"cojson/dist/crypto/PureJSCrypto\";\nimport {\n Account,\n AccountClass,\n type AnonymousJazzAgent,\n AuthCredentials,\n CoValueFromRaw,\n CoreAccountSchema,\n InstanceOfSchema,\n JazzContextManager,\n JazzContextManagerAuthProps,\n JazzContextManagerBaseProps,\n activeAccountContext,\n coValueClassFromCoValueClassOrSchema,\n createAnonymousJazzContext,\n createJazzContext,\n randomSessionProvider,\n} from \"./internal.js\";\n\nconst syncServer: { current: LocalNode | null; asyncPeers: boolean } = {\n current: null,\n asyncPeers: false,\n};\n\nexport class TestJSCrypto extends PureJSCrypto {\n static async create() {\n if (\"navigator\" in globalThis && navigator.userAgent?.includes(\"jsdom\")) {\n // Mocking crypto seal & encrypt to make it work with JSDom. Getting \"Error: Uint8Array expected\" there\n const crypto = new PureJSCrypto();\n\n crypto.seal = (options) =>\n `sealed_U${cojsonInternals.stableStringify(options.message)}` as any;\n crypto.unseal = (sealed) =>\n JSON.parse(sealed.substring(\"sealed_U\".length));\n crypto.encrypt = (message) =>\n `encrypted_U${cojsonInternals.stableStringify(message)}` as any;\n crypto.decryptRaw = (encrypted) =>\n encrypted.substring(\"encrypted_U\".length) as any;\n\n return crypto;\n }\n\n // For non-jsdom environments, we use the real crypto\n return new PureJSCrypto();\n }\n}\n\nexport function getPeerConnectedToTestSyncServer() {\n if (!syncServer.current) {\n throw new Error(\"Sync server not initialized\");\n }\n\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(\n Math.random().toString(),\n Math.random().toString(),\n {\n peer1role: \"client\",\n peer2role: \"server\",\n },\n );\n\n if (syncServer.asyncPeers) {\n const push = aPeer.outgoing.push;\n\n aPeer.outgoing.push = (message) => {\n setTimeout(() => {\n push.call(aPeer.outgoing, message);\n });\n };\n\n bPeer.outgoing.push = (message) => {\n setTimeout(() => {\n push.call(bPeer.outgoing, message);\n });\n };\n }\n\n syncServer.current.syncManager.addPeer(aPeer);\n\n return bPeer;\n}\n\nconst SecretSeedMap = new Map<string, Uint8Array>();\nlet isMigrationActive = false;\n\nexport async function createJazzTestAccount<\n S extends\n | (AccountClass<Account> & CoValueFromRaw<Account>)\n | CoreAccountSchema,\n>(options?: {\n isCurrentActiveAccount?: boolean;\n AccountSchema?: S;\n creationProps?: Record<string, unknown>;\n}): Promise<InstanceOfSchema<S>> {\n const AccountClass = options?.AccountSchema\n ? coValueClassFromCoValueClassOrSchema(options.AccountSchema)\n : Account;\n const peers = [];\n if (syncServer.current) {\n peers.push(getPeerConnectedToTestSyncServer());\n }\n\n const crypto = await TestJSCrypto.create();\n const secretSeed = crypto.newRandomSecretSeed();\n\n const { node } = await LocalNode.withNewlyCreatedAccount({\n creationProps: {\n name: \"Test Account\",\n ...options?.creationProps,\n },\n initialAgentSecret: crypto.agentSecretFromSecretSeed(secretSeed),\n crypto,\n peersToLoadFrom: peers,\n migration: async (rawAccount, _node, creationProps) => {\n if (isMigrationActive) {\n throw new Error(\n \"It is not possible to create multiple accounts in parallel inside the test environment.\",\n );\n }\n\n isMigrationActive = true;\n\n // @ts-expect-error - AccountClass doesn't infer the fromRaw static method\n const account = AccountClass.fromRaw(rawAccount) as InstanceOfSchema<S>;\n\n // We need to set the account as current because the migration\n // will probably rely on the global me\n const prevActiveAccount = activeAccountContext.maybeGet();\n activeAccountContext.set(account);\n\n await account.applyMigration?.(creationProps);\n\n if (!options?.isCurrentActiveAccount) {\n activeAccountContext.set(prevActiveAccount);\n }\n\n isMigrationActive = false;\n },\n });\n\n const account = AccountClass.fromNode(node);\n SecretSeedMap.set(account.$jazz.id, secretSeed);\n\n if (options?.isCurrentActiveAccount) {\n activeAccountContext.set(account);\n }\n\n return account as InstanceOfSchema<S>;\n}\n\nexport function setActiveAccount(account: Account) {\n activeAccountContext.set(account);\n}\n\n/**\n * Run a callback without an active account.\n *\n * Takes care of restoring the active account after the callback is run.\n *\n * If the callback returns a promise, waits for it before restoring the active account.\n *\n * @param callback - The callback to run.\n * @returns The result of the callback.\n */\nexport function runWithoutActiveAccount<Result>(\n callback: () => Result,\n): Result {\n const me = Account.getMe();\n activeAccountContext.set(null);\n const result = callback();\n\n if (result instanceof Promise) {\n return result.finally(() => {\n activeAccountContext.set(me);\n return result;\n }) as Result;\n }\n\n activeAccountContext.set(me);\n return result;\n}\n\nexport async function createJazzTestGuest() {\n const ctx = await createAnonymousJazzContext({\n crypto: await PureJSCrypto.create(),\n peersToLoadFrom: [],\n });\n\n return {\n guest: ctx.agent,\n };\n}\n\nexport type TestJazzContextManagerProps<Acc extends Account> =\n JazzContextManagerBaseProps<Acc> & {\n defaultProfileName?: string;\n AccountSchema?: AccountClass<Acc> & CoValueFromRaw<Acc>;\n isAuthenticated?: boolean;\n };\n\nexport class TestJazzContextManager<\n Acc extends Account,\n> extends JazzContextManager<Acc, TestJazzContextManagerProps<Acc>> {\n static fromAccountOrGuest<Acc extends Account>(\n account?: Acc | { guest: AnonymousJazzAgent },\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n if (account && \"guest\" in account) {\n return this.fromGuest<Acc>(account, props);\n }\n\n return this.fromAccount<Acc>(account ?? (Account.getMe() as Acc), props);\n }\n\n static fromAccount<Acc extends Account>(\n account: Acc,\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n const context = new TestJazzContextManager<Acc>();\n\n const provider = props?.isAuthenticated ? \"testProvider\" : \"anonymous\";\n const storage = context.getAuthSecretStorage();\n const node = account.$jazz.localNode;\n\n const credentials = {\n accountID: account.$jazz.id,\n accountSecret: node.getCurrentAgent().agentSecret,\n secretSeed: SecretSeedMap.get(account.$jazz.id),\n provider,\n } satisfies AuthCredentials;\n\n storage.set(credentials);\n\n context.updateContext(\n {\n AccountSchema: account.constructor as AccountClass<Acc> &\n CoValueFromRaw<Acc>,\n ...props,\n },\n {\n me: account,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n await storage.clear();\n node.gracefulShutdown();\n },\n },\n {\n credentials,\n },\n );\n\n return context;\n }\n\n static fromGuest<Acc extends Account>(\n { guest }: { guest: AnonymousJazzAgent },\n props: TestJazzContextManagerProps<Acc> = {},\n ) {\n const context = new TestJazzContextManager<Acc>();\n const node = guest.node;\n\n context.updateContext(props, {\n guest,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n node.gracefulShutdown();\n },\n });\n\n return context;\n }\n\n async getNewContext(\n props: TestJazzContextManagerProps<Acc>,\n authProps?: JazzContextManagerAuthProps,\n ) {\n if (!syncServer.current) {\n throw new Error(\n \"You need to setup a test sync server with setupJazzTestSync to use the Auth functions\",\n );\n }\n\n const context = await createJazzContext({\n credentials: authProps?.credentials,\n defaultProfileName: props.defaultProfileName,\n newAccountProps: authProps?.newAccountProps,\n peersToLoadFrom: [getPeerConnectedToTestSyncServer()],\n crypto: await TestJSCrypto.create(),\n sessionProvider: randomSessionProvider,\n authSecretStorage: this.getAuthSecretStorage(),\n AccountSchema: props.AccountSchema,\n });\n\n return {\n me: context.account,\n node: context.node,\n done: () => {\n context.done();\n },\n logOut: () => {\n return context.logOut();\n },\n };\n }\n}\n\nexport async function linkAccounts(\n a: Account,\n b: Account,\n aRole: \"server\" | \"client\" = \"server\",\n bRole: \"server\" | \"client\" = \"server\",\n) {\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(\n b.$jazz.id,\n a.$jazz.id,\n {\n peer1role: aRole,\n peer2role: bRole,\n },\n );\n\n a.$jazz.localNode.syncManager.addPeer(aPeer);\n b.$jazz.localNode.syncManager.addPeer(bPeer);\n\n await a.$jazz.waitForAllCoValuesSync();\n await b.$jazz.waitForAllCoValuesSync();\n}\n\nexport async function setupJazzTestSync({\n asyncPeers = false,\n}: {\n asyncPeers?: boolean;\n} = {}) {\n if (syncServer.current) {\n syncServer.current.gracefulShutdown();\n }\n\n const account = await Account.create({\n creationProps: {\n name: \"Test Account\",\n },\n crypto: await TestJSCrypto.create(),\n });\n\n syncServer.current = account.$jazz.localNode;\n syncServer.asyncPeers = asyncPeers;\n\n return account;\n}\n"],"mappings":"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","names":["AccountClass","account"]}
@@ -1,13 +1,14 @@
1
1
  import { CoID, InviteSecret, RawAccount, RawCoMap, SessionID } from "cojson";
2
- import { RawCoStream } from "cojson";
2
+ import { type RawCoStream } from "cojson";
3
3
  import { type Account, CoValue, CoValueClassOrSchema, ID, InstanceOfSchema } from "../internal.js";
4
4
  export type InboxInvite = `${CoID<MessagesStream>}/${InviteSecret}`;
5
5
  type TxKey = `${SessionID}/${number}`;
6
6
  type MessagesStream = RawCoStream<CoID<InboxMessage<CoValue, any>>>;
7
- type FailedMessagesStream = RawCoStream<{
7
+ type FailedMessagesStreamItem = {
8
8
  errors: string[];
9
9
  value: CoID<InboxMessage<CoValue, any>>;
10
- }>;
10
+ };
11
+ type FailedMessagesStream = RawCoStream<FailedMessagesStreamItem>;
11
12
  type TxKeyStream = RawCoStream<TxKey>;
12
13
  export type InboxRoot = RawCoMap<{
13
14
  messages: CoID<MessagesStream>;
@@ -31,10 +32,9 @@ export declare class Inbox {
31
32
  processed: TxKeyStream;
32
33
  failed: FailedMessagesStream;
33
34
  root: InboxRoot;
34
- processing: Set<`${import("cojson").RawAccountID}_session_z${string}/${number}` | `sealer_z${string}/signer_z${string}_session_z${string}/${number}`>;
35
35
  private constructor();
36
36
  subscribe<M extends CoValueClassOrSchema, O extends CoValue | undefined>(Schema: M, callback: (message: InstanceOfSchema<M>, senderAccountID: ID<Account>) => Promise<O | undefined | void>, options?: {
37
- retries?: number;
37
+ concurrencyLimit?: number;
38
38
  }): () => void;
39
39
  static load(account: Account): Promise<Inbox>;
40
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../../src/tools/coValues/inbox.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../../src/tools/coValues/inbox.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { CryptoProvider } from "cojson";
2
2
  import { type AnyWebSocketConstructor } from "cojson-transport-ws";
3
- import { Account, AccountClass, AnyAccountSchema, CoValueFromRaw, Inbox, InstanceOfSchema } from "jazz-tools";
3
+ import { Account, AccountClass, AnyAccountSchema, CoValueFromRaw, Inbox, Loaded } from "jazz-tools";
4
4
  type WorkerOptions<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema> = {
5
5
  accountID?: string;
6
6
  accountSecret?: string;
@@ -8,13 +8,19 @@ type WorkerOptions<S extends (AccountClass<Account> & CoValueFromRaw<Account>) |
8
8
  WebSocket?: AnyWebSocketConstructor;
9
9
  AccountSchema?: S;
10
10
  crypto?: CryptoProvider;
11
+ /**
12
+ * If true, the inbox will not be loaded.
13
+ */
14
+ skipInboxLoad?: boolean;
11
15
  };
12
16
  /** @category Context Creation */
13
17
  export declare function startWorker<S extends (AccountClass<Account> & CoValueFromRaw<Account>) | AnyAccountSchema>(options: WorkerOptions<S>): Promise<{
14
- worker: InstanceOfSchema<S>;
18
+ worker: Loaded<S>;
15
19
  experimental: {
16
20
  inbox: {
17
21
  subscribe: Inbox["subscribe"];
22
+ } | {
23
+ subscribe: () => void;
18
24
  };
19
25
  };
20
26
  waitForConnection(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,cAAc,EAAmB,MAAM,QAAQ,CAAC;AACtE,OAAO,EACL,KAAK,uBAAuB,EAE7B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,OAAO,EACP,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,KAAK,EACL,gBAAgB,EAGjB,MAAM,YAAY,CAAC;AAEpB,KAAK,aAAa,CAChB,CAAC,SACG,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,GACjD,gBAAgB,IAClB;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,uBAAuB,CAAC;IACpC,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB,CAAC;AAEF,iCAAiC;AACjC,wBAAsB,WAAW,CAC/B,CAAC,SACG,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,GACjD,gBAAgB,EACpB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;YA0EI,gBAAgB,CAAC,CAAC,CAAC;;;uBAJJ,KAAK,CAAC,WAAW,CAAC;;;;0CAWtB,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI;;GASrE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,cAAc,EAAmB,MAAM,QAAQ,CAAC;AACtE,OAAO,EACL,KAAK,uBAAuB,EAE7B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,OAAO,EACP,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,KAAK,EAEL,MAAM,EAGP,MAAM,YAAY,CAAC;AAEpB,KAAK,aAAa,CAChB,CAAC,SACG,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,GACjD,gBAAgB,IAClB;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,uBAAuB,CAAC;IACpC,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,iCAAiC;AACjC,wBAAsB,WAAW,CAC/B,CAAC,SACG,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,GACjD,gBAAgB,EACpB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;YA+EI,MAAM,CAAC,CAAC,CAAC;;;uBAPU,KAAK,CAAC,WAAW,CAAC;;;;;;0CAc1B,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI;;GASrE"}
@@ -14,7 +14,8 @@ async function startWorker(options) {
14
14
  accountID = process.env.JAZZ_WORKER_ACCOUNT,
15
15
  accountSecret = process.env.JAZZ_WORKER_SECRET,
16
16
  syncServer = "wss://cloud.jazz.tools",
17
- AccountSchema = Account
17
+ AccountSchema = Account,
18
+ skipInboxLoad = false
18
19
  } = options;
19
20
  let node = void 0;
20
21
  const peersToLoadFrom = [];
@@ -61,14 +62,17 @@ async function startWorker(options) {
61
62
  if (!account.$jazz.refs.profile?.id) {
62
63
  throw new Error("Account has no profile");
63
64
  }
64
- const inbox = await Inbox.load(account);
65
+ const inbox = skipInboxLoad ? void 0 : await Inbox.load(account);
65
66
  async function done() {
66
67
  await context.account.$jazz.waitForAllCoValuesSync();
67
68
  wsPeer.disable();
68
69
  context.done();
69
70
  }
70
- const inboxPublicApi = {
71
+ const inboxPublicApi = inbox ? {
71
72
  subscribe: inbox.subscribe.bind(inbox)
73
+ } : {
74
+ subscribe: () => {
75
+ }
72
76
  };
73
77
  return {
74
78
  worker: context.account,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/worker/index.ts"],"sourcesContent":["import { AgentSecret, CryptoProvider, LocalNode, Peer } from \"cojson\";\nimport {\n type AnyWebSocketConstructor,\n WebSocketPeerWithReconnection,\n} from \"cojson-transport-ws\";\nimport { WasmCrypto } from \"cojson/crypto/WasmCrypto\";\nimport {\n Account,\n AccountClass,\n AnyAccountSchema,\n CoValueFromRaw,\n Inbox,\n InstanceOfSchema,\n createJazzContextFromExistingCredentials,\n randomSessionProvider,\n} from \"jazz-tools\";\n\ntype WorkerOptions<\n S extends\n | (AccountClass<Account> & CoValueFromRaw<Account>)\n | AnyAccountSchema,\n> = {\n accountID?: string;\n accountSecret?: string;\n syncServer?: string;\n WebSocket?: AnyWebSocketConstructor;\n AccountSchema?: S;\n crypto?: CryptoProvider;\n};\n\n/** @category Context Creation */\nexport async function startWorker<\n S extends\n | (AccountClass<Account> & CoValueFromRaw<Account>)\n | AnyAccountSchema,\n>(options: WorkerOptions<S>) {\n const {\n accountID = process.env.JAZZ_WORKER_ACCOUNT,\n accountSecret = process.env.JAZZ_WORKER_SECRET,\n syncServer = \"wss://cloud.jazz.tools\",\n AccountSchema = Account as unknown as S,\n } = options;\n\n let node: LocalNode | undefined = undefined;\n\n const peersToLoadFrom: Peer[] = [];\n\n const wsPeer = new WebSocketPeerWithReconnection({\n peer: syncServer,\n reconnectionTimeout: 100,\n addPeer: (peer) => {\n if (node) {\n node.syncManager.addPeer(peer);\n } else {\n peersToLoadFrom.push(peer);\n }\n },\n removePeer: () => {},\n WebSocketConstructor: options.WebSocket,\n });\n\n wsPeer.enable();\n\n if (!accountID) {\n throw new Error(\"No accountID provided\");\n }\n if (!accountSecret) {\n throw new Error(\"No accountSecret provided\");\n }\n if (!accountID.startsWith(\"co_\")) {\n throw new Error(\"Invalid accountID\");\n }\n if (!accountSecret?.startsWith(\"sealerSecret_\")) {\n throw new Error(\"Invalid accountSecret\");\n }\n\n const context = await createJazzContextFromExistingCredentials({\n credentials: {\n accountID: accountID,\n secret: accountSecret as AgentSecret,\n },\n AccountSchema,\n // TODO: locked sessions similar to browser\n sessionProvider: randomSessionProvider,\n peersToLoadFrom,\n crypto: options.crypto ?? (await WasmCrypto.create()),\n });\n\n const account = context.account as InstanceOfSchema<S>;\n node = account.$jazz.localNode;\n\n if (!account.$jazz.refs.profile?.id) {\n throw new Error(\"Account has no profile\");\n }\n\n const inbox = await Inbox.load(account);\n\n async function done() {\n await context.account.$jazz.waitForAllCoValuesSync();\n\n wsPeer.disable();\n context.done();\n }\n\n const inboxPublicApi = {\n subscribe: inbox.subscribe.bind(inbox) as Inbox[\"subscribe\"],\n };\n\n return {\n worker: context.account as InstanceOfSchema<S>,\n experimental: {\n inbox: inboxPublicApi,\n },\n waitForConnection() {\n return wsPeer.waitUntilConnected();\n },\n subscribeToConnectionChange(listener: (connected: boolean) => void) {\n wsPeer.subscribe(listener);\n\n return () => {\n wsPeer.unsubscribe(listener);\n };\n },\n done,\n };\n}\n"],"mappings":";AACA;AAAA,EAEE;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EAIA;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AAgBP,eAAsB,YAIpB,SAA2B;AAC3B,QAAM;AAAA,IACJ,YAAY,QAAQ,IAAI;AAAA,IACxB,gBAAgB,QAAQ,IAAI;AAAA,IAC5B,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB,IAAI;AAEJ,MAAI,OAA8B;AAElC,QAAM,kBAA0B,CAAC;AAEjC,QAAM,SAAS,IAAI,8BAA8B;AAAA,IAC/C,MAAM;AAAA,IACN,qBAAqB;AAAA,IACrB,SAAS,CAAC,SAAS;AACjB,UAAI,MAAM;AACR,aAAK,YAAY,QAAQ,IAAI;AAAA,MAC/B,OAAO;AACL,wBAAgB,KAAK,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,YAAY,MAAM;AAAA,IAAC;AAAA,IACnB,sBAAsB,QAAQ;AAAA,EAChC,CAAC;AAED,SAAO,OAAO;AAEd,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AACA,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,MAAI,CAAC,UAAU,WAAW,KAAK,GAAG;AAChC,UAAM,IAAI,MAAM,mBAAmB;AAAA,EACrC;AACA,MAAI,CAAC,eAAe,WAAW,eAAe,GAAG;AAC/C,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AAEA,QAAM,UAAU,MAAM,yCAAyC;AAAA,IAC7D,aAAa;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,IACA;AAAA;AAAA,IAEA,iBAAiB;AAAA,IACjB;AAAA,IACA,QAAQ,QAAQ,UAAW,MAAM,WAAW,OAAO;AAAA,EACrD,CAAC;AAED,QAAM,UAAU,QAAQ;AACxB,SAAO,QAAQ,MAAM;AAErB,MAAI,CAAC,QAAQ,MAAM,KAAK,SAAS,IAAI;AACnC,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,QAAM,QAAQ,MAAM,MAAM,KAAK,OAAO;AAEtC,iBAAe,OAAO;AACpB,UAAM,QAAQ,QAAQ,MAAM,uBAAuB;AAEnD,WAAO,QAAQ;AACf,YAAQ,KAAK;AAAA,EACf;AAEA,QAAM,iBAAiB;AAAA,IACrB,WAAW,MAAM,UAAU,KAAK,KAAK;AAAA,EACvC;AAEA,SAAO;AAAA,IACL,QAAQ,QAAQ;AAAA,IAChB,cAAc;AAAA,MACZ,OAAO;AAAA,IACT;AAAA,IACA,oBAAoB;AAClB,aAAO,OAAO,mBAAmB;AAAA,IACnC;AAAA,IACA,4BAA4B,UAAwC;AAClE,aAAO,UAAU,QAAQ;AAEzB,aAAO,MAAM;AACX,eAAO,YAAY,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/worker/index.ts"],"sourcesContent":["import { AgentSecret, CryptoProvider, LocalNode, Peer } from \"cojson\";\nimport {\n type AnyWebSocketConstructor,\n WebSocketPeerWithReconnection,\n} from \"cojson-transport-ws\";\nimport { WasmCrypto } from \"cojson/crypto/WasmCrypto\";\nimport {\n Account,\n AccountClass,\n AnyAccountSchema,\n CoValueFromRaw,\n Inbox,\n InstanceOfSchema,\n Loaded,\n createJazzContextFromExistingCredentials,\n randomSessionProvider,\n} from \"jazz-tools\";\n\ntype WorkerOptions<\n S extends\n | (AccountClass<Account> & CoValueFromRaw<Account>)\n | AnyAccountSchema,\n> = {\n accountID?: string;\n accountSecret?: string;\n syncServer?: string;\n WebSocket?: AnyWebSocketConstructor;\n AccountSchema?: S;\n crypto?: CryptoProvider;\n /**\n * If true, the inbox will not be loaded.\n */\n skipInboxLoad?: boolean;\n};\n\n/** @category Context Creation */\nexport async function startWorker<\n S extends\n | (AccountClass<Account> & CoValueFromRaw<Account>)\n | AnyAccountSchema,\n>(options: WorkerOptions<S>) {\n const {\n accountID = process.env.JAZZ_WORKER_ACCOUNT,\n accountSecret = process.env.JAZZ_WORKER_SECRET,\n syncServer = \"wss://cloud.jazz.tools\",\n AccountSchema = Account as unknown as S,\n skipInboxLoad = false,\n } = options;\n\n let node: LocalNode | undefined = undefined;\n\n const peersToLoadFrom: Peer[] = [];\n\n const wsPeer = new WebSocketPeerWithReconnection({\n peer: syncServer,\n reconnectionTimeout: 100,\n addPeer: (peer) => {\n if (node) {\n node.syncManager.addPeer(peer);\n } else {\n peersToLoadFrom.push(peer);\n }\n },\n removePeer: () => {},\n WebSocketConstructor: options.WebSocket,\n });\n\n wsPeer.enable();\n\n if (!accountID) {\n throw new Error(\"No accountID provided\");\n }\n if (!accountSecret) {\n throw new Error(\"No accountSecret provided\");\n }\n if (!accountID.startsWith(\"co_\")) {\n throw new Error(\"Invalid accountID\");\n }\n if (!accountSecret?.startsWith(\"sealerSecret_\")) {\n throw new Error(\"Invalid accountSecret\");\n }\n\n const context = await createJazzContextFromExistingCredentials({\n credentials: {\n accountID: accountID,\n secret: accountSecret as AgentSecret,\n },\n AccountSchema,\n // TODO: locked sessions similar to browser\n sessionProvider: randomSessionProvider,\n peersToLoadFrom,\n crypto: options.crypto ?? (await WasmCrypto.create()),\n });\n\n const account = context.account as InstanceOfSchema<S>;\n node = account.$jazz.localNode;\n\n if (!account.$jazz.refs.profile?.id) {\n throw new Error(\"Account has no profile\");\n }\n\n const inbox = skipInboxLoad ? undefined : await Inbox.load(account);\n\n async function done() {\n await context.account.$jazz.waitForAllCoValuesSync();\n\n wsPeer.disable();\n context.done();\n }\n\n const inboxPublicApi = inbox\n ? {\n subscribe: inbox.subscribe.bind(inbox) as Inbox[\"subscribe\"],\n }\n : {\n subscribe: () => {},\n };\n\n return {\n worker: context.account as Loaded<S>,\n experimental: {\n inbox: inboxPublicApi,\n },\n waitForConnection() {\n return wsPeer.waitUntilConnected();\n },\n subscribeToConnectionChange(listener: (connected: boolean) => void) {\n wsPeer.subscribe(listener);\n\n return () => {\n wsPeer.unsubscribe(listener);\n };\n },\n done,\n };\n}\n"],"mappings":";AACA;AAAA,EAEE;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EAIA;AAAA,EAGA;AAAA,EACA;AAAA,OACK;AAoBP,eAAsB,YAIpB,SAA2B;AAC3B,QAAM;AAAA,IACJ,YAAY,QAAQ,IAAI;AAAA,IACxB,gBAAgB,QAAQ,IAAI;AAAA,IAC5B,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB,IAAI;AAEJ,MAAI,OAA8B;AAElC,QAAM,kBAA0B,CAAC;AAEjC,QAAM,SAAS,IAAI,8BAA8B;AAAA,IAC/C,MAAM;AAAA,IACN,qBAAqB;AAAA,IACrB,SAAS,CAAC,SAAS;AACjB,UAAI,MAAM;AACR,aAAK,YAAY,QAAQ,IAAI;AAAA,MAC/B,OAAO;AACL,wBAAgB,KAAK,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,YAAY,MAAM;AAAA,IAAC;AAAA,IACnB,sBAAsB,QAAQ;AAAA,EAChC,CAAC;AAED,SAAO,OAAO;AAEd,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AACA,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,MAAI,CAAC,UAAU,WAAW,KAAK,GAAG;AAChC,UAAM,IAAI,MAAM,mBAAmB;AAAA,EACrC;AACA,MAAI,CAAC,eAAe,WAAW,eAAe,GAAG;AAC/C,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AAEA,QAAM,UAAU,MAAM,yCAAyC;AAAA,IAC7D,aAAa;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,IACA;AAAA;AAAA,IAEA,iBAAiB;AAAA,IACjB;AAAA,IACA,QAAQ,QAAQ,UAAW,MAAM,WAAW,OAAO;AAAA,EACrD,CAAC;AAED,QAAM,UAAU,QAAQ;AACxB,SAAO,QAAQ,MAAM;AAErB,MAAI,CAAC,QAAQ,MAAM,KAAK,SAAS,IAAI;AACnC,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,QAAM,QAAQ,gBAAgB,SAAY,MAAM,MAAM,KAAK,OAAO;AAElE,iBAAe,OAAO;AACpB,UAAM,QAAQ,QAAQ,MAAM,uBAAuB;AAEnD,WAAO,QAAQ;AACf,YAAQ,KAAK;AAAA,EACf;AAEA,QAAM,iBAAiB,QACnB;AAAA,IACE,WAAW,MAAM,UAAU,KAAK,KAAK;AAAA,EACvC,IACA;AAAA,IACE,WAAW,MAAM;AAAA,IAAC;AAAA,EACpB;AAEJ,SAAO;AAAA,IACL,QAAQ,QAAQ;AAAA,IAChB,cAAc;AAAA,MACZ,OAAO;AAAA,IACT;AAAA,IACA,oBAAoB;AAClB,aAAO,OAAO,mBAAmB;AAAA,IACnC;AAAA,IACA,4BAA4B,UAAwC;AAClE,aAAO,UAAU,QAAQ;AAEzB,aAAO,MAAM;AACX,eAAO,YAAY,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -167,7 +167,7 @@
167
167
  },
168
168
  "type": "module",
169
169
  "license": "MIT",
170
- "version": "0.18.5",
170
+ "version": "0.18.6",
171
171
  "dependencies": {
172
172
  "@manuscripts/prosemirror-recreate-steps": "^0.1.4",
173
173
  "@scure/base": "1.2.1",
@@ -183,9 +183,9 @@
183
183
  "prosemirror-state": "^1.4.3",
184
184
  "prosemirror-transform": "^1.9.0",
185
185
  "zod": "3.25.76",
186
- "cojson": "0.18.5",
187
- "cojson-storage-indexeddb": "0.18.5",
188
- "cojson-transport-ws": "0.18.5"
186
+ "cojson": "0.18.6",
187
+ "cojson-storage-indexeddb": "0.18.6",
188
+ "cojson-transport-ws": "0.18.6"
189
189
  },
190
190
  "devDependencies": {
191
191
  "@scure/bip39": "^1.3.0",
@@ -7,6 +7,13 @@ import type {
7
7
  } from "jazz-tools";
8
8
  import type { jazzPlugin } from "./server.js";
9
9
 
10
+ const SIGNUP_URLS = [
11
+ "/sign-up",
12
+ "/sign-in/social",
13
+ "/sign-in/oauth2",
14
+ "/email-otp/send-verification-otp",
15
+ ];
16
+
10
17
  /**
11
18
  * @example
12
19
  * ```ts
@@ -83,8 +90,7 @@ export const jazzPluginClient = () => {
83
90
  hooks: {
84
91
  async onRequest(context) {
85
92
  if (
86
- context.url.toString().includes("/sign-up") ||
87
- context.url.toString().includes("/sign-in/social")
93
+ SIGNUP_URLS.some((url) => context.url.toString().includes(url))
88
94
  ) {
89
95
  const credentials = await authSecretStorage.get();
90
96
 
@@ -1,21 +1,9 @@
1
1
  "use client";
2
2
 
3
- import type { ClientOptions } from "better-auth";
4
3
  import { createAuthClient } from "better-auth/client";
5
- import type {
6
- Account,
7
- AccountClass,
8
- AnyAccountSchema,
9
- CoValueFromRaw,
10
- } from "jazz-tools";
11
- import {
12
- type JazzProviderProps,
13
- JazzReactProvider,
14
- useAuthSecretStorage,
15
- useJazzContext,
16
- } from "jazz-tools/react";
4
+ import { useAuthSecretStorage, useJazzContext } from "jazz-tools/react-core";
17
5
  import { useEffect } from "react";
18
- import { type PropsWithChildren, createContext } from "react";
6
+ import { type PropsWithChildren } from "react";
19
7
  import { jazzPluginClient } from "./client.js";
20
8
 
21
9
  type AuthClient = ReturnType<
@@ -24,8 +12,6 @@ type AuthClient = ReturnType<
24
12
  }>
25
13
  >;
26
14
 
27
- export const AuthContext = createContext<AuthClient | null>(null);
28
-
29
15
  /**
30
16
  * @param props.children - The children to render.
31
17
  * @param props.betterAuthClient - The BetterAuth client with the Jazz plugin.
@@ -68,38 +54,3 @@ export function AuthProvider({
68
54
 
69
55
  return children;
70
56
  }
71
-
72
- /**
73
- * @param props - The props for the JazzReactProvider.
74
- * @param props.betterAuth - The options for the BetterAuth client.
75
- * @returns The JazzReactProvider with the BetterAuth plugin.
76
- *
77
- * @example
78
- * ```ts
79
- * <JazzReactProviderWithBetterAuth
80
- * betterAuth={{
81
- * baseURL: "http://localhost:3000",
82
- * }}
83
- * sync={{
84
- * peer: "ws://localhost:4200",
85
- * }}
86
- * >
87
- * <App />
88
- * </JazzReactProviderWithBetterAuth>
89
- * ```
90
- */
91
- export const JazzReactProviderWithBetterAuth = <
92
- S extends
93
- | (AccountClass<Account> & CoValueFromRaw<Account>)
94
- | AnyAccountSchema,
95
- >(
96
- props: { betterAuthClient: AuthClient } & JazzProviderProps<S>,
97
- ) => {
98
- return (
99
- <JazzReactProvider {...props}>
100
- <AuthProvider betterAuthClient={props.betterAuthClient}>
101
- {props.children}
102
- </AuthProvider>
103
- </JazzReactProvider>
104
- );
105
- };
@@ -85,20 +85,23 @@ export const jazzPlugin: () => JazzPlugin = () => {
85
85
  },
86
86
  verification: {
87
87
  create: {
88
- before: async (verification, context) => {
89
- // If a jazzAuth is provided, save it for later usage.
90
- if (contextContainsJazzAuth(context)) {
91
- const parsed = JSON.parse(verification.value);
92
- const newValue = JSON.stringify({
93
- ...parsed,
94
- jazzAuth: context.jazzAuth,
95
- });
96
-
97
- return {
98
- data: {
99
- value: newValue,
88
+ after: async (verification, context) => {
89
+ /**
90
+ * For: Email OTP plugin
91
+ * After a verification is created, if it is from the EmailOTP plugin,
92
+ * create a new verification value with the jazzAuth with the same expiration.
93
+ */
94
+ if (
95
+ contextContainsJazzAuth(context) &&
96
+ verification.identifier.startsWith("sign-in-otp-")
97
+ ) {
98
+ await context.context.internalAdapter.createVerificationValue(
99
+ {
100
+ value: JSON.stringify({ jazzAuth: context.jazzAuth }),
101
+ identifier: `${verification.identifier}-jazz-auth`,
102
+ expiresAt: verification.expiresAt,
100
103
  },
101
- };
104
+ );
102
105
  }
103
106
  },
104
107
  },
@@ -147,6 +150,7 @@ export const jazzPlugin: () => JazzPlugin = () => {
147
150
  },
148
151
 
149
152
  /**
153
+ * For: Social / OAuth2 plugin
150
154
  * /callback is the endpoint that BetterAuth uses to authenticate the user coming from a social provider.
151
155
  * 1. Catch the state
152
156
  * 2. Find the verification value
@@ -162,17 +166,12 @@ export const jazzPlugin: () => JazzPlugin = () => {
162
166
  handler: createAuthMiddleware(async (ctx) => {
163
167
  const state = ctx.query?.state || ctx.body?.state;
164
168
 
165
- const data = await ctx.context.adapter.findOne<{ value: string }>({
166
- model: ctx.context.tables.verification!.modelName,
167
- where: [
168
- {
169
- field: "identifier",
170
- operator: "eq",
171
- value: state,
172
- },
173
- ],
174
- select: ["value"],
175
- });
169
+ const identifier = `${state}-jazz-auth`;
170
+
171
+ const data =
172
+ await ctx.context.internalAdapter.findVerificationValue(
173
+ identifier,
174
+ );
176
175
 
177
176
  // if not found, the social plugin will throw later anyway
178
177
  if (!data) {
@@ -197,6 +196,45 @@ export const jazzPlugin: () => JazzPlugin = () => {
197
196
  }
198
197
  }),
199
198
  },
199
+ /**
200
+ * For: Email OTP plugin
201
+ * When the user sends an OTP, we try to find the jazzAuth.
202
+ * If it isn't a sign-up, we expect to not find a verification value.
203
+ */
204
+ {
205
+ matcher: (context) => {
206
+ return context.path.startsWith("/sign-in/email-otp");
207
+ },
208
+ handler: createAuthMiddleware(async (ctx) => {
209
+ const email = ctx.body.email;
210
+ const identifier = `sign-in-otp-${email}-jazz-auth`;
211
+
212
+ const data =
213
+ await ctx.context.internalAdapter.findVerificationValue(
214
+ identifier,
215
+ );
216
+
217
+ // if not found, it isn't a sign-up
218
+ if (!data || data.expiresAt < new Date()) {
219
+ return;
220
+ }
221
+
222
+ const parsed = JSON.parse(data.value);
223
+
224
+ if (parsed && "jazzAuth" in parsed) {
225
+ return {
226
+ context: {
227
+ ...ctx,
228
+ jazzAuth: parsed.jazzAuth,
229
+ },
230
+ };
231
+ } else {
232
+ throw new APIError(500, {
233
+ message: "JazzAuth not found in verification value",
234
+ });
235
+ }
236
+ }),
237
+ },
200
238
  ],
201
239
  after: [
202
240
  /**
@@ -227,6 +265,38 @@ export const jazzPlugin: () => JazzPlugin = () => {
227
265
  });
228
266
  }),
229
267
  },
268
+
269
+ /**
270
+ * For: Social / OAuth2 plugin
271
+ * When the user sign-in via social, we create a verification value with the jazzAuth.
272
+ */
273
+ {
274
+ matcher: (context) => {
275
+ return context.path.startsWith("/sign-in/social");
276
+ },
277
+ handler: createAuthMiddleware(async (ctx) => {
278
+ if (!contextContainsJazzAuth(ctx)) {
279
+ throw new APIError(500, {
280
+ message: "JazzAuth not found in context",
281
+ });
282
+ }
283
+
284
+ const returned = ctx.context.returned as { url: string };
285
+
286
+ const url = new URL(returned.url);
287
+ const state = url.searchParams.get("state");
288
+
289
+ const value = JSON.stringify({ jazzAuth: ctx.jazzAuth });
290
+ const expiresAt = new Date();
291
+ expiresAt.setMinutes(expiresAt.getMinutes() + 10);
292
+
293
+ await ctx.context.internalAdapter.createVerificationValue({
294
+ value,
295
+ identifier: `${state}-jazz-auth`,
296
+ expiresAt,
297
+ });
298
+ }),
299
+ },
230
300
  ],
231
301
  },
232
302
  } satisfies JazzPlugin;
@@ -7,14 +7,19 @@ import {
7
7
  } from "jazz-tools/testing";
8
8
  import { assert, beforeEach, describe, expect, it, vi } from "vitest";
9
9
  import { jazzPluginClient } from "../client.js";
10
+ import { emailOTPClient, genericOAuthClient } from "better-auth/client/plugins";
10
11
 
11
- describe("auth client", () => {
12
+ describe("Better-Auth client plugin", () => {
12
13
  let account: Account;
13
14
  let jazzContextManager: TestJazzContextManager<Account>;
14
15
  let authSecretStorage: AuthSecretStorage;
15
16
  let authClient: ReturnType<
16
17
  typeof createAuthClient<{
17
- plugins: ReturnType<typeof jazzPluginClient>[];
18
+ plugins: ReturnType<
19
+ | typeof jazzPluginClient
20
+ | typeof emailOTPClient
21
+ | typeof genericOAuthClient
22
+ >[];
18
23
  }>
19
24
  >;
20
25
  let customFetchImpl = vi.fn();
@@ -31,7 +36,7 @@ describe("auth client", () => {
31
36
 
32
37
  authClient = createAuthClient({
33
38
  baseURL: "http://localhost:3000",
34
- plugins: [jazzPluginClient()],
39
+ plugins: [jazzPluginClient(), emailOTPClient(), genericOAuthClient()],
35
40
  fetchOptions: {
36
41
  customFetchImpl,
37
42
  },
@@ -245,5 +250,88 @@ describe("auth client", () => {
245
250
  expect(anonymousCredentials).not.toMatchObject(credentials!);
246
251
  });
247
252
 
248
- it.todo("should logout from Better Auth after Jazz's log-out");
253
+ it("should send Jazz credentials using social login", async () => {
254
+ const credentials = await authSecretStorage.get();
255
+ assert(credentials, "Jazz credentials are not available");
256
+
257
+ customFetchImpl.mockResolvedValue(new Response(JSON.stringify({})));
258
+
259
+ // Sign up
260
+ await authClient.signIn.social({
261
+ provider: "github",
262
+ });
263
+
264
+ expect(customFetchImpl).toHaveBeenCalledTimes(1);
265
+ expect(customFetchImpl.mock.calls[0]![0].toString()).toBe(
266
+ "http://localhost:3000/api/auth/sign-in/social",
267
+ );
268
+
269
+ // Verify the credentials have been injected in the request body
270
+ expect(
271
+ customFetchImpl.mock.calls[0]![1].headers.get("x-jazz-auth")!,
272
+ ).toEqual(
273
+ JSON.stringify({
274
+ accountID: credentials!.accountID,
275
+ secretSeed: credentials!.secretSeed,
276
+ accountSecret: credentials!.accountSecret,
277
+ }),
278
+ );
279
+ });
280
+
281
+ it("should send Jazz credentials using oauth generic plugin", async () => {
282
+ const credentials = await authSecretStorage.get();
283
+ assert(credentials, "Jazz credentials are not available");
284
+
285
+ customFetchImpl.mockResolvedValue(new Response(JSON.stringify({})));
286
+
287
+ // Sign up
288
+ await authClient.signIn.oauth2({
289
+ providerId: "github",
290
+ });
291
+
292
+ expect(customFetchImpl).toHaveBeenCalledTimes(1);
293
+ expect(customFetchImpl.mock.calls[0]![0].toString()).toBe(
294
+ "http://localhost:3000/api/auth/sign-in/oauth2",
295
+ );
296
+
297
+ // Verify the credentials have been injected in the request body
298
+ expect(
299
+ customFetchImpl.mock.calls[0]![1].headers.get("x-jazz-auth")!,
300
+ ).toEqual(
301
+ JSON.stringify({
302
+ accountID: credentials!.accountID,
303
+ secretSeed: credentials!.secretSeed,
304
+ accountSecret: credentials!.accountSecret,
305
+ }),
306
+ );
307
+ });
308
+
309
+ it("should send Jazz credentials using email OTP", async () => {
310
+ const credentials = await authSecretStorage.get();
311
+ assert(credentials, "Jazz credentials are not available");
312
+
313
+ customFetchImpl.mockResolvedValue(new Response(JSON.stringify({})));
314
+
315
+ // Sign up
316
+ await authClient.emailOtp.sendVerificationOtp({
317
+ email: "test@jazz.dev",
318
+ type: "sign-in",
319
+ });
320
+
321
+ expect(customFetchImpl).toHaveBeenCalledTimes(1);
322
+ expect(customFetchImpl.mock.calls[0]![0].toString()).toBe(
323
+ "http://localhost:3000/api/auth/email-otp/send-verification-otp",
324
+ );
325
+
326
+ // Verify the credentials have been injected in the request body
327
+ expect(
328
+ customFetchImpl.mock.calls[0]![1].headers.get("x-jazz-auth")!,
329
+ ).toEqual(
330
+ JSON.stringify({
331
+ accountID: credentials!.accountID,
332
+ secretSeed: credentials!.secretSeed,
333
+ accountSecret: credentials!.accountSecret,
334
+ }),
335
+ );
336
+ });
249
337
  });