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.
- package/.turbo/turbo-build.log +53 -53
- package/CHANGELOG.md +16 -0
- package/dist/better-auth/auth/client.d.ts.map +1 -1
- package/dist/better-auth/auth/client.js +7 -1
- package/dist/better-auth/auth/client.js.map +1 -1
- package/dist/better-auth/auth/react.d.ts +0 -2145
- package/dist/better-auth/auth/react.d.ts.map +1 -1
- package/dist/better-auth/auth/react.js +2 -14
- package/dist/better-auth/auth/react.js.map +1 -1
- package/dist/better-auth/auth/server.d.ts.map +1 -1
- package/dist/better-auth/auth/server.js +73 -22
- package/dist/better-auth/auth/server.js.map +1 -1
- package/dist/better-auth/auth/tests/react.test.d.ts +2 -0
- package/dist/better-auth/auth/tests/react.test.d.ts.map +1 -0
- package/dist/{chunk-3LE7N6TH.js → chunk-45VKEOXG.js} +123 -81
- package/dist/chunk-45VKEOXG.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/inspector/{custom-element-WCY6D3QJ.js → custom-element-IBHKHN27.js} +19 -69
- package/dist/inspector/custom-element-IBHKHN27.js.map +1 -0
- package/dist/inspector/index.d.ts +5 -1
- package/dist/inspector/index.d.ts.map +1 -1
- package/dist/inspector/index.js +18 -17
- package/dist/inspector/index.js.map +1 -1
- package/dist/inspector/register-custom-element.js +1 -1
- package/dist/inspector/viewer/new-app.d.ts +0 -3
- package/dist/inspector/viewer/new-app.d.ts.map +1 -1
- package/dist/react-core/index.js +3 -1
- package/dist/react-core/index.js.map +1 -1
- package/dist/testing.js +2 -2
- package/dist/testing.js.map +1 -1
- package/dist/tools/coValues/inbox.d.ts +5 -5
- package/dist/tools/coValues/inbox.d.ts.map +1 -1
- package/dist/worker/index.d.ts +8 -2
- package/dist/worker/index.d.ts.map +1 -1
- package/dist/worker/index.js +7 -3
- package/dist/worker/index.js.map +1 -1
- package/package.json +4 -4
- package/src/better-auth/auth/client.ts +8 -2
- package/src/better-auth/auth/react.tsx +2 -51
- package/src/better-auth/auth/server.ts +94 -24
- package/src/better-auth/auth/tests/client.test.ts +92 -4
- package/src/better-auth/auth/tests/react.test.tsx +43 -0
- package/src/better-auth/auth/tests/server.test.ts +276 -98
- package/src/inspector/custom-element.tsx +1 -1
- package/src/inspector/index.tsx +44 -0
- package/src/inspector/viewer/new-app.tsx +0 -18
- package/src/tools/coValues/inbox.ts +190 -108
- package/src/tools/testing.ts +1 -1
- package/src/tools/tests/coFeed.test.ts +33 -22
- package/src/tools/tests/coList.test.ts +6 -4
- package/src/tools/tests/coMap.test.ts +13 -5
- package/src/tools/tests/exportImport.test.ts +3 -1
- package/src/tools/tests/groupsAndAccounts.test.ts +56 -44
- package/src/tools/tests/inbox.test.ts +293 -31
- package/src/worker/index.ts +15 -5
- package/tsup.config.ts +1 -1
- package/dist/chunk-3LE7N6TH.js.map +0 -1
- package/dist/inspector/custom-element-WCY6D3QJ.js.map +0 -1
- 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-
|
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: "
|
40
|
+
peer1role: "client",
|
41
41
|
peer2role: "server"
|
42
42
|
}
|
43
43
|
);
|
package/dist/testing.js.map
CHANGED
@@ -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":";;;;;;;;;;;AAAA,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAmB7B,IAAM,aAAiE;AAAA,EACrE,SAAS;AAAA,EACT,YAAY;AACd;AAEO,IAAM,eAAN,cAA2B,aAAa;AAAA,EAC7C,aAAa,SAAS;AACpB,QAAI,eAAe,cAAc,UAAU,WAAW,SAAS,OAAO,GAAG;AAEvE,YAAM,SAAS,IAAI,aAAa;AAEhC,aAAO,OAAO,CAAC,YACb,WAAW,gBAAgB,gBAAgB,QAAQ,OAAO,CAAC;AAC7D,aAAO,SAAS,CAAC,WACf,KAAK,MAAM,OAAO,UAAU,WAAW,MAAM,CAAC;AAChD,aAAO,UAAU,CAAC,YAChB,cAAc,gBAAgB,gBAAgB,OAAO,CAAC;AACxD,aAAO,aAAa,CAAC,cACnB,UAAU,UAAU,cAAc,MAAM;AAE1C,aAAO;AAAA,IACT;AAGA,WAAO,IAAI,aAAa;AAAA,EAC1B;AACF;AAEO,SAAS,mCAAmC;AACjD,MAAI,CAAC,WAAW,SAAS;AACvB,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AAEA,QAAM,CAAC,OAAO,KAAK,IAAI,gBAAgB;AAAA,IACrC,KAAK,OAAO,EAAE,SAAS;AAAA,IACvB,KAAK,OAAO,EAAE,SAAS;AAAA,IACvB;AAAA,MACE,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,EACF;AAEA,MAAI,WAAW,YAAY;AACzB,UAAM,OAAO,MAAM,SAAS;AAE5B,UAAM,SAAS,OAAO,CAAC,YAAY;AACjC,iBAAW,MAAM;AACf,aAAK,KAAK,MAAM,UAAU,OAAO;AAAA,MACnC,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,OAAO,CAAC,YAAY;AACjC,iBAAW,MAAM;AACf,aAAK,KAAK,MAAM,UAAU,OAAO;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,aAAW,QAAQ,YAAY,QAAQ,KAAK;AAE5C,SAAO;AACT;AAEA,IAAM,gBAAgB,oBAAI,IAAwB;AAClD,IAAI,oBAAoB;AAExB,eAAsB,sBAIpB,SAI+B;AAC/B,QAAMA,gBAAe,SAAS,gBAC1B,qCAAqC,QAAQ,aAAa,IAC1D;AACJ,QAAM,QAAQ,CAAC;AACf,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,iCAAiC,CAAC;AAAA,EAC/C;AAEA,QAAM,SAAS,MAAM,aAAa,OAAO;AACzC,QAAM,aAAa,OAAO,oBAAoB;AAE9C,QAAM,EAAE,KAAK,IAAI,MAAM,UAAU,wBAAwB;AAAA,IACvD,eAAe;AAAA,MACb,MAAM;AAAA,MACN,GAAG,SAAS;AAAA,IACd;AAAA,IACA,oBAAoB,OAAO,0BAA0B,UAAU;AAAA,IAC/D;AAAA,IACA,iBAAiB;AAAA,IACjB,WAAW,OAAO,YAAY,OAAO,kBAAkB;AACrD,UAAI,mBAAmB;AACrB,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,0BAAoB;AAGpB,YAAMC,WAAUD,cAAa,QAAQ,UAAU;AAI/C,YAAM,oBAAoB,qBAAqB,SAAS;AACxD,2BAAqB,IAAIC,QAAO;AAEhC,YAAMA,SAAQ,iBAAiB,aAAa;AAE5C,UAAI,CAAC,SAAS,wBAAwB;AACpC,6BAAqB,IAAI,iBAAiB;AAAA,MAC5C;AAEA,0BAAoB;AAAA,IACtB;AAAA,EACF,CAAC;AAED,QAAM,UAAUD,cAAa,SAAS,IAAI;AAC1C,gBAAc,IAAI,QAAQ,MAAM,IAAI,UAAU;AAE9C,MAAI,SAAS,wBAAwB;AACnC,yBAAqB,IAAI,OAAO;AAAA,EAClC;AAEA,SAAO;AACT;AAEO,SAAS,iBAAiB,SAAkB;AACjD,uBAAqB,IAAI,OAAO;AAClC;AAYO,SAAS,wBACd,UACQ;AACR,QAAM,KAAK,QAAQ,MAAM;AACzB,uBAAqB,IAAI,IAAI;AAC7B,QAAM,SAAS,SAAS;AAExB,MAAI,kBAAkB,SAAS;AAC7B,WAAO,OAAO,QAAQ,MAAM;AAC1B,2BAAqB,IAAI,EAAE;AAC3B,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,uBAAqB,IAAI,EAAE;AAC3B,SAAO;AACT;AAEA,eAAsB,sBAAsB;AAC1C,QAAM,MAAM,MAAM,2BAA2B;AAAA,IAC3C,QAAQ,MAAM,aAAa,OAAO;AAAA,IAClC,iBAAiB,CAAC;AAAA,EACpB,CAAC;AAED,SAAO;AAAA,IACL,OAAO,IAAI;AAAA,EACb;AACF;AASO,IAAM,yBAAN,MAAM,gCAEH,mBAA0D;AAAA,EAClE,OAAO,mBACL,SACA,OACA;AACA,QAAI,WAAW,WAAW,SAAS;AACjC,aAAO,KAAK,UAAe,SAAS,KAAK;AAAA,IAC3C;AAEA,WAAO,KAAK,YAAiB,WAAY,QAAQ,MAAM,GAAW,KAAK;AAAA,EACzE;AAAA,EAEA,OAAO,YACL,SACA,OACA;AACA,UAAM,UAAU,IAAI,wBAA4B;AAEhD,UAAM,WAAW,OAAO,kBAAkB,iBAAiB;AAC3D,UAAM,UAAU,QAAQ,qBAAqB;AAC7C,UAAM,OAAO,QAAQ,MAAM;AAE3B,UAAM,cAAc;AAAA,MAClB,WAAW,QAAQ,MAAM;AAAA,MACzB,eAAe,KAAK,gBAAgB,EAAE;AAAA,MACtC,YAAY,cAAc,IAAI,QAAQ,MAAM,EAAE;AAAA,MAC9C;AAAA,IACF;AAEA,YAAQ,IAAI,WAAW;AAEvB,YAAQ;AAAA,MACN;AAAA,QACE,eAAe,QAAQ;AAAA,QAEvB,GAAG;AAAA,MACL;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ;AAAA,QACA,MAAM,MAAM;AACV,eAAK,iBAAiB;AAAA,QACxB;AAAA,QACA,QAAQ,YAAY;AAClB,gBAAM,QAAQ,MAAM;AACpB,eAAK,iBAAiB;AAAA,QACxB;AAAA,MACF;AAAA,MACA;AAAA,QACE;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,UACL,EAAE,MAAM,GACR,QAA0C,CAAC,GAC3C;AACA,UAAM,UAAU,IAAI,wBAA4B;AAChD,UAAM,OAAO,MAAM;AAEnB,YAAQ,cAAc,OAAO;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,MAAM,MAAM;AACV,aAAK,iBAAiB;AAAA,MACxB;AAAA,MACA,QAAQ,YAAY;AAClB,aAAK,iBAAiB;AAAA,MACxB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cACJ,OACA,WACA;AACA,QAAI,CAAC,WAAW,SAAS;AACvB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,MAAM,kBAAkB;AAAA,MACtC,aAAa,WAAW;AAAA,MACxB,oBAAoB,MAAM;AAAA,MAC1B,iBAAiB,WAAW;AAAA,MAC5B,iBAAiB,CAAC,iCAAiC,CAAC;AAAA,MACpD,QAAQ,MAAM,aAAa,OAAO;AAAA,MAClC,iBAAiB;AAAA,MACjB,mBAAmB,KAAK,qBAAqB;AAAA,MAC7C,eAAe,MAAM;AAAA,IACvB,CAAC;AAED,WAAO;AAAA,MACL,IAAI,QAAQ;AAAA,MACZ,MAAM,QAAQ;AAAA,MACd,MAAM,MAAM;AACV,gBAAQ,KAAK;AAAA,MACf;AAAA,MACA,QAAQ,MAAM;AACZ,eAAO,QAAQ,OAAO;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,aACpB,GACA,GACA,QAA6B,UAC7B,QAA6B,UAC7B;AACA,QAAM,CAAC,OAAO,KAAK,IAAI,gBAAgB;AAAA,IACrC,EAAE,MAAM;AAAA,IACR,EAAE,MAAM;AAAA,IACR;AAAA,MACE,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,EACF;AAEA,IAAE,MAAM,UAAU,YAAY,QAAQ,KAAK;AAC3C,IAAE,MAAM,UAAU,YAAY,QAAQ,KAAK;AAE3C,QAAM,EAAE,MAAM,uBAAuB;AACrC,QAAM,EAAE,MAAM,uBAAuB;AACvC;AAEA,eAAsB,kBAAkB;AAAA,EACtC,aAAa;AACf,IAEI,CAAC,GAAG;AACN,MAAI,WAAW,SAAS;AACtB,eAAW,QAAQ,iBAAiB;AAAA,EACtC;AAEA,QAAM,UAAU,MAAM,QAAQ,OAAO;AAAA,IACnC,eAAe;AAAA,MACb,MAAM;AAAA,IACR;AAAA,IACA,QAAQ,MAAM,aAAa,OAAO;AAAA,EACpC,CAAC;AAED,aAAW,UAAU,QAAQ,MAAM;AACnC,aAAW,aAAa;AAExB,SAAO;AACT;","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
|
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
|
-
|
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":"AAAA,OAAO,
|
1
|
+
{"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../../src/tools/coValues/inbox.ts"],"names":[],"mappings":"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"}
|
package/dist/worker/index.d.ts
CHANGED
@@ -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,
|
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:
|
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,
|
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"}
|
package/dist/worker/index.js
CHANGED
@@ -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,
|
package/dist/worker/index.js.map
CHANGED
@@ -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
|
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.
|
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.
|
187
|
-
"cojson-storage-indexeddb": "0.18.
|
188
|
-
"cojson-transport-ws": "0.18.
|
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(
|
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
|
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
|
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
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
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("
|
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<
|
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
|
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
|
});
|