jazz-tools 0.19.20 → 0.19.22

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 (105) hide show
  1. package/.svelte-kit/__package__/server.d.ts.map +1 -1
  2. package/.svelte-kit/__package__/server.js +9 -7
  3. package/.turbo/turbo-build.log +56 -56
  4. package/CHANGELOG.md +15 -0
  5. package/dist/better-auth/auth/server.d.ts.map +1 -1
  6. package/dist/better-auth/auth/server.js +4 -4
  7. package/dist/better-auth/auth/server.js.map +1 -1
  8. package/dist/better-auth/database-adapter/index.js.map +1 -1
  9. package/dist/better-auth/database-adapter/repository/generic.d.ts +3 -3
  10. package/dist/better-auth/database-adapter/repository/session.d.ts +2 -2
  11. package/dist/better-auth/database-adapter/schema.d.ts +3 -3
  12. package/dist/better-auth/database-adapter/schema.d.ts.map +1 -1
  13. package/dist/{chunk-MI24YFCY.js → chunk-QCTQH5RS.js} +1 -1
  14. package/dist/chunk-QCTQH5RS.js.map +1 -0
  15. package/dist/index.js +36 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/media/{chunk-3LKBM3G3.js → chunk-IRL3KNPO.js} +2 -2
  18. package/dist/media/{chunk-3LKBM3G3.js.map → chunk-IRL3KNPO.js.map} +1 -1
  19. package/dist/media/create-image/react-native.d.ts +1 -1
  20. package/dist/media/create-image/react-native.d.ts.map +1 -1
  21. package/dist/media/index.browser.js +1 -1
  22. package/dist/media/index.js +1 -1
  23. package/dist/media/index.native.js +5 -5
  24. package/dist/media/index.native.js.map +1 -1
  25. package/dist/media/index.server.js +1 -1
  26. package/dist/react/hooks.d.ts +1 -2
  27. package/dist/react/hooks.d.ts.map +1 -1
  28. package/dist/react/index.js +7 -2
  29. package/dist/react/index.js.map +1 -1
  30. package/dist/react-core/hooks.d.ts +92 -1
  31. package/dist/react-core/hooks.d.ts.map +1 -1
  32. package/dist/react-core/index.js +126 -57
  33. package/dist/react-core/index.js.map +1 -1
  34. package/dist/react-core/tests/useCoStates.test.d.ts +2 -0
  35. package/dist/react-core/tests/useCoStates.test.d.ts.map +1 -0
  36. package/dist/react-native/index.js +4 -0
  37. package/dist/react-native/index.js.map +1 -1
  38. package/dist/react-native-core/hooks.d.ts +1 -1
  39. package/dist/react-native-core/hooks.d.ts.map +1 -1
  40. package/dist/react-native-core/index.js +4 -0
  41. package/dist/react-native-core/index.js.map +1 -1
  42. package/dist/svelte/auth/ClerkAuth.svelte.d.ts +38 -0
  43. package/dist/svelte/auth/ClerkAuth.svelte.d.ts.map +1 -0
  44. package/dist/svelte/auth/ClerkAuth.svelte.js +47 -0
  45. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte +156 -0
  46. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte.d.ts +67 -0
  47. package/dist/svelte/auth/JazzSvelteProviderWithClerk.svelte.d.ts.map +1 -0
  48. package/dist/svelte/auth/RegisterClerkAuth.svelte +27 -0
  49. package/dist/svelte/auth/RegisterClerkAuth.svelte.d.ts +17 -0
  50. package/dist/svelte/auth/RegisterClerkAuth.svelte.d.ts.map +1 -0
  51. package/dist/svelte/auth/index.d.ts +2 -0
  52. package/dist/svelte/auth/index.d.ts.map +1 -1
  53. package/dist/svelte/auth/index.js +2 -0
  54. package/dist/svelte/tests/ClerkAuth.svelte.test.d.ts +2 -0
  55. package/dist/svelte/tests/ClerkAuth.svelte.test.d.ts.map +1 -0
  56. package/dist/svelte/tests/ClerkAuth.svelte.test.js +202 -0
  57. package/dist/svelte/tests/TestClerkAuthWrapper.svelte +16 -0
  58. package/dist/svelte/tests/TestClerkAuthWrapper.svelte.d.ts +8 -0
  59. package/dist/svelte/tests/TestClerkAuthWrapper.svelte.d.ts.map +1 -0
  60. package/dist/svelte/tests/testUtils.d.ts +1 -0
  61. package/dist/svelte/tests/testUtils.d.ts.map +1 -1
  62. package/dist/svelte/tests/testUtils.js +3 -1
  63. package/dist/testing.js +1 -1
  64. package/dist/tools/auth/clerk/index.d.ts +1 -1
  65. package/dist/tools/auth/clerk/types.d.ts +1 -1
  66. package/dist/tools/auth/clerk/types.d.ts.map +1 -1
  67. package/dist/tools/exports.d.ts +1 -0
  68. package/dist/tools/exports.d.ts.map +1 -1
  69. package/dist/tools/subscribe/types.d.ts +1 -1
  70. package/dist/tools/subscribe/types.d.ts.map +1 -1
  71. package/dist/worker/JazzMessageChannel.d.ts +36 -0
  72. package/dist/worker/JazzMessageChannel.d.ts.map +1 -0
  73. package/dist/worker/index.d.ts +7 -1
  74. package/dist/worker/index.d.ts.map +1 -1
  75. package/dist/worker/index.js +28 -17
  76. package/dist/worker/index.js.map +1 -1
  77. package/package.json +4 -4
  78. package/src/better-auth/auth/server.ts +9 -7
  79. package/src/better-auth/database-adapter/repository/generic.ts +3 -3
  80. package/src/better-auth/database-adapter/repository/session.ts +2 -2
  81. package/src/better-auth/database-adapter/schema.ts +5 -5
  82. package/src/media/create-image/react-native.ts +9 -7
  83. package/src/media/create-image-factory.test.ts +1 -1
  84. package/src/media/create-image-factory.ts +1 -1
  85. package/src/react/hooks.tsx +4 -2
  86. package/src/react-core/hooks.ts +321 -76
  87. package/src/react-core/tests/testUtils.tsx +2 -2
  88. package/src/react-core/tests/useCoState.selector.test.ts +309 -22
  89. package/src/react-core/tests/useCoStates.test.tsx +414 -0
  90. package/src/react-native-core/hooks.tsx +2 -0
  91. package/src/svelte/auth/ClerkAuth.svelte.ts +67 -0
  92. package/src/svelte/auth/JazzSvelteProviderWithClerk.svelte +156 -0
  93. package/src/svelte/auth/RegisterClerkAuth.svelte +27 -0
  94. package/src/svelte/auth/index.ts +2 -0
  95. package/src/svelte/tests/ClerkAuth.svelte.test.ts +305 -0
  96. package/src/svelte/tests/TestClerkAuthWrapper.svelte +16 -0
  97. package/src/svelte/tests/testUtils.ts +4 -1
  98. package/src/tools/auth/clerk/types.ts +1 -1
  99. package/src/tools/exports.ts +5 -0
  100. package/src/tools/subscribe/types.ts +1 -1
  101. package/src/tools/tests/inbox.test.ts +7 -7
  102. package/src/tools/tests/testStorage.ts +2 -2
  103. package/src/worker/JazzMessageChannel.ts +73 -0
  104. package/src/worker/index.ts +36 -17
  105. package/dist/chunk-MI24YFCY.js.map +0 -1
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ import {
23
23
  Ref,
24
24
  SchemaUnion,
25
25
  SubscriptionScope,
26
+ activeAccountContext,
26
27
  assertLoaded,
27
28
  captureStack,
28
29
  coExport_exports,
@@ -48,7 +49,7 @@ import {
48
49
  subscribeToCoValue,
49
50
  unstable_loadUnique,
50
51
  zodReExport_exports
51
- } from "./chunk-MI24YFCY.js";
52
+ } from "./chunk-QCTQH5RS.js";
52
53
  import {
53
54
  createSSRJazzAgent
54
55
  } from "./chunk-M2HGBOXS.js";
@@ -981,6 +982,39 @@ import {
981
982
  LogLevel
982
983
  } from "cojson";
983
984
 
985
+ // src/worker/JazzMessageChannel.ts
986
+ import { CojsonMessageChannel } from "cojson";
987
+ import { AnonymousJazzAgent as AnonymousJazzAgent2 } from "jazz-tools";
988
+ var JazzMessageChannel = class {
989
+ /**
990
+ * Expose a Jazz connection to a target.
991
+ * This is the host-side API, typically called from the main thread.
992
+ *
993
+ * @param target - Any object with a postMessage method (Worker, Window, etc.)
994
+ * @param opts - Configuration options including the account to use
995
+ * @returns A promise that resolves once the connection is established
996
+ */
997
+ static async expose(target, opts = {}) {
998
+ const { loadAs, ...cojsonOpts } = opts;
999
+ const accountOrAgent = loadAs ?? activeAccountContext.maybeGet();
1000
+ if (!accountOrAgent) {
1001
+ throw new Error(
1002
+ "No account provided and no active account context available"
1003
+ );
1004
+ }
1005
+ const node = accountOrAgent instanceof AnonymousJazzAgent2 ? accountOrAgent.node : accountOrAgent.$jazz.localNode;
1006
+ const peer = await CojsonMessageChannel.expose(target, cojsonOpts);
1007
+ node.syncManager.addPeer(peer);
1008
+ }
1009
+ /**
1010
+ * Accept an incoming Jazz connection.
1011
+ * Same as cojson CojsonMessageChannel.waitForConnection().
1012
+ */
1013
+ static waitForConnection(opts) {
1014
+ return CojsonMessageChannel.waitForConnection(opts);
1015
+ }
1016
+ };
1017
+
984
1018
  // src/tools/index.ts
985
1019
  import {
986
1020
  cojsonInternals as cojsonInternals4,
@@ -1034,6 +1068,7 @@ export {
1034
1068
  createJazzContextFromExistingCredentials,
1035
1069
  createSSRJazzAgent,
1036
1070
  createUnloadedCoValue,
1071
+ JazzMessageChannel as experimental_JazzMessageChannel,
1037
1072
  experimental_defineRequest,
1038
1073
  exportCoValue,
1039
1074
  generateAuthToken,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tools/auth/clerk/index.ts","../src/tools/auth/clerk/getClerkUsername.ts","../src/tools/auth/clerk/types.ts","../src/tools/auth/DemoAuth.ts","../src/tools/auth/PassphraseAuth.ts","../src/tools/implementation/invites.ts","../src/tools/coValues/request.ts","../src/tools/config.ts","../src/tools/index.ts"],"sourcesContent":["import {\n Account,\n AuthCredentials,\n AuthSecretStorage,\n AuthenticateAccountFunction,\n} from \"jazz-tools\";\nimport { getClerkUsername } from \"./getClerkUsername.js\";\nimport {\n ClerkCredentials,\n ClerkEventSchema,\n ClerkUser,\n MinimalClerkClient,\n isClerkAuthStateEqual,\n isClerkCredentials,\n} from \"./types.js\";\n\nexport type { MinimalClerkClient };\nexport { isClerkCredentials };\n\nexport class JazzClerkAuth {\n constructor(\n private authenticate: AuthenticateAccountFunction,\n private logOut: () => Promise<void> | void,\n private authSecretStorage: AuthSecretStorage,\n ) {}\n\n /**\n * Loads the Jazz auth data from the Clerk user and sets it in the auth secret storage.\n */\n static loadClerkAuthData(\n credentials: ClerkCredentials,\n storage: AuthSecretStorage,\n ) {\n return storage.set({\n accountID: credentials.jazzAccountID,\n accountSecret: credentials.jazzAccountSecret,\n secretSeed: credentials.jazzAccountSeed\n ? Uint8Array.from(credentials.jazzAccountSeed)\n : undefined,\n provider: \"clerk\",\n });\n }\n\n static async initializeAuth(clerk: MinimalClerkClient) {\n const secretStorage = new AuthSecretStorage();\n\n if (!isClerkCredentials(clerk.user?.unsafeMetadata)) {\n return;\n }\n\n await JazzClerkAuth.loadClerkAuthData(\n clerk.user.unsafeMetadata,\n secretStorage,\n );\n }\n\n private isFirstCall = true;\n private previousUser: Pick<ClerkUser, \"unsafeMetadata\"> | null = null;\n\n registerListener(clerkClient: MinimalClerkClient) {\n this.previousUser = ClerkEventSchema.parse(clerkClient).user ?? null;\n\n // Need to use addListener because the clerk user object is not updated when the user logs in\n return clerkClient.addListener((event) => {\n const parsedEvent = ClerkEventSchema.safeParse(event);\n\n if (!parsedEvent.success) {\n console.error(\"Invalid Clerk event\", parsedEvent.error);\n return;\n }\n\n const user = parsedEvent.data.user ?? null;\n\n if (!isClerkAuthStateEqual(this.previousUser, user) || this.isFirstCall) {\n this.previousUser = user;\n this.onClerkUserChange(user);\n this.isFirstCall = false;\n }\n });\n }\n\n onClerkUserChange = async (clerkUser: ClerkUser | null | undefined) => {\n const isAuthenticated = this.authSecretStorage.isAuthenticated;\n\n // LogOut is driven by Clerk. The framework adapters will need to pass `logOutReplacement` to the `JazzProvider`\n // to make the logOut work correctly.\n if (!clerkUser) {\n if (isAuthenticated) {\n this.authSecretStorage.clear();\n await this.logOut();\n }\n return;\n }\n\n if (isAuthenticated) return;\n\n if (!clerkUser.unsafeMetadata.jazzAccountID) {\n await this.signIn(clerkUser);\n } else {\n await this.logIn(clerkUser);\n }\n };\n\n logIn = async (clerkUser: ClerkUser) => {\n const clerkCredentials = clerkUser.unsafeMetadata;\n if (!isClerkCredentials(clerkCredentials)) {\n throw new Error(\"No credentials found on Clerk\");\n }\n\n const credentials = {\n accountID: clerkCredentials.jazzAccountID,\n accountSecret: clerkCredentials.jazzAccountSecret,\n secretSeed: clerkCredentials.jazzAccountSeed\n ? Uint8Array.from(clerkCredentials.jazzAccountSeed)\n : undefined,\n provider: \"clerk\",\n } satisfies AuthCredentials;\n\n await this.authenticate(credentials);\n\n await JazzClerkAuth.loadClerkAuthData(\n {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed: clerkCredentials.jazzAccountSeed,\n },\n this.authSecretStorage,\n );\n };\n\n signIn = async (clerkUser: ClerkUser) => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials) {\n throw new Error(\"No credentials found\");\n }\n\n const jazzAccountSeed = credentials.secretSeed\n ? Array.from(credentials.secretSeed)\n : undefined;\n\n const clerkCredentials = {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed,\n };\n // user.update will cause the Clerk user change listener to fire; updating this.previousUser beforehand\n // ensures the listener sees the new credentials and does not trigger an unnecessary logIn operation\n this.previousUser = { unsafeMetadata: clerkCredentials };\n\n await clerkUser.update({\n unsafeMetadata: clerkCredentials,\n });\n\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n const username = getClerkUsername(clerkUser);\n\n if (username) {\n currentAccount.profile.$jazz.set(\"name\", username);\n }\n\n await JazzClerkAuth.loadClerkAuthData(\n {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed,\n },\n this.authSecretStorage,\n );\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace BrowserClerkAuth {\n export interface Driver {\n onError: (error: string | Error) => void;\n }\n}\n","import type { ClerkUser } from \"./types.js\";\n\nexport function getClerkUsername(user: ClerkUser) {\n if (user.fullName) {\n return user.fullName;\n }\n\n if (user.firstName) {\n if (user.lastName) {\n return `${user.firstName} ${user.lastName}`;\n }\n\n return user.firstName;\n }\n\n if (user.username) {\n return user.username;\n }\n\n if (user.primaryEmailAddress?.emailAddress) {\n const emailUsername = user.primaryEmailAddress.emailAddress.split(\"@\")[0];\n\n if (emailUsername) {\n return emailUsername;\n }\n }\n\n return user.id;\n}\n","import { type AgentSecret } from \"cojson\";\nimport { z } from \"zod/v4\";\n\nconst ClerkJazzCredentialsSchema = z.object({\n jazzAccountID: z.string(),\n jazzAccountSecret: z.string(),\n jazzAccountSeed: z.array(z.number()).optional(),\n});\n\nconst ClerkUserSchema = z.object({\n fullName: z.string().nullish(),\n username: z.string().nullish(),\n firstName: z.string().nullish(),\n lastName: z.string().nullish(),\n id: z.string().optional(),\n primaryEmailAddress: z\n .object({\n emailAddress: z.string().nullable(),\n })\n .nullish(),\n unsafeMetadata: ClerkJazzCredentialsSchema.or(z.object({})),\n update: z.function({\n input: [\n z.object({\n unsafeMetadata: ClerkJazzCredentialsSchema,\n }),\n ],\n output: z.promise(z.unknown()),\n }),\n});\n\nexport const ClerkEventSchema = z.object({\n user: ClerkUserSchema.nullish(),\n});\nexport type ClerkEventSchema = z.infer<typeof ClerkEventSchema>;\n\nexport type ClerkUser = z.infer<typeof ClerkUserSchema>;\n\n// Need to provide a permissive type externally to accept\ntype PermissiveClerkUser = Omit<ClerkUser, \"unsafeMetadata\" | \"update\"> & {\n unsafeMetadata: Record<string, unknown>;\n update: (args: {\n unsafeMetadata: Record<string, unknown>;\n }) => Promise<unknown>;\n};\n\nexport type MinimalClerkClient = {\n user: PermissiveClerkUser | null | undefined;\n signOut: () => Promise<void>;\n addListener: (listener: (data: unknown) => void) => void;\n};\n\nexport type ClerkCredentials = {\n jazzAccountID: string;\n jazzAccountSecret: AgentSecret;\n jazzAccountSeed?: number[];\n};\n\n/**\n * Checks if the Clerk user metadata contains the necessary credentials for Jazz auth.\n * **Note**: It does not validate the credentials, only checks if the necessary fields are present in the metadata object.\n */\nexport function isClerkCredentials(\n data: Record<string, unknown> | undefined,\n): data is ClerkCredentials {\n return !!data && \"jazzAccountID\" in data && \"jazzAccountSecret\" in data;\n}\n\ntype ClerkUserWithUnsafeMetadata =\n | Pick<ClerkUser, \"unsafeMetadata\">\n | null\n | undefined;\n\nexport function isClerkAuthStateEqual(\n previousUser: ClerkUserWithUnsafeMetadata,\n newUser: ClerkUserWithUnsafeMetadata,\n) {\n if (Boolean(previousUser) !== Boolean(newUser)) {\n return false;\n }\n\n const previousCredentials = isClerkCredentials(previousUser?.unsafeMetadata)\n ? previousUser?.unsafeMetadata\n : null;\n const newCredentials = isClerkCredentials(newUser?.unsafeMetadata)\n ? newUser?.unsafeMetadata\n : null;\n\n if (!previousCredentials || !newCredentials) {\n return previousCredentials === newCredentials;\n }\n\n return previousCredentials.jazzAccountID === newCredentials.jazzAccountID;\n}\n","import { AgentSecret } from \"cojson\";\nimport { Account, ID } from \"../internal.js\";\nimport { AuthenticateAccountFunction } from \"../types.js\";\nimport { AuthSecretStorage } from \"./AuthSecretStorage.js\";\nimport { KvStore, KvStoreContext } from \"./KvStoreContext.js\";\n\ntype StorageData = {\n accountID: ID<Account>;\n accountSecret: AgentSecret;\n secretSeed?: number[];\n};\n\n/**\n * `DemoAuth` provides a `JazzAuth` object for demo authentication.\n *\n * Demo authentication is useful for quickly testing your app, as it allows you to create new accounts and log in as existing ones.\n *\n * ```\n * import { DemoAuth } from \"jazz-tools\";\n *\n * const auth = new DemoAuth(jazzContext.authenticate, new AuthSecretStorage());\n * ```\n *\n * @category Auth Providers\n */\nexport class DemoAuth {\n constructor(\n private authenticate: AuthenticateAccountFunction,\n private authSecretStorage: AuthSecretStorage,\n ) {}\n\n logIn = async (username: string) => {\n const existingUsers = await this.getExisitingUsersWithData();\n const storageData = existingUsers[username];\n\n if (!storageData?.accountID) {\n throw new Error(\"User not found\");\n }\n\n await this.authenticate({\n accountID: storageData.accountID,\n accountSecret: storageData.accountSecret,\n });\n\n await this.authSecretStorage.set({\n accountID: storageData.accountID,\n accountSecret: storageData.accountSecret,\n secretSeed: storageData.secretSeed\n ? new Uint8Array(storageData.secretSeed)\n : undefined,\n provider: \"demo\",\n });\n };\n\n signUp = async (username: string) => {\n const existingUsers = await this.getExistingUsers();\n if (existingUsers.includes(username)) {\n throw new Error(\"User already registered\");\n }\n\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials) {\n throw new Error(\"No credentials found\");\n }\n\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n currentAccount.profile.$jazz.set(\"name\", username);\n\n await this.authSecretStorage.set({\n accountID: credentials.accountID,\n accountSecret: credentials.accountSecret,\n secretSeed: credentials.secretSeed\n ? new Uint8Array(credentials.secretSeed)\n : undefined,\n provider: \"demo\",\n });\n\n await this.addToExistingUsers(username, {\n accountID: credentials.accountID,\n accountSecret: credentials.accountSecret,\n secretSeed: credentials.secretSeed\n ? Array.from(credentials.secretSeed)\n : undefined,\n });\n };\n\n private async addToExistingUsers(username: string, data: StorageData) {\n const existingUsers = await this.getExisitingUsersWithData();\n\n if (existingUsers[username]) {\n return;\n }\n\n existingUsers[username] = data;\n\n const kvStore = KvStoreContext.getInstance().getStorage();\n await kvStore.set(\"demo-auth-users\", JSON.stringify(existingUsers));\n }\n\n private async getExisitingUsersWithData() {\n const kvStore = KvStoreContext.getInstance().getStorage();\n await migrateExistingUsers(kvStore);\n\n const existingUsers = await kvStore.get(\"demo-auth-users\");\n return existingUsers ? JSON.parse(existingUsers) : {};\n }\n\n getExistingUsers = async () => {\n return Object.keys(await this.getExisitingUsersWithData());\n };\n}\n\nexport function encodeUsername(username: string) {\n return btoa(username)\n .replace(/=/g, \"-\")\n .replace(/\\+/g, \"_\")\n .replace(/\\//g, \".\");\n}\n\nasync function getStorageVersion(kvStore: KvStore) {\n try {\n const version = await kvStore.get(\"demo-auth-storage-version\");\n return version ? parseInt(version) : 1;\n } catch (error) {\n return 1;\n }\n}\n\nasync function setStorageVersion(kvStore: KvStore, version: number) {\n await kvStore.set(\"demo-auth-storage-version\", version.toString());\n}\n\nasync function getExistingUsersList(kvStore: KvStore) {\n const existingUsers = await kvStore.get(\"demo-auth-existing-users\");\n return existingUsers ? existingUsers.split(\",\") : [];\n}\n\n/**\n * Migrates existing users keys to work with any storage.\n */\nasync function migrateExistingUsers(kvStore: KvStore) {\n if ((await getStorageVersion(kvStore)) < 2) {\n const existingUsers = await getExistingUsersList(kvStore);\n\n for (const username of existingUsers) {\n const legacyKey = `demo-auth-existing-users-${username}`;\n const storageData = await kvStore.get(legacyKey);\n if (storageData) {\n await kvStore.set(\n `demo-auth-existing-users-${encodeUsername(username)}`,\n storageData,\n );\n await kvStore.delete(legacyKey);\n }\n }\n\n await setStorageVersion(kvStore, 2);\n }\n\n if ((await getStorageVersion(kvStore)) < 3) {\n const existingUsersList = await getExistingUsersList(kvStore);\n\n const existingUsers: Record<string, StorageData> = {};\n const keysToDelete: string[] = [\"demo-auth-existing-users\"];\n\n for (const username of existingUsersList) {\n const key = `demo-auth-existing-users-${encodeUsername(username)}`;\n const storageData = await kvStore.get(key);\n if (storageData) {\n existingUsers[username] = JSON.parse(storageData);\n keysToDelete.push(key);\n }\n }\n\n await kvStore.set(\"demo-auth-users\", JSON.stringify(existingUsers));\n\n for (const key of keysToDelete) {\n await kvStore.delete(key);\n }\n\n await setStorageVersion(kvStore, 3);\n }\n}\n","import * as bip39 from \"@scure/bip39\";\nimport { entropyToMnemonic } from \"@scure/bip39\";\nimport { CryptoProvider, cojsonInternals } from \"cojson\";\nimport type { ID } from \"../internal.js\";\nimport { Account } from \"../internal.js\";\nimport type {\n AuthenticateAccountFunction,\n RegisterAccountFunction,\n} from \"../types.js\";\nimport { AuthSecretStorage } from \"./AuthSecretStorage.js\";\n\n/**\n * `PassphraseAuth` provides a `JazzAuth` object for passphrase authentication.\n *\n * ```ts\n * import { PassphraseAuth } from \"jazz-tools\";\n *\n * const auth = new PassphraseAuth(crypto, jazzContext.authenticate, new AuthSecretStorage(), wordlist);\n * ```\n *\n * @category Auth Providers\n */\nexport class PassphraseAuth {\n passphrase: string = \"\";\n\n constructor(\n private crypto: CryptoProvider,\n private authenticate: AuthenticateAccountFunction,\n private register: RegisterAccountFunction,\n private authSecretStorage: AuthSecretStorage,\n public wordlist: string[],\n ) {}\n\n logIn = async (passphrase: string) => {\n const { crypto, authenticate } = this;\n\n let secretSeed;\n\n try {\n secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);\n } catch (e) {\n throw new Error(\"Invalid passphrase\");\n }\n\n const accountSecret = crypto.agentSecretFromSecretSeed(secretSeed);\n\n const accountID = cojsonInternals.idforHeader(\n cojsonInternals.accountHeaderForInitialAgentSecret(accountSecret, crypto),\n crypto,\n ) as ID<Account>;\n\n await authenticate({\n accountID,\n accountSecret,\n });\n\n await this.authSecretStorage.set({\n accountID,\n secretSeed,\n accountSecret,\n provider: \"passphrase\",\n });\n\n this.passphrase = passphrase;\n this.notify();\n };\n\n signUp = async (name?: string) => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials || !credentials.secretSeed) {\n throw new Error(\"No credentials found\");\n }\n\n const passphrase = entropyToMnemonic(credentials.secretSeed, this.wordlist);\n\n await this.authSecretStorage.set({\n accountID: credentials.accountID,\n secretSeed: credentials.secretSeed,\n accountSecret: credentials.accountSecret,\n provider: \"passphrase\",\n });\n\n if (name?.trim()) {\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n currentAccount.profile.$jazz.set(\"name\", name);\n }\n\n return passphrase;\n };\n\n registerNewAccount = async (passphrase: string, name: string) => {\n const secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);\n const accountSecret = this.crypto.agentSecretFromSecretSeed(secretSeed);\n const accountID = await this.register(accountSecret, { name });\n\n await this.authSecretStorage.set({\n accountID,\n secretSeed,\n accountSecret,\n provider: \"passphrase\",\n });\n\n return accountID;\n };\n\n getCurrentAccountPassphrase = async () => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials || !credentials.secretSeed) {\n throw new Error(\"No credentials found\");\n }\n\n return entropyToMnemonic(credentials.secretSeed, this.wordlist);\n };\n\n generateRandomPassphrase = () => {\n return entropyToMnemonic(this.crypto.newRandomSecretSeed(), this.wordlist);\n };\n\n loadCurrentAccountPassphrase = async () => {\n const passphrase = await this.getCurrentAccountPassphrase();\n this.passphrase = passphrase;\n this.notify();\n };\n\n listeners = new Set<() => void>();\n subscribe = (callback: () => void) => {\n this.listeners.add(callback);\n\n return () => {\n this.listeners.delete(callback);\n };\n };\n\n notify() {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","import { AccountRole, type InviteSecret, cojsonInternals } from \"cojson\";\nimport { Account } from \"../coValues/account.js\";\nimport type { CoValue, CoValueClassOrSchema } from \"../internal.js\";\n\n/** @category Invite Links */\nexport function createInviteLink<C extends CoValue>(\n value: C,\n role: AccountRole,\n baseURL: string,\n valueHint?: string,\n): string {\n const coValueCore = value.$jazz.raw.core;\n let currentCoValue = coValueCore;\n\n while (currentCoValue.verified.header.ruleset.type === \"ownedByGroup\") {\n currentCoValue = currentCoValue.getGroup().core;\n }\n\n const { ruleset, meta } = currentCoValue.verified.header;\n\n if (ruleset.type !== \"group\" || meta?.type === \"account\") {\n throw new Error(\"Can't create invite link for object without group\");\n }\n\n const group = cojsonInternals.expectGroup(currentCoValue.getCurrentContent());\n const inviteSecret = group.createInvite(role);\n\n return `${baseURL}#/invite/${valueHint ? valueHint + \"/\" : \"\"}${\n value.$jazz.id\n }/${inviteSecret}`;\n}\n\n/** @category Invite Links */\nexport function parseInviteLink(inviteURL: string):\n | {\n valueID: string;\n valueHint?: string;\n inviteSecret: InviteSecret;\n }\n | undefined {\n const url = new URL(inviteURL);\n const parts = url.hash.split(\"/\");\n\n let valueHint: string | undefined;\n let valueID: string | undefined;\n let inviteSecret: InviteSecret | undefined;\n\n if (parts[0] === \"#\" && parts[1] === \"invite\") {\n if (parts.length === 5) {\n valueHint = parts[2];\n valueID = parts[3];\n inviteSecret = parts[4] as InviteSecret;\n } else if (parts.length === 4) {\n valueID = parts[2];\n inviteSecret = parts[3] as InviteSecret;\n }\n\n if (!valueID || !inviteSecret) {\n return undefined;\n }\n return { valueID, inviteSecret, valueHint };\n }\n}\n\n/** @category Invite Links */\nexport function consumeInviteLink<S extends CoValueClassOrSchema>({\n inviteURL,\n as = Account.getMe(),\n forValueHint,\n invitedObjectSchema,\n}: {\n inviteURL: string;\n as?: Account;\n forValueHint?: string;\n invitedObjectSchema: S;\n}): Promise<\n | {\n valueID: string;\n valueHint?: string;\n inviteSecret: InviteSecret;\n }\n | undefined\n> {\n return new Promise((resolve, reject) => {\n const result = parseInviteLink(inviteURL);\n\n if (result && result.valueHint === forValueHint) {\n as.acceptInvite(result.valueID, result.inviteSecret, invitedObjectSchema)\n .then(() => {\n resolve(result);\n })\n .catch(reject);\n } else {\n resolve(undefined);\n }\n });\n}\n","import {\n CoValueCore,\n CojsonInternalTypes,\n CryptoProvider,\n RawAccount,\n RawCoMap,\n cojsonInternals,\n} from \"cojson\";\nimport z from \"zod/v4\";\nimport {\n AnyZodOrCoValueSchema,\n CoMap,\n CoMapSchema,\n CoMapSchemaInit,\n CoValueClass,\n CoreCoMapSchema,\n Group,\n Loaded,\n ResolveQuery,\n ResolveQueryStrict,\n Simplify,\n coMapDefiner,\n coValueClassFromCoValueClassOrSchema,\n exportCoValue,\n importContentPieces,\n loadCoValue,\n} from \"../internal.js\";\nimport { isCoValueId } from \"../lib/utils.js\";\nimport { Account } from \"./account.js\";\n\ntype MessageShape = Record<string, AnyZodOrCoValueSchema>;\n\ntype RequestSchemaDefinition<\n S extends MessageShape,\n R extends ResolveQuery<CoMapSchema<S>> = true,\n> =\n | S\n | {\n schema: S;\n resolve?: R;\n };\n\n/**\n * Configuration options for defining HTTP request/response schemas in Jazz.\n *\n * This interface defines the structure for creating typed HTTP routes with\n * request and response validation using CoMap schemas.\n *\n * @template RequestShape - The shape of the request message schema (must extend MessageShape)\n * @template RequestResolve - The resolve query type for the request CoMap schema\n * @template ResponseShape - The shape of the response message schema (must extend MessageShape)\n * @template ResponseResolve - The resolve query type for the response CoMap schema\n */\ninterface RequestOptions<\n RequestShape extends MessageShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>>,\n ResponseShape extends MessageShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>>,\n> {\n /**\n * The URL endpoint for the HTTP route.\n * This is used by the client to send requests to the server.\n */\n url: string;\n\n /**\n * The id of the worker Account or Group.\n */\n workerId: string;\n\n /**\n * Schema definition for the request payload.\n * Can be either a direct schema object or an object with schema and optional resolve properties.\n * The schema defines the structure and validation rules for incoming requests.\n */\n request: RequestSchemaDefinition<\n RequestShape,\n ResolveQueryStrict<CoMapSchema<RequestShape>, RequestResolve>\n >;\n\n /**\n * Schema definition for the response payload.\n * Can be either a direct schema object or an object with schema and optional resolve properties.\n * The schema defines the structure and validation rules for outgoing responses.\n */\n response: RequestSchemaDefinition<\n ResponseShape,\n ResolveQueryStrict<CoMapSchema<ResponseShape>, ResponseResolve>\n >;\n}\n\ntype AsNullablePayload<T extends MessageShape> = T extends Record<string, never>\n ? undefined\n : never;\ntype MessageValuePayload<T extends MessageShape> =\n | Simplify<CoMapSchemaInit<T>>\n | AsNullablePayload<T>;\n\nfunction createMessageEnvelope<S extends MessageShape>(\n schema: CoreCoMapSchema,\n value: MessageValuePayload<S>,\n owner: Account,\n sharedWith: Account | Group,\n type: \"request\" | \"response\",\n): Loaded<CoMapSchema<S>> {\n const group = Group.create({ owner });\n\n if (type === \"request\") {\n group.addMember(sharedWith, \"writer\");\n } else {\n group.addMember(sharedWith, \"reader\");\n }\n\n // @ts-expect-error - CoreCoMapSchema doesn't have static methods\n return schema.create(value ?? {}, group);\n}\n\n/**\n * Function that exports the input CoValue in a serializable format and prepares the information\n * required for the other side to safely verify the identity of the sender.\n */\nasync function serializeMessagePayload({\n type,\n schema,\n resolve,\n value,\n owner,\n target,\n}: {\n // Skipping type validation here to avoid excessive type complexity that affects the typecheck performance\n type: \"request\" | \"response\";\n schema: CoreCoMapSchema;\n resolve: any;\n value: any;\n owner: Account;\n target: Account | Group;\n}) {\n const me = owner ?? Account.getMe();\n const node = me.$jazz.localNode;\n const crypto = node.crypto;\n\n const agent = node.getCurrentAgent();\n const signerID = agent.currentSignerID();\n const signerSecret = agent.currentSignerSecret();\n\n const envelope = createMessageEnvelope(schema, value, me, target, type);\n\n const contentPieces =\n (await exportCoValue(schema, envelope.$jazz.id, {\n resolve,\n loadAs: me,\n bestEffortResolution: true,\n })) ?? [];\n\n const createdAt = Date.now();\n\n const signPayload = crypto.secureHash({\n contentPieces,\n id: envelope.$jazz.id,\n createdAt,\n signerID,\n });\n\n const authToken = crypto.sign(signerSecret, signPayload);\n\n return {\n contentPieces,\n id: envelope.$jazz.id,\n createdAt,\n authToken,\n signerID,\n };\n}\n\nconst coIdSchema = z.custom<`co_z${string}`>(isCoValueId);\nconst signatureSchema = z.custom<`signature_z${string}`>(\n (value) => typeof value === \"string\" && value.startsWith(\"signature_z\"),\n);\n\nconst requestSchema = z.object({\n contentPieces: z.array(z.json()),\n id: coIdSchema,\n createdAt: z.number(),\n authToken: signatureSchema,\n signerID: z.custom<`signer_z${string}`>(\n (value) => typeof value === \"string\" && value.startsWith(\"signer_z\"),\n ),\n});\n\n/**\n * Function that parses the message payload, verifies the identity of the sender and loads the data.\n *\n * @returns The data from the message.\n */\nasync function handleMessagePayload({\n type,\n schema,\n resolve,\n request,\n loadAs,\n}: {\n type: \"request\" | \"response\";\n // Skipping type validation here to avoid excessive type complexity that affects the typecheck performance\n schema: CoreCoMapSchema;\n resolve: any;\n request: unknown;\n loadAs: Account;\n}) {\n const node = loadAs.$jazz.localNode;\n const crypto = node.crypto;\n\n const requestParsed = requestSchema.safeParse(request);\n\n if (!requestParsed.success) {\n throw new JazzRequestError(\n \"Request payload is not valid\",\n 400,\n requestParsed.error,\n );\n }\n\n const requestData = requestParsed.data;\n\n if (type === \"request\") {\n const core = await node.loadCoValueCore(requestData.id, undefined, true);\n\n // Check if the message has already been handled to prevent replay attacks\n if (core.isAvailable()) {\n const content = core.getCurrentContent() as RawCoMap;\n\n if (content.get(\"$handled\") === loadAs.$jazz.id) {\n throw new JazzRequestError(\"Request payload is already handled\", 400);\n }\n }\n\n // Check if the message is expired as extra protection\n if (requestData.createdAt + 1000 * 60 < Date.now()) {\n throw new JazzRequestError(\"Authentication token is expired\", 401);\n }\n }\n\n // Verify the signature of the message to prevent tampering\n const signPayload = crypto.secureHash({\n contentPieces: requestData.contentPieces,\n id: requestData.id,\n createdAt: requestData.createdAt,\n signerID: requestData.signerID,\n });\n\n if (\n !safeVerifySignature(\n crypto,\n signPayload,\n requestData.signerID,\n requestData.authToken,\n )\n ) {\n throw new JazzRequestError(\"Invalid signature\", 401);\n }\n\n let contentPieces =\n requestData.contentPieces as CojsonInternalTypes.NewContentMessage[];\n\n if (type === \"request\") {\n const coValueContent = contentPieces.find(\n (piece) => piece.id === requestData.id,\n );\n\n if (coValueContent && coValueContent.header) {\n const validValues = cojsonInternals.getDependedOnCoValues(\n coValueContent.header,\n coValueContent,\n );\n validValues.add(requestData.id);\n contentPieces = contentPieces.filter((piece) =>\n validValues.has(piece.id),\n );\n } else {\n contentPieces = [];\n }\n }\n\n importContentPieces(contentPieces, loadAs);\n\n const coValue = await node.loadCoValueCore(requestData.id);\n const accountId = getCoValueCreatorAccountId(coValue);\n\n const madeBy = await Account.load(accountId, {\n loadAs,\n });\n\n if (!madeBy.$isLoaded) {\n throw new JazzRequestError(\"Creator account not found\", 400);\n }\n\n const coSchema = coValueClassFromCoValueClassOrSchema(\n schema,\n ) as CoValueClass<CoMap>;\n const value = await loadCoValue<CoMap, true>(coSchema, requestData.id, {\n resolve,\n loadAs,\n });\n\n if (!value.$isLoaded) {\n throw new JazzRequestError(\"Value not found\", 400);\n }\n\n if (type === \"request\") {\n value.$jazz.raw.set(\"$handled\", loadAs.$jazz.id);\n }\n\n return {\n value: value as unknown,\n madeBy,\n };\n}\n\nfunction parseSchemaAndResolve<\n S extends MessageShape,\n R extends ResolveQuery<CoMapSchema<S>>,\n>(options: RequestSchemaDefinition<S, R>) {\n if (\"schema\" in options) {\n return {\n // Using a type cast to reduce the type complexity\n schema: coMapDefiner(options.schema) as CoreCoMapSchema,\n resolve: options.resolve as any,\n };\n }\n\n return {\n schema: coMapDefiner(options) as CoreCoMapSchema,\n resolve: true as any,\n };\n}\n\nexport class HttpRoute<\n RequestShape extends MessageShape = z.core.$ZodLooseShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>> = any,\n ResponseShape extends MessageShape = z.core.$ZodLooseShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>> = any,\n> {\n private requestDefinition: {\n schema: CoreCoMapSchema;\n resolve: any;\n };\n private responseDefinition: {\n schema: CoreCoMapSchema;\n resolve: any;\n };\n private url: string;\n private workerId: string;\n\n constructor(\n params: RequestOptions<\n RequestShape,\n RequestResolve,\n ResponseShape,\n ResponseResolve\n >,\n ) {\n this.requestDefinition = parseSchemaAndResolve(params.request);\n this.responseDefinition = parseSchemaAndResolve(params.response);\n this.url = params.url;\n this.workerId = params.workerId;\n\n if (params.workerId === undefined) {\n throw new TypeError(\"Worker ID is required\");\n }\n }\n\n async send(\n values: MessageValuePayload<RequestShape>,\n options?: { owner?: Account },\n ): Promise<Loaded<CoMapSchema<ResponseShape>, ResponseResolve>> {\n const as = options?.owner ?? Account.getMe();\n\n const target = await loadWorkerAccountOrGroup(this.workerId, as);\n\n const response = await fetch(this.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n await serializeMessagePayload({\n type: \"request\",\n schema: this.requestDefinition.schema,\n resolve: true, // export only the envelope\n value: values,\n owner: as,\n target,\n }),\n ),\n });\n\n if (!response.ok) {\n if (response.headers.has(\"X-Jazz-Request-Error\")) {\n const error = await response.json();\n throw new JazzRequestError(error.message, error.code, error.details);\n }\n\n throw new JazzRequestError(\"Request failed\", response.status);\n }\n\n const responseBody = await response.json();\n\n const responseParsed = z\n .object({\n type: z.literal(\"success\"),\n payload: z.any(),\n })\n .safeParse(responseBody);\n\n if (!responseParsed.success) {\n throw new JazzRequestError(\n \"Response payload is not valid\",\n 400,\n responseParsed.error,\n );\n }\n\n const data = await handleMessagePayload({\n type: \"response\",\n schema: this.responseDefinition.schema,\n resolve: this.responseDefinition.resolve,\n request: responseParsed.data.payload,\n loadAs: as,\n });\n\n return data.value as Loaded<CoMapSchema<ResponseShape>, ResponseResolve>;\n }\n\n handle = async (\n request: Request,\n as: Account,\n callback: (\n value: Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n madeBy: Account,\n ) =>\n | Promise<MessageValuePayload<ResponseShape>>\n | MessageValuePayload<ResponseShape>,\n ): Promise<Response> => {\n try {\n const response = await this.executeHandleRequest(request, as, callback);\n return response;\n } catch (error) {\n // Serialize the error to make it possible to handle it on the client side\n if (isJazzRequestError(error)) {\n return new Response(JSON.stringify(error.toJSON()), {\n status: error.code,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Jazz-Request-Error\": \"true\",\n },\n });\n }\n\n throw error;\n }\n };\n\n executeHandleRequest = async (\n request: Request,\n as: Account,\n callback: (\n value: Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n madeBy: Account,\n ) =>\n | Promise<MessageValuePayload<ResponseShape>>\n | MessageValuePayload<ResponseShape>,\n ): Promise<Response> => {\n const node = as.$jazz.localNode;\n const body = await request.json();\n const data = await handleMessagePayload({\n type: \"request\",\n schema: this.requestDefinition.schema,\n resolve: this.requestDefinition.resolve,\n request: body,\n loadAs: as,\n });\n\n const tracking = node.syncManager.trackDirtyCoValues();\n\n const responseValue = await callback(\n data.value as Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n data.madeBy,\n );\n\n const responsePayload = await serializeMessagePayload({\n type: \"response\",\n schema: this.responseDefinition.schema,\n resolve: this.responseDefinition.resolve,\n value: responseValue,\n owner: as,\n target: data.madeBy,\n });\n\n const responseBody = JSON.stringify({\n type: \"success\",\n payload: responsePayload,\n });\n\n // TODO: Detect the defer support from the environment\n await Promise.all(\n Array.from(tracking.done(), (id) => node.syncManager.waitForSync(id)),\n );\n\n return new Response(responseBody, {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n };\n\n get requestSchema(): CoMapSchema<RequestShape> {\n return this.requestDefinition.schema as CoMapSchema<RequestShape>;\n }\n\n get responseSchema() {\n return this.responseDefinition.schema as CoMapSchema<ResponseShape>;\n }\n}\n\n/**\n * Define a request route.\n *\n * @param params - The parameters for the request route.\n * @returns The request route.\n *\n * @see {@link https://jazz.tools/docs/react/server-side/http-requests}\n */\nexport function experimental_defineRequest<\n RequestShape extends MessageShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>>,\n ResponseShape extends MessageShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>>,\n>(\n params: RequestOptions<\n RequestShape,\n RequestResolve,\n ResponseShape,\n ResponseResolve\n >,\n) {\n return new HttpRoute(params);\n}\n\nfunction getCoValueCreatorAccountId(coValue: CoValueCore) {\n if (!coValue.isAvailable()) {\n throw new Error(\"Unable to load the request payload\");\n }\n\n const creatorSessionId = coValue.getValidSortedTransactions().at(0)\n ?.txID.sessionID;\n\n if (!creatorSessionId) {\n throw new JazzRequestError(\n \"Request payload is not valid, creator session ID not found\",\n 400,\n );\n }\n\n const accountId =\n cojsonInternals.accountOrAgentIDfromSessionID(creatorSessionId);\n\n if (!isCoValueId(accountId)) {\n throw new JazzRequestError(\n \"Request payload is not valid, the creator is not a valid account\",\n 400,\n );\n }\n\n return accountId;\n}\n\nexport class JazzRequestError {\n public readonly isJazzRequestError = true;\n\n constructor(\n public readonly message: string,\n public readonly code: number,\n public readonly details?: unknown,\n ) {}\n\n toJSON() {\n return { message: this.message, code: this.code, details: this.details };\n }\n}\n\nexport function isJazzRequestError(error: unknown): error is JazzRequestError {\n return (\n error instanceof JazzRequestError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"isJazzRequestError\" in error &&\n Boolean(error.isJazzRequestError))\n );\n}\n\nfunction safeVerifySignature(\n crypto: CryptoProvider,\n signPayload: `hash_z${string}`,\n signerID: `signer_z${string}`,\n authToken: `signature_z${string}`,\n) {\n try {\n return crypto.verify(authToken, signPayload, signerID);\n } catch (error) {\n return false;\n }\n}\n\nasync function loadWorkerAccountOrGroup(id: string, loadAs: Account) {\n const node = loadAs.$jazz.localNode;\n const coValue = await node.loadCoValueCore(id as `co_z${string}`);\n\n if (!coValue.isAvailable()) {\n throw new JazzRequestError(\"Worker account not found\", 400);\n }\n\n const content = coValue.getCurrentContent();\n\n if (content instanceof RawAccount) {\n const account = await Account.load(content.id, {\n loadAs,\n });\n if (!account.$isLoaded) {\n throw new JazzRequestError(\"Worker account not found\", 400);\n }\n return account;\n }\n\n const group = await Group.load(content.id, {\n loadAs,\n });\n\n if (!group.$isLoaded) {\n throw new JazzRequestError(\"Worker group not found\", 400);\n }\n return group;\n}\n\nfunction defaultGetToken(request: Request) {\n const headerValue = request.headers.get(\"Authorization\");\n if (headerValue?.startsWith(\"Jazz \")) {\n return headerValue.replace(\"Jazz \", \"\");\n }\n\n if (headerValue) {\n console.warn(\n \"An Authorization header was found, but it did not start with 'Jazz '. If this is intentional, you can specify the location of the token using the `getToken` option.\",\n );\n }\n\n return undefined;\n}\n\n/**\n * Authenticates a Request by verifying a signed authentication token.\n *\n * - If a token is not provided, the returned account is `undefined` and no error is returned.\n * - If a valid token is provided, the signer account is returned.\n * - If an invalid token is provided, an error is returned detailing the validation error, and the returned account is `undefined`.\n *\n * @see {@link generateAuthToken} for generating a token.\n *\n * Note: This function does not perform any authorization checks, it only verifies if - **when provided** - a token is valid. It is up to the caller to perform any additional authorization checks, if needed.\n *\n * @param request - The request to authenticate.\n * @param options - The options for the authentication.\n * @param options.expiration - The expiration time of the token in milliseconds, defaults to 1 minute.\n * @param options.loadAs - The account to load the token from, defaults to the current active account.\n * @param options.getToken - If specified, this function will be used to get the token from the request. By default the token is expected to be in the `Authorization` header in the form of `Jazz <token>`.\n * @returns The account if it is valid, otherwise an error.\n *\n * @example\n * ```ts\n * const { account, error } = await authenticateRequest(request);\n * if (error) {\n * return new Response(JSON.stringify(error), { status: 401 });\n * }\n * ```\n */\nexport async function authenticateRequest(\n request: Request,\n options?: {\n expiration?: number;\n loadAs?: Account;\n getToken?: (request: Request) => string | undefined | null;\n },\n): Promise<\n | {\n account?: Account;\n error?: never;\n }\n | {\n account?: never;\n error: { message: string; details?: unknown };\n }\n> {\n const token = options?.getToken?.(request) ?? defaultGetToken(request);\n\n if (!token) {\n return {};\n }\n\n const { account, error } = await parseAuthToken(token, {\n loadAs: options?.loadAs,\n expiration: options?.expiration ?? 1000 * 60,\n });\n\n if (error) {\n return { error };\n }\n\n return { account, error };\n}\n\n/**\n * Generates an authentication token for a given account. This token can be used to authenticate a request. See {@link authenticateRequest} for more details.\n *\n * @param as - The account to generate the token for, defaults to the current active account.\n * @returns The authentication token.\n *\n * @example Make a fetch request with the token\n * ```ts\n * const token = generateAuthToken();\n * const response = await fetch(url, {\n * headers: {\n * Authorization: `Jazz ${token}`,\n * },\n * });\n * ```\n */\n\nexport function generateAuthToken(as?: Account) {\n const account = as ?? Account.getMe();\n const node = account.$jazz.localNode;\n const crypto = node.crypto;\n\n const agent = node.getCurrentAgent();\n const signerSecret = agent.currentSignerSecret();\n\n const createdAt = Date.now();\n\n const signPayload = crypto.secureHash({\n id: account.$jazz.id,\n createdAt,\n });\n\n const authToken = crypto.sign(signerSecret, signPayload);\n\n return `${authToken}~${account.$jazz.id}~${createdAt}`;\n}\n\nexport async function parseAuthToken(\n authToken: string,\n options?: { loadAs?: Account; expiration?: number },\n): Promise<\n | { account: Account; error?: never }\n | { account?: never; error: { message: string; details?: unknown } }\n> {\n const expiration = options?.expiration ?? 1_000 * 60; // 1 minute\n\n const parsed = z\n .tuple([signatureSchema, coIdSchema, z.string().transform(Number)])\n .safeParse(authToken.split(\"~\"));\n\n if (!parsed.success) {\n return {\n error: {\n message: \"Invalid token\",\n details: parsed.error,\n },\n };\n }\n\n const [signature, id, createdAt] = parsed.data;\n\n if (createdAt + expiration < Date.now()) {\n return {\n error: {\n message: \"Token expired\",\n },\n };\n }\n\n const account = await Account.load(id, { loadAs: options?.loadAs });\n\n if (!account.$isLoaded) {\n return {\n error: {\n message: \"Failed to load account\",\n details: { id },\n },\n };\n }\n\n const node = account.$jazz.localNode;\n const crypto = node.crypto;\n\n // Verify the signature of the message to prevent tampering\n const signPayload = crypto.secureHash({\n id: account.$jazz.id,\n createdAt: Number(createdAt),\n });\n\n const agentID = account.$jazz.raw.currentAgentID();\n const signerID = crypto.getAgentSignerID(agentID);\n\n if (!crypto.verify(signature, signPayload, signerID)) {\n return {\n error: {\n message: \"Invalid signature\",\n },\n };\n }\n\n return {\n account,\n };\n}\n","export {\n setCustomErrorReporter,\n enableCaptureErrorCause,\n} from \"./subscribe/errorReporting.js\";\n\nexport {\n logger,\n LogLevel,\n} from \"cojson\";\n","export * from \"./exports.js\";\n\nexport {\n cojsonInternals,\n logger,\n LogLevel,\n} from \"cojson\";\n"],"mappings":"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","names":["Account","AuthSecretStorage","Account","AuthSecretStorage","cojsonInternals","cojsonInternals","cojsonInternals","z","z","cojsonInternals","cojsonInternals","logger","LogLevel"]}
1
+ {"version":3,"sources":["../src/tools/auth/clerk/index.ts","../src/tools/auth/clerk/getClerkUsername.ts","../src/tools/auth/clerk/types.ts","../src/tools/auth/DemoAuth.ts","../src/tools/auth/PassphraseAuth.ts","../src/tools/implementation/invites.ts","../src/tools/coValues/request.ts","../src/tools/config.ts","../src/worker/JazzMessageChannel.ts","../src/tools/index.ts"],"sourcesContent":["import {\n Account,\n AuthCredentials,\n AuthSecretStorage,\n AuthenticateAccountFunction,\n} from \"jazz-tools\";\nimport { getClerkUsername } from \"./getClerkUsername.js\";\nimport {\n ClerkCredentials,\n ClerkEventSchema,\n ClerkUser,\n MinimalClerkClient,\n isClerkAuthStateEqual,\n isClerkCredentials,\n} from \"./types.js\";\n\nexport type { MinimalClerkClient };\nexport { isClerkCredentials };\n\nexport class JazzClerkAuth {\n constructor(\n private authenticate: AuthenticateAccountFunction,\n private logOut: () => Promise<void> | void,\n private authSecretStorage: AuthSecretStorage,\n ) {}\n\n /**\n * Loads the Jazz auth data from the Clerk user and sets it in the auth secret storage.\n */\n static loadClerkAuthData(\n credentials: ClerkCredentials,\n storage: AuthSecretStorage,\n ) {\n return storage.set({\n accountID: credentials.jazzAccountID,\n accountSecret: credentials.jazzAccountSecret,\n secretSeed: credentials.jazzAccountSeed\n ? Uint8Array.from(credentials.jazzAccountSeed)\n : undefined,\n provider: \"clerk\",\n });\n }\n\n static async initializeAuth(clerk: MinimalClerkClient) {\n const secretStorage = new AuthSecretStorage();\n\n if (!isClerkCredentials(clerk.user?.unsafeMetadata)) {\n return;\n }\n\n await JazzClerkAuth.loadClerkAuthData(\n clerk.user.unsafeMetadata,\n secretStorage,\n );\n }\n\n private isFirstCall = true;\n private previousUser: Pick<ClerkUser, \"unsafeMetadata\"> | null = null;\n\n registerListener(clerkClient: MinimalClerkClient) {\n this.previousUser = ClerkEventSchema.parse(clerkClient).user ?? null;\n\n // Need to use addListener because the clerk user object is not updated when the user logs in\n return clerkClient.addListener((event) => {\n const parsedEvent = ClerkEventSchema.safeParse(event);\n\n if (!parsedEvent.success) {\n console.error(\"Invalid Clerk event\", parsedEvent.error);\n return;\n }\n\n const user = parsedEvent.data.user ?? null;\n\n if (!isClerkAuthStateEqual(this.previousUser, user) || this.isFirstCall) {\n this.previousUser = user;\n this.onClerkUserChange(user);\n this.isFirstCall = false;\n }\n });\n }\n\n onClerkUserChange = async (clerkUser: ClerkUser | null | undefined) => {\n const isAuthenticated = this.authSecretStorage.isAuthenticated;\n\n // LogOut is driven by Clerk. The framework adapters will need to pass `logOutReplacement` to the `JazzProvider`\n // to make the logOut work correctly.\n if (!clerkUser) {\n if (isAuthenticated) {\n this.authSecretStorage.clear();\n await this.logOut();\n }\n return;\n }\n\n if (isAuthenticated) return;\n\n if (!clerkUser.unsafeMetadata.jazzAccountID) {\n await this.signIn(clerkUser);\n } else {\n await this.logIn(clerkUser);\n }\n };\n\n logIn = async (clerkUser: ClerkUser) => {\n const clerkCredentials = clerkUser.unsafeMetadata;\n if (!isClerkCredentials(clerkCredentials)) {\n throw new Error(\"No credentials found on Clerk\");\n }\n\n const credentials = {\n accountID: clerkCredentials.jazzAccountID,\n accountSecret: clerkCredentials.jazzAccountSecret,\n secretSeed: clerkCredentials.jazzAccountSeed\n ? Uint8Array.from(clerkCredentials.jazzAccountSeed)\n : undefined,\n provider: \"clerk\",\n } satisfies AuthCredentials;\n\n await this.authenticate(credentials);\n\n await JazzClerkAuth.loadClerkAuthData(\n {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed: clerkCredentials.jazzAccountSeed,\n },\n this.authSecretStorage,\n );\n };\n\n signIn = async (clerkUser: ClerkUser) => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials) {\n throw new Error(\"No credentials found\");\n }\n\n const jazzAccountSeed = credentials.secretSeed\n ? Array.from(credentials.secretSeed)\n : undefined;\n\n const clerkCredentials = {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed,\n };\n // user.update will cause the Clerk user change listener to fire; updating this.previousUser beforehand\n // ensures the listener sees the new credentials and does not trigger an unnecessary logIn operation\n this.previousUser = { unsafeMetadata: clerkCredentials };\n\n await clerkUser.update({\n unsafeMetadata: clerkCredentials,\n });\n\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n const username = getClerkUsername(clerkUser);\n\n if (username) {\n currentAccount.profile.$jazz.set(\"name\", username);\n }\n\n await JazzClerkAuth.loadClerkAuthData(\n {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed,\n },\n this.authSecretStorage,\n );\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace BrowserClerkAuth {\n export interface Driver {\n onError: (error: string | Error) => void;\n }\n}\n","import type { ClerkUser } from \"./types.js\";\n\nexport function getClerkUsername(user: ClerkUser) {\n if (user.fullName) {\n return user.fullName;\n }\n\n if (user.firstName) {\n if (user.lastName) {\n return `${user.firstName} ${user.lastName}`;\n }\n\n return user.firstName;\n }\n\n if (user.username) {\n return user.username;\n }\n\n if (user.primaryEmailAddress?.emailAddress) {\n const emailUsername = user.primaryEmailAddress.emailAddress.split(\"@\")[0];\n\n if (emailUsername) {\n return emailUsername;\n }\n }\n\n return user.id;\n}\n","import { type AgentSecret } from \"cojson\";\nimport { z } from \"zod/v4\";\n\nconst ClerkJazzCredentialsSchema = z.object({\n jazzAccountID: z.string(),\n jazzAccountSecret: z.string(),\n jazzAccountSeed: z.array(z.number()).optional(),\n});\n\nconst ClerkUserSchema = z.object({\n fullName: z.string().nullish(),\n username: z.string().nullish(),\n firstName: z.string().nullish(),\n lastName: z.string().nullish(),\n id: z.string().optional(),\n primaryEmailAddress: z\n .object({\n emailAddress: z.string().nullable(),\n })\n .nullish(),\n unsafeMetadata: ClerkJazzCredentialsSchema.or(z.object({})),\n update: z.function({\n input: [\n z.object({\n unsafeMetadata: ClerkJazzCredentialsSchema,\n }),\n ],\n output: z.promise(z.unknown()),\n }),\n});\n\nexport const ClerkEventSchema = z.object({\n user: ClerkUserSchema.nullish(),\n});\nexport type ClerkEventSchema = z.infer<typeof ClerkEventSchema>;\n\nexport type ClerkUser = z.infer<typeof ClerkUserSchema>;\n\n// Need to provide a permissive type externally to accept\ntype PermissiveClerkUser = Omit<ClerkUser, \"unsafeMetadata\" | \"update\"> & {\n unsafeMetadata: Record<string, unknown>;\n update: (args: {\n unsafeMetadata: Record<string, unknown>;\n }) => Promise<unknown>;\n};\n\nexport type MinimalClerkClient = {\n user: PermissiveClerkUser | null | undefined;\n signOut: () => Promise<void>;\n addListener: (listener: (data: unknown) => void) => (() => void) | void;\n};\n\nexport type ClerkCredentials = {\n jazzAccountID: string;\n jazzAccountSecret: AgentSecret;\n jazzAccountSeed?: number[];\n};\n\n/**\n * Checks if the Clerk user metadata contains the necessary credentials for Jazz auth.\n * **Note**: It does not validate the credentials, only checks if the necessary fields are present in the metadata object.\n */\nexport function isClerkCredentials(\n data: Record<string, unknown> | undefined,\n): data is ClerkCredentials {\n return !!data && \"jazzAccountID\" in data && \"jazzAccountSecret\" in data;\n}\n\ntype ClerkUserWithUnsafeMetadata =\n | Pick<ClerkUser, \"unsafeMetadata\">\n | null\n | undefined;\n\nexport function isClerkAuthStateEqual(\n previousUser: ClerkUserWithUnsafeMetadata,\n newUser: ClerkUserWithUnsafeMetadata,\n) {\n if (Boolean(previousUser) !== Boolean(newUser)) {\n return false;\n }\n\n const previousCredentials = isClerkCredentials(previousUser?.unsafeMetadata)\n ? previousUser?.unsafeMetadata\n : null;\n const newCredentials = isClerkCredentials(newUser?.unsafeMetadata)\n ? newUser?.unsafeMetadata\n : null;\n\n if (!previousCredentials || !newCredentials) {\n return previousCredentials === newCredentials;\n }\n\n return previousCredentials.jazzAccountID === newCredentials.jazzAccountID;\n}\n","import { AgentSecret } from \"cojson\";\nimport { Account, ID } from \"../internal.js\";\nimport { AuthenticateAccountFunction } from \"../types.js\";\nimport { AuthSecretStorage } from \"./AuthSecretStorage.js\";\nimport { KvStore, KvStoreContext } from \"./KvStoreContext.js\";\n\ntype StorageData = {\n accountID: ID<Account>;\n accountSecret: AgentSecret;\n secretSeed?: number[];\n};\n\n/**\n * `DemoAuth` provides a `JazzAuth` object for demo authentication.\n *\n * Demo authentication is useful for quickly testing your app, as it allows you to create new accounts and log in as existing ones.\n *\n * ```\n * import { DemoAuth } from \"jazz-tools\";\n *\n * const auth = new DemoAuth(jazzContext.authenticate, new AuthSecretStorage());\n * ```\n *\n * @category Auth Providers\n */\nexport class DemoAuth {\n constructor(\n private authenticate: AuthenticateAccountFunction,\n private authSecretStorage: AuthSecretStorage,\n ) {}\n\n logIn = async (username: string) => {\n const existingUsers = await this.getExisitingUsersWithData();\n const storageData = existingUsers[username];\n\n if (!storageData?.accountID) {\n throw new Error(\"User not found\");\n }\n\n await this.authenticate({\n accountID: storageData.accountID,\n accountSecret: storageData.accountSecret,\n });\n\n await this.authSecretStorage.set({\n accountID: storageData.accountID,\n accountSecret: storageData.accountSecret,\n secretSeed: storageData.secretSeed\n ? new Uint8Array(storageData.secretSeed)\n : undefined,\n provider: \"demo\",\n });\n };\n\n signUp = async (username: string) => {\n const existingUsers = await this.getExistingUsers();\n if (existingUsers.includes(username)) {\n throw new Error(\"User already registered\");\n }\n\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials) {\n throw new Error(\"No credentials found\");\n }\n\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n currentAccount.profile.$jazz.set(\"name\", username);\n\n await this.authSecretStorage.set({\n accountID: credentials.accountID,\n accountSecret: credentials.accountSecret,\n secretSeed: credentials.secretSeed\n ? new Uint8Array(credentials.secretSeed)\n : undefined,\n provider: \"demo\",\n });\n\n await this.addToExistingUsers(username, {\n accountID: credentials.accountID,\n accountSecret: credentials.accountSecret,\n secretSeed: credentials.secretSeed\n ? Array.from(credentials.secretSeed)\n : undefined,\n });\n };\n\n private async addToExistingUsers(username: string, data: StorageData) {\n const existingUsers = await this.getExisitingUsersWithData();\n\n if (existingUsers[username]) {\n return;\n }\n\n existingUsers[username] = data;\n\n const kvStore = KvStoreContext.getInstance().getStorage();\n await kvStore.set(\"demo-auth-users\", JSON.stringify(existingUsers));\n }\n\n private async getExisitingUsersWithData() {\n const kvStore = KvStoreContext.getInstance().getStorage();\n await migrateExistingUsers(kvStore);\n\n const existingUsers = await kvStore.get(\"demo-auth-users\");\n return existingUsers ? JSON.parse(existingUsers) : {};\n }\n\n getExistingUsers = async () => {\n return Object.keys(await this.getExisitingUsersWithData());\n };\n}\n\nexport function encodeUsername(username: string) {\n return btoa(username)\n .replace(/=/g, \"-\")\n .replace(/\\+/g, \"_\")\n .replace(/\\//g, \".\");\n}\n\nasync function getStorageVersion(kvStore: KvStore) {\n try {\n const version = await kvStore.get(\"demo-auth-storage-version\");\n return version ? parseInt(version) : 1;\n } catch (error) {\n return 1;\n }\n}\n\nasync function setStorageVersion(kvStore: KvStore, version: number) {\n await kvStore.set(\"demo-auth-storage-version\", version.toString());\n}\n\nasync function getExistingUsersList(kvStore: KvStore) {\n const existingUsers = await kvStore.get(\"demo-auth-existing-users\");\n return existingUsers ? existingUsers.split(\",\") : [];\n}\n\n/**\n * Migrates existing users keys to work with any storage.\n */\nasync function migrateExistingUsers(kvStore: KvStore) {\n if ((await getStorageVersion(kvStore)) < 2) {\n const existingUsers = await getExistingUsersList(kvStore);\n\n for (const username of existingUsers) {\n const legacyKey = `demo-auth-existing-users-${username}`;\n const storageData = await kvStore.get(legacyKey);\n if (storageData) {\n await kvStore.set(\n `demo-auth-existing-users-${encodeUsername(username)}`,\n storageData,\n );\n await kvStore.delete(legacyKey);\n }\n }\n\n await setStorageVersion(kvStore, 2);\n }\n\n if ((await getStorageVersion(kvStore)) < 3) {\n const existingUsersList = await getExistingUsersList(kvStore);\n\n const existingUsers: Record<string, StorageData> = {};\n const keysToDelete: string[] = [\"demo-auth-existing-users\"];\n\n for (const username of existingUsersList) {\n const key = `demo-auth-existing-users-${encodeUsername(username)}`;\n const storageData = await kvStore.get(key);\n if (storageData) {\n existingUsers[username] = JSON.parse(storageData);\n keysToDelete.push(key);\n }\n }\n\n await kvStore.set(\"demo-auth-users\", JSON.stringify(existingUsers));\n\n for (const key of keysToDelete) {\n await kvStore.delete(key);\n }\n\n await setStorageVersion(kvStore, 3);\n }\n}\n","import * as bip39 from \"@scure/bip39\";\nimport { entropyToMnemonic } from \"@scure/bip39\";\nimport { CryptoProvider, cojsonInternals } from \"cojson\";\nimport type { ID } from \"../internal.js\";\nimport { Account } from \"../internal.js\";\nimport type {\n AuthenticateAccountFunction,\n RegisterAccountFunction,\n} from \"../types.js\";\nimport { AuthSecretStorage } from \"./AuthSecretStorage.js\";\n\n/**\n * `PassphraseAuth` provides a `JazzAuth` object for passphrase authentication.\n *\n * ```ts\n * import { PassphraseAuth } from \"jazz-tools\";\n *\n * const auth = new PassphraseAuth(crypto, jazzContext.authenticate, new AuthSecretStorage(), wordlist);\n * ```\n *\n * @category Auth Providers\n */\nexport class PassphraseAuth {\n passphrase: string = \"\";\n\n constructor(\n private crypto: CryptoProvider,\n private authenticate: AuthenticateAccountFunction,\n private register: RegisterAccountFunction,\n private authSecretStorage: AuthSecretStorage,\n public wordlist: string[],\n ) {}\n\n logIn = async (passphrase: string) => {\n const { crypto, authenticate } = this;\n\n let secretSeed;\n\n try {\n secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);\n } catch (e) {\n throw new Error(\"Invalid passphrase\");\n }\n\n const accountSecret = crypto.agentSecretFromSecretSeed(secretSeed);\n\n const accountID = cojsonInternals.idforHeader(\n cojsonInternals.accountHeaderForInitialAgentSecret(accountSecret, crypto),\n crypto,\n ) as ID<Account>;\n\n await authenticate({\n accountID,\n accountSecret,\n });\n\n await this.authSecretStorage.set({\n accountID,\n secretSeed,\n accountSecret,\n provider: \"passphrase\",\n });\n\n this.passphrase = passphrase;\n this.notify();\n };\n\n signUp = async (name?: string) => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials || !credentials.secretSeed) {\n throw new Error(\"No credentials found\");\n }\n\n const passphrase = entropyToMnemonic(credentials.secretSeed, this.wordlist);\n\n await this.authSecretStorage.set({\n accountID: credentials.accountID,\n secretSeed: credentials.secretSeed,\n accountSecret: credentials.accountSecret,\n provider: \"passphrase\",\n });\n\n if (name?.trim()) {\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n currentAccount.profile.$jazz.set(\"name\", name);\n }\n\n return passphrase;\n };\n\n registerNewAccount = async (passphrase: string, name: string) => {\n const secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);\n const accountSecret = this.crypto.agentSecretFromSecretSeed(secretSeed);\n const accountID = await this.register(accountSecret, { name });\n\n await this.authSecretStorage.set({\n accountID,\n secretSeed,\n accountSecret,\n provider: \"passphrase\",\n });\n\n return accountID;\n };\n\n getCurrentAccountPassphrase = async () => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials || !credentials.secretSeed) {\n throw new Error(\"No credentials found\");\n }\n\n return entropyToMnemonic(credentials.secretSeed, this.wordlist);\n };\n\n generateRandomPassphrase = () => {\n return entropyToMnemonic(this.crypto.newRandomSecretSeed(), this.wordlist);\n };\n\n loadCurrentAccountPassphrase = async () => {\n const passphrase = await this.getCurrentAccountPassphrase();\n this.passphrase = passphrase;\n this.notify();\n };\n\n listeners = new Set<() => void>();\n subscribe = (callback: () => void) => {\n this.listeners.add(callback);\n\n return () => {\n this.listeners.delete(callback);\n };\n };\n\n notify() {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","import { AccountRole, type InviteSecret, cojsonInternals } from \"cojson\";\nimport { Account } from \"../coValues/account.js\";\nimport type { CoValue, CoValueClassOrSchema } from \"../internal.js\";\n\n/** @category Invite Links */\nexport function createInviteLink<C extends CoValue>(\n value: C,\n role: AccountRole,\n baseURL: string,\n valueHint?: string,\n): string {\n const coValueCore = value.$jazz.raw.core;\n let currentCoValue = coValueCore;\n\n while (currentCoValue.verified.header.ruleset.type === \"ownedByGroup\") {\n currentCoValue = currentCoValue.getGroup().core;\n }\n\n const { ruleset, meta } = currentCoValue.verified.header;\n\n if (ruleset.type !== \"group\" || meta?.type === \"account\") {\n throw new Error(\"Can't create invite link for object without group\");\n }\n\n const group = cojsonInternals.expectGroup(currentCoValue.getCurrentContent());\n const inviteSecret = group.createInvite(role);\n\n return `${baseURL}#/invite/${valueHint ? valueHint + \"/\" : \"\"}${\n value.$jazz.id\n }/${inviteSecret}`;\n}\n\n/** @category Invite Links */\nexport function parseInviteLink(inviteURL: string):\n | {\n valueID: string;\n valueHint?: string;\n inviteSecret: InviteSecret;\n }\n | undefined {\n const url = new URL(inviteURL);\n const parts = url.hash.split(\"/\");\n\n let valueHint: string | undefined;\n let valueID: string | undefined;\n let inviteSecret: InviteSecret | undefined;\n\n if (parts[0] === \"#\" && parts[1] === \"invite\") {\n if (parts.length === 5) {\n valueHint = parts[2];\n valueID = parts[3];\n inviteSecret = parts[4] as InviteSecret;\n } else if (parts.length === 4) {\n valueID = parts[2];\n inviteSecret = parts[3] as InviteSecret;\n }\n\n if (!valueID || !inviteSecret) {\n return undefined;\n }\n return { valueID, inviteSecret, valueHint };\n }\n}\n\n/** @category Invite Links */\nexport function consumeInviteLink<S extends CoValueClassOrSchema>({\n inviteURL,\n as = Account.getMe(),\n forValueHint,\n invitedObjectSchema,\n}: {\n inviteURL: string;\n as?: Account;\n forValueHint?: string;\n invitedObjectSchema: S;\n}): Promise<\n | {\n valueID: string;\n valueHint?: string;\n inviteSecret: InviteSecret;\n }\n | undefined\n> {\n return new Promise((resolve, reject) => {\n const result = parseInviteLink(inviteURL);\n\n if (result && result.valueHint === forValueHint) {\n as.acceptInvite(result.valueID, result.inviteSecret, invitedObjectSchema)\n .then(() => {\n resolve(result);\n })\n .catch(reject);\n } else {\n resolve(undefined);\n }\n });\n}\n","import {\n CoValueCore,\n CojsonInternalTypes,\n CryptoProvider,\n RawAccount,\n RawCoMap,\n cojsonInternals,\n} from \"cojson\";\nimport z from \"zod/v4\";\nimport {\n AnyZodOrCoValueSchema,\n CoMap,\n CoMapSchema,\n CoMapSchemaInit,\n CoValueClass,\n CoreCoMapSchema,\n Group,\n Loaded,\n ResolveQuery,\n ResolveQueryStrict,\n Simplify,\n coMapDefiner,\n coValueClassFromCoValueClassOrSchema,\n exportCoValue,\n importContentPieces,\n loadCoValue,\n} from \"../internal.js\";\nimport { isCoValueId } from \"../lib/utils.js\";\nimport { Account } from \"./account.js\";\n\ntype MessageShape = Record<string, AnyZodOrCoValueSchema>;\n\ntype RequestSchemaDefinition<\n S extends MessageShape,\n R extends ResolveQuery<CoMapSchema<S>> = true,\n> =\n | S\n | {\n schema: S;\n resolve?: R;\n };\n\n/**\n * Configuration options for defining HTTP request/response schemas in Jazz.\n *\n * This interface defines the structure for creating typed HTTP routes with\n * request and response validation using CoMap schemas.\n *\n * @template RequestShape - The shape of the request message schema (must extend MessageShape)\n * @template RequestResolve - The resolve query type for the request CoMap schema\n * @template ResponseShape - The shape of the response message schema (must extend MessageShape)\n * @template ResponseResolve - The resolve query type for the response CoMap schema\n */\ninterface RequestOptions<\n RequestShape extends MessageShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>>,\n ResponseShape extends MessageShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>>,\n> {\n /**\n * The URL endpoint for the HTTP route.\n * This is used by the client to send requests to the server.\n */\n url: string;\n\n /**\n * The id of the worker Account or Group.\n */\n workerId: string;\n\n /**\n * Schema definition for the request payload.\n * Can be either a direct schema object or an object with schema and optional resolve properties.\n * The schema defines the structure and validation rules for incoming requests.\n */\n request: RequestSchemaDefinition<\n RequestShape,\n ResolveQueryStrict<CoMapSchema<RequestShape>, RequestResolve>\n >;\n\n /**\n * Schema definition for the response payload.\n * Can be either a direct schema object or an object with schema and optional resolve properties.\n * The schema defines the structure and validation rules for outgoing responses.\n */\n response: RequestSchemaDefinition<\n ResponseShape,\n ResolveQueryStrict<CoMapSchema<ResponseShape>, ResponseResolve>\n >;\n}\n\ntype AsNullablePayload<T extends MessageShape> = T extends Record<string, never>\n ? undefined\n : never;\ntype MessageValuePayload<T extends MessageShape> =\n | Simplify<CoMapSchemaInit<T>>\n | AsNullablePayload<T>;\n\nfunction createMessageEnvelope<S extends MessageShape>(\n schema: CoreCoMapSchema,\n value: MessageValuePayload<S>,\n owner: Account,\n sharedWith: Account | Group,\n type: \"request\" | \"response\",\n): Loaded<CoMapSchema<S>> {\n const group = Group.create({ owner });\n\n if (type === \"request\") {\n group.addMember(sharedWith, \"writer\");\n } else {\n group.addMember(sharedWith, \"reader\");\n }\n\n // @ts-expect-error - CoreCoMapSchema doesn't have static methods\n return schema.create(value ?? {}, group);\n}\n\n/**\n * Function that exports the input CoValue in a serializable format and prepares the information\n * required for the other side to safely verify the identity of the sender.\n */\nasync function serializeMessagePayload({\n type,\n schema,\n resolve,\n value,\n owner,\n target,\n}: {\n // Skipping type validation here to avoid excessive type complexity that affects the typecheck performance\n type: \"request\" | \"response\";\n schema: CoreCoMapSchema;\n resolve: any;\n value: any;\n owner: Account;\n target: Account | Group;\n}) {\n const me = owner ?? Account.getMe();\n const node = me.$jazz.localNode;\n const crypto = node.crypto;\n\n const agent = node.getCurrentAgent();\n const signerID = agent.currentSignerID();\n const signerSecret = agent.currentSignerSecret();\n\n const envelope = createMessageEnvelope(schema, value, me, target, type);\n\n const contentPieces =\n (await exportCoValue(schema, envelope.$jazz.id, {\n resolve,\n loadAs: me,\n bestEffortResolution: true,\n })) ?? [];\n\n const createdAt = Date.now();\n\n const signPayload = crypto.secureHash({\n contentPieces,\n id: envelope.$jazz.id,\n createdAt,\n signerID,\n });\n\n const authToken = crypto.sign(signerSecret, signPayload);\n\n return {\n contentPieces,\n id: envelope.$jazz.id,\n createdAt,\n authToken,\n signerID,\n };\n}\n\nconst coIdSchema = z.custom<`co_z${string}`>(isCoValueId);\nconst signatureSchema = z.custom<`signature_z${string}`>(\n (value) => typeof value === \"string\" && value.startsWith(\"signature_z\"),\n);\n\nconst requestSchema = z.object({\n contentPieces: z.array(z.json()),\n id: coIdSchema,\n createdAt: z.number(),\n authToken: signatureSchema,\n signerID: z.custom<`signer_z${string}`>(\n (value) => typeof value === \"string\" && value.startsWith(\"signer_z\"),\n ),\n});\n\n/**\n * Function that parses the message payload, verifies the identity of the sender and loads the data.\n *\n * @returns The data from the message.\n */\nasync function handleMessagePayload({\n type,\n schema,\n resolve,\n request,\n loadAs,\n}: {\n type: \"request\" | \"response\";\n // Skipping type validation here to avoid excessive type complexity that affects the typecheck performance\n schema: CoreCoMapSchema;\n resolve: any;\n request: unknown;\n loadAs: Account;\n}) {\n const node = loadAs.$jazz.localNode;\n const crypto = node.crypto;\n\n const requestParsed = requestSchema.safeParse(request);\n\n if (!requestParsed.success) {\n throw new JazzRequestError(\n \"Request payload is not valid\",\n 400,\n requestParsed.error,\n );\n }\n\n const requestData = requestParsed.data;\n\n if (type === \"request\") {\n const core = await node.loadCoValueCore(requestData.id, undefined, true);\n\n // Check if the message has already been handled to prevent replay attacks\n if (core.isAvailable()) {\n const content = core.getCurrentContent() as RawCoMap;\n\n if (content.get(\"$handled\") === loadAs.$jazz.id) {\n throw new JazzRequestError(\"Request payload is already handled\", 400);\n }\n }\n\n // Check if the message is expired as extra protection\n if (requestData.createdAt + 1000 * 60 < Date.now()) {\n throw new JazzRequestError(\"Authentication token is expired\", 401);\n }\n }\n\n // Verify the signature of the message to prevent tampering\n const signPayload = crypto.secureHash({\n contentPieces: requestData.contentPieces,\n id: requestData.id,\n createdAt: requestData.createdAt,\n signerID: requestData.signerID,\n });\n\n if (\n !safeVerifySignature(\n crypto,\n signPayload,\n requestData.signerID,\n requestData.authToken,\n )\n ) {\n throw new JazzRequestError(\"Invalid signature\", 401);\n }\n\n let contentPieces =\n requestData.contentPieces as CojsonInternalTypes.NewContentMessage[];\n\n if (type === \"request\") {\n const coValueContent = contentPieces.find(\n (piece) => piece.id === requestData.id,\n );\n\n if (coValueContent && coValueContent.header) {\n const validValues = cojsonInternals.getDependedOnCoValues(\n coValueContent.header,\n coValueContent,\n );\n validValues.add(requestData.id);\n contentPieces = contentPieces.filter((piece) =>\n validValues.has(piece.id),\n );\n } else {\n contentPieces = [];\n }\n }\n\n importContentPieces(contentPieces, loadAs);\n\n const coValue = await node.loadCoValueCore(requestData.id);\n const accountId = getCoValueCreatorAccountId(coValue);\n\n const madeBy = await Account.load(accountId, {\n loadAs,\n });\n\n if (!madeBy.$isLoaded) {\n throw new JazzRequestError(\"Creator account not found\", 400);\n }\n\n const coSchema = coValueClassFromCoValueClassOrSchema(\n schema,\n ) as CoValueClass<CoMap>;\n const value = await loadCoValue<CoMap, true>(coSchema, requestData.id, {\n resolve,\n loadAs,\n });\n\n if (!value.$isLoaded) {\n throw new JazzRequestError(\"Value not found\", 400);\n }\n\n if (type === \"request\") {\n value.$jazz.raw.set(\"$handled\", loadAs.$jazz.id);\n }\n\n return {\n value: value as unknown,\n madeBy,\n };\n}\n\nfunction parseSchemaAndResolve<\n S extends MessageShape,\n R extends ResolveQuery<CoMapSchema<S>>,\n>(options: RequestSchemaDefinition<S, R>) {\n if (\"schema\" in options) {\n return {\n // Using a type cast to reduce the type complexity\n schema: coMapDefiner(options.schema) as CoreCoMapSchema,\n resolve: options.resolve as any,\n };\n }\n\n return {\n schema: coMapDefiner(options) as CoreCoMapSchema,\n resolve: true as any,\n };\n}\n\nexport class HttpRoute<\n RequestShape extends MessageShape = z.core.$ZodLooseShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>> = any,\n ResponseShape extends MessageShape = z.core.$ZodLooseShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>> = any,\n> {\n private requestDefinition: {\n schema: CoreCoMapSchema;\n resolve: any;\n };\n private responseDefinition: {\n schema: CoreCoMapSchema;\n resolve: any;\n };\n private url: string;\n private workerId: string;\n\n constructor(\n params: RequestOptions<\n RequestShape,\n RequestResolve,\n ResponseShape,\n ResponseResolve\n >,\n ) {\n this.requestDefinition = parseSchemaAndResolve(params.request);\n this.responseDefinition = parseSchemaAndResolve(params.response);\n this.url = params.url;\n this.workerId = params.workerId;\n\n if (params.workerId === undefined) {\n throw new TypeError(\"Worker ID is required\");\n }\n }\n\n async send(\n values: MessageValuePayload<RequestShape>,\n options?: { owner?: Account },\n ): Promise<Loaded<CoMapSchema<ResponseShape>, ResponseResolve>> {\n const as = options?.owner ?? Account.getMe();\n\n const target = await loadWorkerAccountOrGroup(this.workerId, as);\n\n const response = await fetch(this.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n await serializeMessagePayload({\n type: \"request\",\n schema: this.requestDefinition.schema,\n resolve: true, // export only the envelope\n value: values,\n owner: as,\n target,\n }),\n ),\n });\n\n if (!response.ok) {\n if (response.headers.has(\"X-Jazz-Request-Error\")) {\n const error = await response.json();\n throw new JazzRequestError(error.message, error.code, error.details);\n }\n\n throw new JazzRequestError(\"Request failed\", response.status);\n }\n\n const responseBody = await response.json();\n\n const responseParsed = z\n .object({\n type: z.literal(\"success\"),\n payload: z.any(),\n })\n .safeParse(responseBody);\n\n if (!responseParsed.success) {\n throw new JazzRequestError(\n \"Response payload is not valid\",\n 400,\n responseParsed.error,\n );\n }\n\n const data = await handleMessagePayload({\n type: \"response\",\n schema: this.responseDefinition.schema,\n resolve: this.responseDefinition.resolve,\n request: responseParsed.data.payload,\n loadAs: as,\n });\n\n return data.value as Loaded<CoMapSchema<ResponseShape>, ResponseResolve>;\n }\n\n handle = async (\n request: Request,\n as: Account,\n callback: (\n value: Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n madeBy: Account,\n ) =>\n | Promise<MessageValuePayload<ResponseShape>>\n | MessageValuePayload<ResponseShape>,\n ): Promise<Response> => {\n try {\n const response = await this.executeHandleRequest(request, as, callback);\n return response;\n } catch (error) {\n // Serialize the error to make it possible to handle it on the client side\n if (isJazzRequestError(error)) {\n return new Response(JSON.stringify(error.toJSON()), {\n status: error.code,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Jazz-Request-Error\": \"true\",\n },\n });\n }\n\n throw error;\n }\n };\n\n executeHandleRequest = async (\n request: Request,\n as: Account,\n callback: (\n value: Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n madeBy: Account,\n ) =>\n | Promise<MessageValuePayload<ResponseShape>>\n | MessageValuePayload<ResponseShape>,\n ): Promise<Response> => {\n const node = as.$jazz.localNode;\n const body = await request.json();\n const data = await handleMessagePayload({\n type: \"request\",\n schema: this.requestDefinition.schema,\n resolve: this.requestDefinition.resolve,\n request: body,\n loadAs: as,\n });\n\n const tracking = node.syncManager.trackDirtyCoValues();\n\n const responseValue = await callback(\n data.value as Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n data.madeBy,\n );\n\n const responsePayload = await serializeMessagePayload({\n type: \"response\",\n schema: this.responseDefinition.schema,\n resolve: this.responseDefinition.resolve,\n value: responseValue,\n owner: as,\n target: data.madeBy,\n });\n\n const responseBody = JSON.stringify({\n type: \"success\",\n payload: responsePayload,\n });\n\n // TODO: Detect the defer support from the environment\n await Promise.all(\n Array.from(tracking.done(), (id) => node.syncManager.waitForSync(id)),\n );\n\n return new Response(responseBody, {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n };\n\n get requestSchema(): CoMapSchema<RequestShape> {\n return this.requestDefinition.schema as CoMapSchema<RequestShape>;\n }\n\n get responseSchema() {\n return this.responseDefinition.schema as CoMapSchema<ResponseShape>;\n }\n}\n\n/**\n * Define a request route.\n *\n * @param params - The parameters for the request route.\n * @returns The request route.\n *\n * @see {@link https://jazz.tools/docs/react/server-side/http-requests}\n */\nexport function experimental_defineRequest<\n RequestShape extends MessageShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>>,\n ResponseShape extends MessageShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>>,\n>(\n params: RequestOptions<\n RequestShape,\n RequestResolve,\n ResponseShape,\n ResponseResolve\n >,\n) {\n return new HttpRoute(params);\n}\n\nfunction getCoValueCreatorAccountId(coValue: CoValueCore) {\n if (!coValue.isAvailable()) {\n throw new Error(\"Unable to load the request payload\");\n }\n\n const creatorSessionId = coValue.getValidSortedTransactions().at(0)\n ?.txID.sessionID;\n\n if (!creatorSessionId) {\n throw new JazzRequestError(\n \"Request payload is not valid, creator session ID not found\",\n 400,\n );\n }\n\n const accountId =\n cojsonInternals.accountOrAgentIDfromSessionID(creatorSessionId);\n\n if (!isCoValueId(accountId)) {\n throw new JazzRequestError(\n \"Request payload is not valid, the creator is not a valid account\",\n 400,\n );\n }\n\n return accountId;\n}\n\nexport class JazzRequestError {\n public readonly isJazzRequestError = true;\n\n constructor(\n public readonly message: string,\n public readonly code: number,\n public readonly details?: unknown,\n ) {}\n\n toJSON() {\n return { message: this.message, code: this.code, details: this.details };\n }\n}\n\nexport function isJazzRequestError(error: unknown): error is JazzRequestError {\n return (\n error instanceof JazzRequestError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"isJazzRequestError\" in error &&\n Boolean(error.isJazzRequestError))\n );\n}\n\nfunction safeVerifySignature(\n crypto: CryptoProvider,\n signPayload: `hash_z${string}`,\n signerID: `signer_z${string}`,\n authToken: `signature_z${string}`,\n) {\n try {\n return crypto.verify(authToken, signPayload, signerID);\n } catch (error) {\n return false;\n }\n}\n\nasync function loadWorkerAccountOrGroup(id: string, loadAs: Account) {\n const node = loadAs.$jazz.localNode;\n const coValue = await node.loadCoValueCore(id as `co_z${string}`);\n\n if (!coValue.isAvailable()) {\n throw new JazzRequestError(\"Worker account not found\", 400);\n }\n\n const content = coValue.getCurrentContent();\n\n if (content instanceof RawAccount) {\n const account = await Account.load(content.id, {\n loadAs,\n });\n if (!account.$isLoaded) {\n throw new JazzRequestError(\"Worker account not found\", 400);\n }\n return account;\n }\n\n const group = await Group.load(content.id, {\n loadAs,\n });\n\n if (!group.$isLoaded) {\n throw new JazzRequestError(\"Worker group not found\", 400);\n }\n return group;\n}\n\nfunction defaultGetToken(request: Request) {\n const headerValue = request.headers.get(\"Authorization\");\n if (headerValue?.startsWith(\"Jazz \")) {\n return headerValue.replace(\"Jazz \", \"\");\n }\n\n if (headerValue) {\n console.warn(\n \"An Authorization header was found, but it did not start with 'Jazz '. If this is intentional, you can specify the location of the token using the `getToken` option.\",\n );\n }\n\n return undefined;\n}\n\n/**\n * Authenticates a Request by verifying a signed authentication token.\n *\n * - If a token is not provided, the returned account is `undefined` and no error is returned.\n * - If a valid token is provided, the signer account is returned.\n * - If an invalid token is provided, an error is returned detailing the validation error, and the returned account is `undefined`.\n *\n * @see {@link generateAuthToken} for generating a token.\n *\n * Note: This function does not perform any authorization checks, it only verifies if - **when provided** - a token is valid. It is up to the caller to perform any additional authorization checks, if needed.\n *\n * @param request - The request to authenticate.\n * @param options - The options for the authentication.\n * @param options.expiration - The expiration time of the token in milliseconds, defaults to 1 minute.\n * @param options.loadAs - The account to load the token from, defaults to the current active account.\n * @param options.getToken - If specified, this function will be used to get the token from the request. By default the token is expected to be in the `Authorization` header in the form of `Jazz <token>`.\n * @returns The account if it is valid, otherwise an error.\n *\n * @example\n * ```ts\n * const { account, error } = await authenticateRequest(request);\n * if (error) {\n * return new Response(JSON.stringify(error), { status: 401 });\n * }\n * ```\n */\nexport async function authenticateRequest(\n request: Request,\n options?: {\n expiration?: number;\n loadAs?: Account;\n getToken?: (request: Request) => string | undefined | null;\n },\n): Promise<\n | {\n account?: Account;\n error?: never;\n }\n | {\n account?: never;\n error: { message: string; details?: unknown };\n }\n> {\n const token = options?.getToken?.(request) ?? defaultGetToken(request);\n\n if (!token) {\n return {};\n }\n\n const { account, error } = await parseAuthToken(token, {\n loadAs: options?.loadAs,\n expiration: options?.expiration ?? 1000 * 60,\n });\n\n if (error) {\n return { error };\n }\n\n return { account, error };\n}\n\n/**\n * Generates an authentication token for a given account. This token can be used to authenticate a request. See {@link authenticateRequest} for more details.\n *\n * @param as - The account to generate the token for, defaults to the current active account.\n * @returns The authentication token.\n *\n * @example Make a fetch request with the token\n * ```ts\n * const token = generateAuthToken();\n * const response = await fetch(url, {\n * headers: {\n * Authorization: `Jazz ${token}`,\n * },\n * });\n * ```\n */\n\nexport function generateAuthToken(as?: Account) {\n const account = as ?? Account.getMe();\n const node = account.$jazz.localNode;\n const crypto = node.crypto;\n\n const agent = node.getCurrentAgent();\n const signerSecret = agent.currentSignerSecret();\n\n const createdAt = Date.now();\n\n const signPayload = crypto.secureHash({\n id: account.$jazz.id,\n createdAt,\n });\n\n const authToken = crypto.sign(signerSecret, signPayload);\n\n return `${authToken}~${account.$jazz.id}~${createdAt}`;\n}\n\nexport async function parseAuthToken(\n authToken: string,\n options?: { loadAs?: Account; expiration?: number },\n): Promise<\n | { account: Account; error?: never }\n | { account?: never; error: { message: string; details?: unknown } }\n> {\n const expiration = options?.expiration ?? 1_000 * 60; // 1 minute\n\n const parsed = z\n .tuple([signatureSchema, coIdSchema, z.string().transform(Number)])\n .safeParse(authToken.split(\"~\"));\n\n if (!parsed.success) {\n return {\n error: {\n message: \"Invalid token\",\n details: parsed.error,\n },\n };\n }\n\n const [signature, id, createdAt] = parsed.data;\n\n if (createdAt + expiration < Date.now()) {\n return {\n error: {\n message: \"Token expired\",\n },\n };\n }\n\n const account = await Account.load(id, { loadAs: options?.loadAs });\n\n if (!account.$isLoaded) {\n return {\n error: {\n message: \"Failed to load account\",\n details: { id },\n },\n };\n }\n\n const node = account.$jazz.localNode;\n const crypto = node.crypto;\n\n // Verify the signature of the message to prevent tampering\n const signPayload = crypto.secureHash({\n id: account.$jazz.id,\n createdAt: Number(createdAt),\n });\n\n const agentID = account.$jazz.raw.currentAgentID();\n const signerID = crypto.getAgentSignerID(agentID);\n\n if (!crypto.verify(signature, signPayload, signerID)) {\n return {\n error: {\n message: \"Invalid signature\",\n },\n };\n }\n\n return {\n account,\n };\n}\n","export {\n setCustomErrorReporter,\n enableCaptureErrorCause,\n} from \"./subscribe/errorReporting.js\";\n\nexport {\n logger,\n LogLevel,\n} from \"cojson\";\n","import { CojsonMessageChannel, type Peer } from \"cojson\";\nimport type {\n WaitForConnectionOptions,\n ExposeOptions,\n PostMessageTarget,\n} from \"cojson/src/CojsonMessageChannel/types.js\";\nimport { Account, AnonymousJazzAgent } from \"jazz-tools\";\nimport { activeAccountContext } from \"../tools/implementation/activeAccountContext.js\";\n\n/**\n * Options for JazzMessageChannel.expose()\n */\nexport interface JazzMessageChannelExposeOptions extends ExposeOptions {\n /**\n * The account or anonymous agent to use for the connection.\n * If not provided, falls back to the active account context.\n */\n loadAs?: Account | AnonymousJazzAgent;\n}\n\n/**\n * JazzMessageChannel provides a high-level API for creating Jazz connections\n * via the MessageChannel API. It wraps cojson's CojsonMessageChannel and\n * automatically manages the node connection.\n */\nexport class JazzMessageChannel {\n /**\n * Expose a Jazz connection to a target.\n * This is the host-side API, typically called from the main thread.\n *\n * @param target - Any object with a postMessage method (Worker, Window, etc.)\n * @param opts - Configuration options including the account to use\n * @returns A promise that resolves once the connection is established\n */\n static async expose(\n target: PostMessageTarget,\n opts: JazzMessageChannelExposeOptions = {},\n ): Promise<void> {\n const { loadAs, ...cojsonOpts } = opts;\n\n // Get account from loadAs or fall back to active account context\n const accountOrAgent = loadAs ?? activeAccountContext.maybeGet();\n\n if (!accountOrAgent) {\n throw new Error(\n \"No account provided and no active account context available\",\n );\n }\n\n const node =\n accountOrAgent instanceof AnonymousJazzAgent\n ? accountOrAgent.node\n : accountOrAgent.$jazz.localNode;\n\n const peer = await CojsonMessageChannel.expose(target, cojsonOpts);\n\n node.syncManager.addPeer(peer);\n }\n\n /**\n * Accept an incoming Jazz connection.\n * Same as cojson CojsonMessageChannel.waitForConnection().\n */\n static waitForConnection(opts?: WaitForConnectionOptions): Promise<Peer> {\n return CojsonMessageChannel.waitForConnection(opts);\n }\n}\n\n// Re-export types for convenience\nexport type {\n WaitForConnectionOptions,\n AcceptFromPortOptions,\n} from \"cojson/src/CojsonMessageChannel/types.js\";\n","export * from \"./exports.js\";\n\nexport {\n cojsonInternals,\n logger,\n LogLevel,\n} from \"cojson\";\n"],"mappings":"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","names":["Account","AuthSecretStorage","Account","AuthSecretStorage","cojsonInternals","cojsonInternals","cojsonInternals","z","z","cojsonInternals","AnonymousJazzAgent","AnonymousJazzAgent","cojsonInternals","logger","LogLevel"]}
@@ -187,7 +187,7 @@ async function createImage(imageBlobOrFile, options, impl) {
187
187
  );
188
188
  if (options?.progressive) {
189
189
  imageCoValue.$jazz.set("progressive", true);
190
- const resizes = [256, 1024, 2048].filter(
190
+ const resizes = [256, 512, 1024, 2048].filter(
191
191
  (s) => s < Math.max(imageCoValue.originalSize[0], imageCoValue.originalSize[1])
192
192
  );
193
193
  for (const size of resizes) {
@@ -224,4 +224,4 @@ export {
224
224
  loadImageBySize,
225
225
  createImageFactory
226
226
  };
227
- //# sourceMappingURL=chunk-3LKBM3G3.js.map
227
+ //# sourceMappingURL=chunk-IRL3KNPO.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/media/utils.ts","../../src/media/create-image-factory.ts"],"sourcesContent":["import type { CoID } from \"cojson\";\nimport { Account, FileStream, ImageDefinition, MaybeLoaded } from \"jazz-tools\";\n\nexport function highestResAvailable(\n image: ImageDefinition,\n wantedWidth: number,\n wantedHeight: number,\n): { width: number; height: number; image: FileStream } | null {\n const availableSizes: [number, number, string][] = image.$jazz.raw\n .keys()\n .filter((key) => /^\\d+x\\d+$/.test(key))\n .map((key) => {\n const [w, h] = key.split(\"x\").map(Number) as [number, number];\n return [w, h, key];\n });\n\n if (availableSizes.length === 0) {\n return image.original.$isLoaded\n ? {\n width: image.originalSize[0],\n height: image.originalSize[1],\n image: image.original,\n }\n : null;\n }\n\n const sortedSizes = availableSizes\n .map((size) => {\n return {\n size,\n match: sizesMatchWanted(size[0], size[1], wantedWidth, wantedHeight),\n isLoaded: isLoaded(\n image.$jazz.raw.get(size[2]) as CoID<any> | undefined,\n ),\n };\n })\n .sort((a, b) => a.match - b.match);\n\n // We try to find the better already loaded image\n // note: `toReversed` is not available in react-native.\n const bestLoaded = [...sortedSizes]\n .reverse()\n .find((el) => el.isLoaded && getImageChunks(image[el.size[2]]));\n\n // if I can't find a good match, let's use the highest resolution\n const bestTarget =\n sortedSizes.find((el) => el.match > 0.95) || sortedSizes.at(-1);\n\n // if the best target is already loaded, we are done\n const bestTargetImage = image[bestTarget!.size[2]];\n if (getImageChunks(bestTargetImage)) {\n return bestTargetImage?.$isLoaded\n ? {\n width: bestTarget!.size[0],\n height: bestTarget!.size[1],\n image: bestTargetImage,\n }\n : null;\n }\n\n // if the best already loaded is not the best target\n // let's trigger the load of the best target\n if (bestLoaded) {\n getImageChunks(bestTargetImage);\n const bestLoadedImage = image[bestLoaded.size[2]];\n return bestLoadedImage?.$isLoaded\n ? {\n width: bestLoaded.size[0],\n height: bestLoaded.size[1],\n image: bestLoadedImage,\n }\n : null;\n }\n\n // if nothing is loaded, then start fetching all the images till the best\n for (let size of sortedSizes) {\n if (size.match <= bestTarget!.match) {\n getImageChunks(image[size.size[2]]);\n }\n }\n\n return null;\n}\n\nfunction getImageChunks(file: MaybeLoaded<FileStream> | undefined) {\n if (!file || !file.$isLoaded) {\n return undefined;\n }\n return file.getChunks();\n}\n\nfunction sizesMatchWanted(\n w: number,\n h: number,\n wantedW: number,\n wantedH: number,\n): number {\n const area1 = w * h;\n const area2 = wantedW * wantedH;\n\n const areaRatio = area1 / area2;\n\n // // Below 0.95 means the image is too small, we don't want to upscale it\n // if (areaRatio < 0.95) {\n // return 9999;\n // }\n\n return areaRatio;\n}\n\nfunction isLoaded(id: CoID<any> | null | undefined): boolean {\n if (!id) {\n return false;\n }\n\n return !!Account.getMe().$jazz.localNode.getLoaded(id);\n}\n\nexport async function loadImage(\n imageOrId: ImageDefinition | string,\n): Promise<{ width: number; height: number; image: FileStream } | null> {\n if (typeof imageOrId === \"string\") {\n const image = await ImageDefinition.load(imageOrId, {\n resolve: {\n original: true,\n },\n });\n\n if (!image.$isLoaded) {\n return null;\n }\n\n return {\n width: image.originalSize[0],\n height: image.originalSize[1],\n image: image.original,\n };\n }\n\n if (!imageOrId.original.$isLoaded) {\n console.warn(\"Unable to find the original image\");\n return null;\n }\n\n const loadedOriginal = await FileStream.load(imageOrId.original.$jazz.id);\n\n if (!loadedOriginal.$isLoaded) {\n console.warn(\"Unable to find the original image\");\n return null;\n }\n\n return {\n width: imageOrId.originalSize[0],\n height: imageOrId.originalSize[1],\n image: loadedOriginal,\n };\n}\n\nexport async function loadImageBySize(\n imageOrId: ImageDefinition | string,\n wantedWidth: number,\n wantedHeight: number,\n): Promise<{ width: number; height: number; image: FileStream } | null> {\n // @ts-expect-error The resolved type for CoMap does not include catchall properties\n const image: MaybeLoaded<ImageDefinition> =\n typeof imageOrId === \"string\"\n ? await ImageDefinition.load(imageOrId)\n : imageOrId;\n\n if (image.$isLoaded === false) {\n return null;\n }\n\n if (image.progressive === false) {\n return loadImage(imageOrId);\n }\n\n const availableSizes: [number, number, string][] = image.$jazz.raw\n .keys()\n .filter((key) => /^\\d+x\\d+$/.test(key))\n .map((key) => {\n const [w, h] = key.split(\"x\").map(Number) as [number, number];\n return [w, h, key];\n });\n\n if (availableSizes.length === 0) {\n return null;\n }\n\n const sortedSizes = availableSizes\n .map((size) => ({\n size,\n match: sizesMatchWanted(size[0], size[1], wantedWidth, wantedHeight),\n }))\n .sort((a, b) => a.match - b.match);\n\n const bestTarget =\n sortedSizes.find((el) => el.match > 0.95) || sortedSizes.at(-1)!;\n\n // The image's `wxh` keys reference FileStream.\n // image[bestTarget.size[2]] returns undefined if FileStream hasn't loaded yet.\n // Since we only need the file's ID to fetch it later, we check the raw _refs\n // which contain only the linked covalue's ID.\n const file = image.$jazz.refs[bestTarget.size[2]];\n\n if (!file) {\n return null;\n }\n\n const loadedFile = await FileStream.load(file.id);\n\n if (!loadedFile.$isLoaded) {\n return null;\n }\n\n return {\n width: bestTarget.size[0],\n height: bestTarget.size[1],\n image: loadedFile,\n };\n}\n","import {\n Account,\n FileStream,\n Group,\n ImageDefinition,\n type Loaded,\n} from \"jazz-tools\";\n\nexport type SourceType = Blob | File | string;\n\nexport type ResizeOutput = Blob | string;\n\nexport type CreateImageOptions = {\n /** The owner of the image. Can be either a Group or Account. If not specified, the current user will be the owner. */\n owner?: Group | Account;\n /**\n * Controls placeholder generation for the image.\n * - `\"blur\"`: Generates a blurred placeholder image (default)\n * - `false`: No placeholder is generated\n * @default \"blur\"\n */\n placeholder?: \"blur\" | false;\n /**\n * Maximum size constraint for the image. The image will be resized to fit within this size while maintaining aspect ratio.\n * If the image is smaller than maxSize in both dimensions, no resizing occurs.\n * @example 1024 // Resizes image to fit within 1024px in the largest dimension\n */\n maxSize?: number; // | [number, number];\n /**\n * The progressive loading pattern is a technique that allows images to load incrementally, starting with a small version and gradually replacing it with a larger version as it becomes available.\n * This is useful for improving the user experience by showing a placeholder while the image is loading.\n *\n * Passing progressive: true to createImage() will create internal smaller versions of the image for future uses.\n *\n * @default false\n */\n progressive?: boolean;\n};\n\nexport type CreateImageReturnType = Loaded<\n typeof ImageDefinition,\n { original: true }\n>;\n\nexport type CreateImageImpl<\n TSourceType = SourceType,\n TResizeOutput = ResizeOutput,\n> = {\n createFileStreamFromSource: (\n imageBlobOrFile: TSourceType | TResizeOutput,\n owner?: Group | Account,\n ) => Promise<FileStream>;\n getImageSize: (\n imageBlobOrFile: TSourceType,\n ) => Promise<{ width: number; height: number }>;\n getPlaceholderBase64: (imageBlobOrFile: TSourceType) => Promise<string>;\n resize: (\n imageBlobOrFile: TSourceType,\n width: number,\n height: number,\n ) => Promise<TResizeOutput>;\n};\n\nexport function createImageFactory<TSourceType, TResizeOutput>(\n impl: CreateImageImpl<TSourceType, TResizeOutput>,\n imageTypeGuard?: (imageBlobOrFile: TSourceType) => void,\n) {\n return (source: TSourceType, options?: CreateImageOptions) => {\n imageTypeGuard?.(source);\n return createImage(source, options ?? {}, impl);\n };\n}\n\nasync function createImage<TSourceType, TResizeOutput>(\n imageBlobOrFile: TSourceType,\n options: CreateImageOptions,\n impl: CreateImageImpl<TSourceType, TResizeOutput>,\n): Promise<CreateImageReturnType> {\n // Get the original size of the image\n const { width: originalWidth, height: originalHeight } =\n await impl.getImageSize(imageBlobOrFile);\n\n const def: {\n originalSize: [number, number];\n progressive: boolean;\n placeholderDataURL: string | undefined;\n original?: FileStream;\n files: Record<string, FileStream>;\n } = {\n originalSize: [originalWidth, originalHeight],\n progressive: false,\n placeholderDataURL: undefined,\n files: {},\n };\n\n // Placeholder\n if (options?.placeholder === \"blur\") {\n def.placeholderDataURL = await impl.getPlaceholderBase64(imageBlobOrFile);\n }\n\n /**\n * Original\n *\n * Save the original image.\n * If the maxSize is set, resize the image to the maxSize if needed\n */\n if (options?.maxSize === undefined) {\n def.original = await impl.createFileStreamFromSource(\n imageBlobOrFile,\n options?.owner,\n );\n def.files[`${originalWidth}x${originalHeight}`] = def.original;\n } else if (\n options?.maxSize >= originalWidth &&\n options?.maxSize >= originalHeight\n ) {\n // no resizes required, just return the original image\n def.original = await impl.createFileStreamFromSource(\n imageBlobOrFile,\n options?.owner,\n );\n def.files[`${originalWidth}x${originalHeight}`] = def.original;\n } else {\n const { width, height } = getNewDimensions(\n originalWidth,\n originalHeight,\n options.maxSize,\n );\n\n const blob = await impl.resize(imageBlobOrFile, width, height);\n def.originalSize = [width, height];\n def.original = await impl.createFileStreamFromSource(blob, options?.owner);\n def.files[`${width}x${height}`] = def.original;\n }\n\n const imageCoValue = ImageDefinition.create(\n {\n originalSize: def.originalSize,\n progressive: def.progressive,\n placeholderDataURL: def.placeholderDataURL,\n original: def.original,\n ...def.files,\n },\n options?.owner,\n );\n\n /**\n * Progressive loading\n *\n * Save a set of resized images using three sizes: 256, 1024, 2048\n *\n * On the client side, the image will be loaded progressively, starting from the smallest size and increasing the size until the original size is reached.\n */\n if (options?.progressive) {\n imageCoValue.$jazz.set(\"progressive\", true);\n\n const resizes = ([256, 1024, 2048] as const).filter(\n (s) =>\n s <\n Math.max(imageCoValue.originalSize[0], imageCoValue.originalSize[1]),\n );\n\n for (const size of resizes) {\n const { width, height } = getNewDimensions(\n originalWidth,\n originalHeight,\n size,\n );\n\n const blob = await impl.resize(imageBlobOrFile, width, height);\n imageCoValue.$jazz.set(\n `${width}x${height}`,\n await impl.createFileStreamFromSource(blob, options?.owner),\n );\n }\n }\n\n return imageCoValue;\n}\n\nconst getNewDimensions = (\n originalWidth: number,\n originalHeight: number,\n maxSize: number,\n) => {\n if (originalWidth > originalHeight) {\n return {\n width: maxSize,\n height: Math.round(maxSize * (originalHeight / originalWidth)),\n };\n }\n\n return {\n width: Math.round(maxSize * (originalWidth / originalHeight)),\n height: maxSize,\n };\n};\n"],"mappings":"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","names":["ImageDefinition"]}
1
+ {"version":3,"sources":["../../src/media/utils.ts","../../src/media/create-image-factory.ts"],"sourcesContent":["import type { CoID } from \"cojson\";\nimport { Account, FileStream, ImageDefinition, MaybeLoaded } from \"jazz-tools\";\n\nexport function highestResAvailable(\n image: ImageDefinition,\n wantedWidth: number,\n wantedHeight: number,\n): { width: number; height: number; image: FileStream } | null {\n const availableSizes: [number, number, string][] = image.$jazz.raw\n .keys()\n .filter((key) => /^\\d+x\\d+$/.test(key))\n .map((key) => {\n const [w, h] = key.split(\"x\").map(Number) as [number, number];\n return [w, h, key];\n });\n\n if (availableSizes.length === 0) {\n return image.original.$isLoaded\n ? {\n width: image.originalSize[0],\n height: image.originalSize[1],\n image: image.original,\n }\n : null;\n }\n\n const sortedSizes = availableSizes\n .map((size) => {\n return {\n size,\n match: sizesMatchWanted(size[0], size[1], wantedWidth, wantedHeight),\n isLoaded: isLoaded(\n image.$jazz.raw.get(size[2]) as CoID<any> | undefined,\n ),\n };\n })\n .sort((a, b) => a.match - b.match);\n\n // We try to find the better already loaded image\n // note: `toReversed` is not available in react-native.\n const bestLoaded = [...sortedSizes]\n .reverse()\n .find((el) => el.isLoaded && getImageChunks(image[el.size[2]]));\n\n // if I can't find a good match, let's use the highest resolution\n const bestTarget =\n sortedSizes.find((el) => el.match > 0.95) || sortedSizes.at(-1);\n\n // if the best target is already loaded, we are done\n const bestTargetImage = image[bestTarget!.size[2]];\n if (getImageChunks(bestTargetImage)) {\n return bestTargetImage?.$isLoaded\n ? {\n width: bestTarget!.size[0],\n height: bestTarget!.size[1],\n image: bestTargetImage,\n }\n : null;\n }\n\n // if the best already loaded is not the best target\n // let's trigger the load of the best target\n if (bestLoaded) {\n getImageChunks(bestTargetImage);\n const bestLoadedImage = image[bestLoaded.size[2]];\n return bestLoadedImage?.$isLoaded\n ? {\n width: bestLoaded.size[0],\n height: bestLoaded.size[1],\n image: bestLoadedImage,\n }\n : null;\n }\n\n // if nothing is loaded, then start fetching all the images till the best\n for (let size of sortedSizes) {\n if (size.match <= bestTarget!.match) {\n getImageChunks(image[size.size[2]]);\n }\n }\n\n return null;\n}\n\nfunction getImageChunks(file: MaybeLoaded<FileStream> | undefined) {\n if (!file || !file.$isLoaded) {\n return undefined;\n }\n return file.getChunks();\n}\n\nfunction sizesMatchWanted(\n w: number,\n h: number,\n wantedW: number,\n wantedH: number,\n): number {\n const area1 = w * h;\n const area2 = wantedW * wantedH;\n\n const areaRatio = area1 / area2;\n\n // // Below 0.95 means the image is too small, we don't want to upscale it\n // if (areaRatio < 0.95) {\n // return 9999;\n // }\n\n return areaRatio;\n}\n\nfunction isLoaded(id: CoID<any> | null | undefined): boolean {\n if (!id) {\n return false;\n }\n\n return !!Account.getMe().$jazz.localNode.getLoaded(id);\n}\n\nexport async function loadImage(\n imageOrId: ImageDefinition | string,\n): Promise<{ width: number; height: number; image: FileStream } | null> {\n if (typeof imageOrId === \"string\") {\n const image = await ImageDefinition.load(imageOrId, {\n resolve: {\n original: true,\n },\n });\n\n if (!image.$isLoaded) {\n return null;\n }\n\n return {\n width: image.originalSize[0],\n height: image.originalSize[1],\n image: image.original,\n };\n }\n\n if (!imageOrId.original.$isLoaded) {\n console.warn(\"Unable to find the original image\");\n return null;\n }\n\n const loadedOriginal = await FileStream.load(imageOrId.original.$jazz.id);\n\n if (!loadedOriginal.$isLoaded) {\n console.warn(\"Unable to find the original image\");\n return null;\n }\n\n return {\n width: imageOrId.originalSize[0],\n height: imageOrId.originalSize[1],\n image: loadedOriginal,\n };\n}\n\nexport async function loadImageBySize(\n imageOrId: ImageDefinition | string,\n wantedWidth: number,\n wantedHeight: number,\n): Promise<{ width: number; height: number; image: FileStream } | null> {\n // @ts-expect-error The resolved type for CoMap does not include catchall properties\n const image: MaybeLoaded<ImageDefinition> =\n typeof imageOrId === \"string\"\n ? await ImageDefinition.load(imageOrId)\n : imageOrId;\n\n if (image.$isLoaded === false) {\n return null;\n }\n\n if (image.progressive === false) {\n return loadImage(imageOrId);\n }\n\n const availableSizes: [number, number, string][] = image.$jazz.raw\n .keys()\n .filter((key) => /^\\d+x\\d+$/.test(key))\n .map((key) => {\n const [w, h] = key.split(\"x\").map(Number) as [number, number];\n return [w, h, key];\n });\n\n if (availableSizes.length === 0) {\n return null;\n }\n\n const sortedSizes = availableSizes\n .map((size) => ({\n size,\n match: sizesMatchWanted(size[0], size[1], wantedWidth, wantedHeight),\n }))\n .sort((a, b) => a.match - b.match);\n\n const bestTarget =\n sortedSizes.find((el) => el.match > 0.95) || sortedSizes.at(-1)!;\n\n // The image's `wxh` keys reference FileStream.\n // image[bestTarget.size[2]] returns undefined if FileStream hasn't loaded yet.\n // Since we only need the file's ID to fetch it later, we check the raw _refs\n // which contain only the linked covalue's ID.\n const file = image.$jazz.refs[bestTarget.size[2]];\n\n if (!file) {\n return null;\n }\n\n const loadedFile = await FileStream.load(file.id);\n\n if (!loadedFile.$isLoaded) {\n return null;\n }\n\n return {\n width: bestTarget.size[0],\n height: bestTarget.size[1],\n image: loadedFile,\n };\n}\n","import {\n Account,\n FileStream,\n Group,\n ImageDefinition,\n type Loaded,\n} from \"jazz-tools\";\n\nexport type SourceType = Blob | File | string;\n\nexport type ResizeOutput = Blob | string;\n\nexport type CreateImageOptions = {\n /** The owner of the image. Can be either a Group or Account. If not specified, the current user will be the owner. */\n owner?: Group | Account;\n /**\n * Controls placeholder generation for the image.\n * - `\"blur\"`: Generates a blurred placeholder image (default)\n * - `false`: No placeholder is generated\n * @default \"blur\"\n */\n placeholder?: \"blur\" | false;\n /**\n * Maximum size constraint for the image. The image will be resized to fit within this size while maintaining aspect ratio.\n * If the image is smaller than maxSize in both dimensions, no resizing occurs.\n * @example 1024 // Resizes image to fit within 1024px in the largest dimension\n */\n maxSize?: number; // | [number, number];\n /**\n * The progressive loading pattern is a technique that allows images to load incrementally, starting with a small version and gradually replacing it with a larger version as it becomes available.\n * This is useful for improving the user experience by showing a placeholder while the image is loading.\n *\n * Passing progressive: true to createImage() will create internal smaller versions of the image for future uses.\n *\n * @default false\n */\n progressive?: boolean;\n};\n\nexport type CreateImageReturnType = Loaded<\n typeof ImageDefinition,\n { original: true }\n>;\n\nexport type CreateImageImpl<\n TSourceType = SourceType,\n TResizeOutput = ResizeOutput,\n> = {\n createFileStreamFromSource: (\n imageBlobOrFile: TSourceType | TResizeOutput,\n owner?: Group | Account,\n ) => Promise<FileStream>;\n getImageSize: (\n imageBlobOrFile: TSourceType,\n ) => Promise<{ width: number; height: number }>;\n getPlaceholderBase64: (imageBlobOrFile: TSourceType) => Promise<string>;\n resize: (\n imageBlobOrFile: TSourceType,\n width: number,\n height: number,\n ) => Promise<TResizeOutput>;\n};\n\nexport function createImageFactory<TSourceType, TResizeOutput>(\n impl: CreateImageImpl<TSourceType, TResizeOutput>,\n imageTypeGuard?: (imageBlobOrFile: TSourceType) => void,\n) {\n return (source: TSourceType, options?: CreateImageOptions) => {\n imageTypeGuard?.(source);\n return createImage(source, options ?? {}, impl);\n };\n}\n\nasync function createImage<TSourceType, TResizeOutput>(\n imageBlobOrFile: TSourceType,\n options: CreateImageOptions,\n impl: CreateImageImpl<TSourceType, TResizeOutput>,\n): Promise<CreateImageReturnType> {\n // Get the original size of the image\n const { width: originalWidth, height: originalHeight } =\n await impl.getImageSize(imageBlobOrFile);\n\n const def: {\n originalSize: [number, number];\n progressive: boolean;\n placeholderDataURL: string | undefined;\n original?: FileStream;\n files: Record<string, FileStream>;\n } = {\n originalSize: [originalWidth, originalHeight],\n progressive: false,\n placeholderDataURL: undefined,\n files: {},\n };\n\n // Placeholder\n if (options?.placeholder === \"blur\") {\n def.placeholderDataURL = await impl.getPlaceholderBase64(imageBlobOrFile);\n }\n\n /**\n * Original\n *\n * Save the original image.\n * If the maxSize is set, resize the image to the maxSize if needed\n */\n if (options?.maxSize === undefined) {\n def.original = await impl.createFileStreamFromSource(\n imageBlobOrFile,\n options?.owner,\n );\n def.files[`${originalWidth}x${originalHeight}`] = def.original;\n } else if (\n options?.maxSize >= originalWidth &&\n options?.maxSize >= originalHeight\n ) {\n // no resizes required, just return the original image\n def.original = await impl.createFileStreamFromSource(\n imageBlobOrFile,\n options?.owner,\n );\n def.files[`${originalWidth}x${originalHeight}`] = def.original;\n } else {\n const { width, height } = getNewDimensions(\n originalWidth,\n originalHeight,\n options.maxSize,\n );\n\n const blob = await impl.resize(imageBlobOrFile, width, height);\n def.originalSize = [width, height];\n def.original = await impl.createFileStreamFromSource(blob, options?.owner);\n def.files[`${width}x${height}`] = def.original;\n }\n\n const imageCoValue = ImageDefinition.create(\n {\n originalSize: def.originalSize,\n progressive: def.progressive,\n placeholderDataURL: def.placeholderDataURL,\n original: def.original,\n ...def.files,\n },\n options?.owner,\n );\n\n /**\n * Progressive loading\n *\n * Save a set of resized images using three sizes: 256, 1024, 2048\n *\n * On the client side, the image will be loaded progressively, starting from the smallest size and increasing the size until the original size is reached.\n */\n if (options?.progressive) {\n imageCoValue.$jazz.set(\"progressive\", true);\n\n const resizes = ([256, 512, 1024, 2048] as const).filter(\n (s) =>\n s <\n Math.max(imageCoValue.originalSize[0], imageCoValue.originalSize[1]),\n );\n\n for (const size of resizes) {\n const { width, height } = getNewDimensions(\n originalWidth,\n originalHeight,\n size,\n );\n\n const blob = await impl.resize(imageBlobOrFile, width, height);\n imageCoValue.$jazz.set(\n `${width}x${height}`,\n await impl.createFileStreamFromSource(blob, options?.owner),\n );\n }\n }\n\n return imageCoValue;\n}\n\nconst getNewDimensions = (\n originalWidth: number,\n originalHeight: number,\n maxSize: number,\n) => {\n if (originalWidth > originalHeight) {\n return {\n width: maxSize,\n height: Math.round(maxSize * (originalHeight / originalWidth)),\n };\n }\n\n return {\n width: Math.round(maxSize * (originalWidth / originalHeight)),\n height: maxSize,\n };\n};\n"],"mappings":"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","names":["ImageDefinition"]}
@@ -1,5 +1,5 @@
1
1
  import type { Account, Group } from "jazz-tools";
2
- import { FileStream } from "jazz-tools";
2
+ import { type FileStream } from "jazz-tools";
3
3
  /**
4
4
  * Creates an ImageDefinition from an image file path with built-in UX features.
5
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"react-native.d.ts","sourceRoot":"","sources":["../../../src/media/create-image/react-native.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAIxC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW;;;;;;;;;+BAcvB,CAAC;AAqHF,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GACtB,OAAO,CAAC,UAAU,CAAC,CAOrB"}
1
+ {"version":3,"file":"react-native.d.ts","sourceRoot":"","sources":["../../../src/media/create-image/react-native.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAM,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAIjD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW;;;;;;;;;+BAcvB,CAAC;AAsHF,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GACtB,OAAO,CAAC,UAAU,CAAC,CASrB"}
@@ -3,7 +3,7 @@ import {
3
3
  highestResAvailable,
4
4
  loadImage,
5
5
  loadImageBySize
6
- } from "./chunk-3LKBM3G3.js";
6
+ } from "./chunk-IRL3KNPO.js";
7
7
 
8
8
  // src/media/create-image/browser.ts
9
9
  import { FileStream } from "jazz-tools";
@@ -3,7 +3,7 @@ import {
3
3
  highestResAvailable,
4
4
  loadImage,
5
5
  loadImageBySize
6
- } from "./chunk-3LKBM3G3.js";
6
+ } from "./chunk-IRL3KNPO.js";
7
7
  export {
8
8
  createImageFactory,
9
9
  highestResAvailable,
@@ -3,10 +3,10 @@ import {
3
3
  highestResAvailable,
4
4
  loadImage,
5
5
  loadImageBySize
6
- } from "./chunk-3LKBM3G3.js";
6
+ } from "./chunk-IRL3KNPO.js";
7
7
 
8
8
  // src/media/create-image/react-native.ts
9
- import { FileStream } from "jazz-tools";
9
+ import { co } from "jazz-tools";
10
10
  import { Image } from "react-native";
11
11
  var createImage = createImageFactory(
12
12
  {
@@ -71,7 +71,7 @@ async function getPlaceholderBase64(filePath) {
71
71
  "Failed to get generate placeholder using expo-image-manipulator"
72
72
  );
73
73
  }
74
- return base64;
74
+ return "data:image/png;base64," + base64;
75
75
  }
76
76
  }
77
77
  async function resize(filePath, width, height) {
@@ -98,7 +98,7 @@ async function resize(filePath, width, height) {
98
98
  return result.uri;
99
99
  }
100
100
  }
101
- function getMimeType(filePath) {
101
+ async function getMimeType(filePath) {
102
102
  return fetch(filePath).then((res) => res.blob()).then((blob) => blob.type);
103
103
  }
104
104
  function contentTypeToFormat(contentType) {
@@ -110,7 +110,7 @@ function contentTypeToFormat(contentType) {
110
110
  async function createFileStreamFromSource(filePath, owner) {
111
111
  const blob = await fetch(filePath).then((res) => res.blob());
112
112
  const arrayBuffer = await toArrayBuffer(blob);
113
- return FileStream.createFromArrayBuffer(arrayBuffer, blob.type, void 0, {
113
+ return co.fileStream().createFromArrayBuffer(arrayBuffer, blob.type, void 0, {
114
114
  owner
115
115
  });
116
116
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/media/create-image/react-native.ts"],"sourcesContent":["import { NativeModules } from \"react-native\";\nimport type ImageResizerType from \"@bam.tech/react-native-image-resizer\";\nimport type ImageManipulatorType from \"expo-image-manipulator\";\nimport type { Account, Group } from \"jazz-tools\";\nimport { FileStream } from \"jazz-tools\";\nimport { Image } from \"react-native\";\nimport { createImageFactory } from \"../create-image-factory\";\n\n/**\n * Creates an ImageDefinition from an image file path with built-in UX features.\n *\n * This function creates a specialized CoValue for managing images in Jazz applications.\n * It supports blurry placeholders, built-in resizing, and progressive loading patterns.\n *\n * @returns Promise that resolves to an ImageDefinition\n *\n * @example\n * ```ts\n * import { createImage } from \"jazz-tools/media\";\n *\n * async function uploadImageFromCamera(imagePath: string) {\n * const image = await createImage(imagePath, {\n * maxSize: 800,\n * placeholder: \"blur\",\n * progressive: false,\n * });\n *\n * return image;\n * }\n * ```\n */\nexport const createImage = createImageFactory(\n {\n getImageSize,\n getPlaceholderBase64,\n createFileStreamFromSource,\n resize,\n },\n (filePath) => {\n if (typeof filePath !== \"string\") {\n throw new Error(\n \"createImage(Blob | File) is not supported on this platform\",\n );\n }\n },\n);\n\nasync function getResizer(): Promise<\n typeof ImageResizerType | typeof ImageManipulatorType\n> {\n try {\n const rnImageResizer = await import(\"@bam.tech/react-native-image-resizer\");\n\n if (rnImageResizer.default !== undefined) {\n return rnImageResizer.default;\n }\n } catch (e) {}\n\n try {\n const expoImageManipulator = await import(\"expo-image-manipulator\");\n if (expoImageManipulator.ImageManipulator !== undefined) {\n return expoImageManipulator;\n }\n } catch (e) {}\n\n throw new Error(\n \"No resizer lib found. Please install `@bam.tech/react-native-image-resizer` or `expo-image-manipulator`\",\n );\n}\n\nasync function getImageSize(\n filePath: string,\n): Promise<{ width: number; height: number }> {\n const { width, height } = await Image.getSize(filePath);\n\n return { width, height };\n}\n\nasync function getPlaceholderBase64(filePath: string): Promise<string> {\n const ImageResizer = await getResizer();\n\n if (\"createResizedImage\" in ImageResizer) {\n const { uri } = await ImageResizer.createResizedImage(\n filePath,\n 8,\n 8,\n \"PNG\",\n 100,\n );\n\n return imageUrlToBase64(uri);\n } else {\n const ctx = ImageResizer.ImageManipulator.manipulate(filePath);\n\n ctx.resize({ width: 8, height: 8 });\n\n const im = await ctx.renderAsync();\n const result = await im.saveAsync({\n base64: true,\n format: ImageResizer.SaveFormat.PNG,\n });\n\n const base64 = result.base64;\n\n if (!base64) {\n throw new Error(\n \"Failed to get generate placeholder using expo-image-manipulator\",\n );\n }\n\n return base64;\n }\n}\n\nasync function resize(\n filePath: string,\n width: number,\n height: number,\n): Promise<string> {\n const ImageResizer = await getResizer();\n\n const mimeType = await getMimeType(filePath);\n\n if (\"createResizedImage\" in ImageResizer) {\n const { uri } = await ImageResizer.createResizedImage(\n filePath,\n width,\n height,\n contentTypeToFormat(mimeType),\n 80,\n );\n\n return uri;\n } else {\n const ctx = ImageResizer.ImageManipulator.manipulate(filePath);\n ctx.resize({ width: width, height: height });\n\n const mime = contentTypeToFormat(mimeType);\n\n const im = await ctx.renderAsync();\n const result = await im.saveAsync({\n format: ImageResizer.SaveFormat[mime],\n compress: 0.8,\n });\n\n return result.uri;\n }\n}\n\nfunction getMimeType(filePath: string): Promise<string> {\n return fetch(filePath)\n .then((res) => res.blob())\n .then((blob) => blob.type);\n}\n\nfunction contentTypeToFormat(contentType: string) {\n if (contentType.includes(\"image/png\")) return \"PNG\";\n if (contentType.includes(\"image/jpeg\")) return \"JPEG\";\n if (contentType.includes(\"image/webp\")) return \"WEBP\";\n return \"PNG\";\n}\n\nexport async function createFileStreamFromSource(\n filePath: string,\n owner?: Account | Group,\n): Promise<FileStream> {\n const blob = await fetch(filePath).then((res) => res.blob());\n const arrayBuffer = await toArrayBuffer(blob);\n\n return FileStream.createFromArrayBuffer(arrayBuffer, blob.type, undefined, {\n owner,\n });\n}\n\n// TODO: look for more efficient way to do this as React Native hasn't blob.arrayBuffer()\nfunction toArrayBuffer(blob: Blob): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n resolve(reader.result as ArrayBuffer);\n };\n reader.onerror = (error) => {\n reject(error);\n };\n reader.readAsArrayBuffer(blob);\n });\n}\n\nasync function imageUrlToBase64(url: string): Promise<string> {\n const response = await fetch(url);\n const blob = await response.blob();\n return new Promise((onSuccess, onError) => {\n try {\n const reader = new FileReader();\n reader.onload = function () {\n onSuccess(reader.result as string);\n };\n reader.readAsDataURL(blob);\n } catch (e) {\n onError(e);\n }\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/media/create-image/react-native.ts"],"sourcesContent":["import type ImageResizerType from \"@bam.tech/react-native-image-resizer\";\nimport type ImageManipulatorType from \"expo-image-manipulator\";\nimport type { Account, Group } from \"jazz-tools\";\nimport { co, type FileStream } from \"jazz-tools\";\nimport { Image } from \"react-native\";\nimport { createImageFactory } from \"../create-image-factory\";\n\n/**\n * Creates an ImageDefinition from an image file path with built-in UX features.\n *\n * This function creates a specialized CoValue for managing images in Jazz applications.\n * It supports blurry placeholders, built-in resizing, and progressive loading patterns.\n *\n * @returns Promise that resolves to an ImageDefinition\n *\n * @example\n * ```ts\n * import { createImage } from \"jazz-tools/media\";\n *\n * async function uploadImageFromCamera(imagePath: string) {\n * const image = await createImage(imagePath, {\n * maxSize: 800,\n * placeholder: \"blur\",\n * progressive: false,\n * });\n *\n * return image;\n * }\n * ```\n */\nexport const createImage = createImageFactory(\n {\n getImageSize,\n getPlaceholderBase64,\n createFileStreamFromSource,\n resize,\n },\n (filePath) => {\n if (typeof filePath !== \"string\") {\n throw new Error(\n \"createImage(Blob | File) is not supported on this platform\",\n );\n }\n },\n);\n\nasync function getResizer(): Promise<\n typeof ImageResizerType | typeof ImageManipulatorType\n> {\n try {\n const rnImageResizer = await import(\"@bam.tech/react-native-image-resizer\");\n\n if (rnImageResizer.default !== undefined) {\n return rnImageResizer.default;\n }\n } catch (e) {}\n\n try {\n const expoImageManipulator = await import(\"expo-image-manipulator\");\n if (expoImageManipulator.ImageManipulator !== undefined) {\n return expoImageManipulator;\n }\n } catch (e) {}\n\n throw new Error(\n \"No resizer lib found. Please install `@bam.tech/react-native-image-resizer` or `expo-image-manipulator`\",\n );\n}\n\nasync function getImageSize(\n filePath: string,\n): Promise<{ width: number; height: number }> {\n const { width, height } = await Image.getSize(filePath);\n\n return { width, height };\n}\n\nasync function getPlaceholderBase64(filePath: string): Promise<string> {\n const ImageResizer = await getResizer();\n\n if (\"createResizedImage\" in ImageResizer) {\n const { uri } = await ImageResizer.createResizedImage(\n filePath,\n 8,\n 8,\n \"PNG\",\n 100,\n );\n\n return imageUrlToBase64(uri);\n } else {\n const ctx = ImageResizer.ImageManipulator.manipulate(filePath);\n\n ctx.resize({ width: 8, height: 8 });\n\n const im = await ctx.renderAsync();\n const result = await im.saveAsync({\n base64: true,\n format: ImageResizer.SaveFormat.PNG,\n });\n\n const base64 = result.base64;\n\n if (!base64) {\n throw new Error(\n \"Failed to get generate placeholder using expo-image-manipulator\",\n );\n }\n\n // Convert base64 to data URL\n return \"data:image/png;base64,\" + base64;\n }\n}\n\nasync function resize(\n filePath: string,\n width: number,\n height: number,\n): Promise<string> {\n const ImageResizer = await getResizer();\n\n const mimeType = await getMimeType(filePath);\n\n if (\"createResizedImage\" in ImageResizer) {\n const { uri } = await ImageResizer.createResizedImage(\n filePath,\n width,\n height,\n contentTypeToFormat(mimeType),\n 80,\n );\n\n return uri;\n } else {\n const ctx = ImageResizer.ImageManipulator.manipulate(filePath);\n ctx.resize({ width: width, height: height });\n\n const mime = contentTypeToFormat(mimeType);\n\n const im = await ctx.renderAsync();\n const result = await im.saveAsync({\n format: ImageResizer.SaveFormat[mime],\n compress: 0.8,\n });\n\n return result.uri;\n }\n}\n\nasync function getMimeType(filePath: string): Promise<string> {\n return fetch(filePath)\n .then((res) => res.blob())\n .then((blob) => blob.type);\n}\n\nfunction contentTypeToFormat(contentType: string) {\n if (contentType.includes(\"image/png\")) return \"PNG\";\n if (contentType.includes(\"image/jpeg\")) return \"JPEG\";\n if (contentType.includes(\"image/webp\")) return \"WEBP\";\n return \"PNG\";\n}\n\nexport async function createFileStreamFromSource(\n filePath: string,\n owner?: Account | Group,\n): Promise<FileStream> {\n const blob = await fetch(filePath).then((res) => res.blob());\n const arrayBuffer = await toArrayBuffer(blob);\n\n return co\n .fileStream()\n .createFromArrayBuffer(arrayBuffer, blob.type, undefined, {\n owner,\n });\n}\n\n// TODO: look for more efficient way to do this as React Native hasn't blob.arrayBuffer()\nfunction toArrayBuffer(blob: Blob): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n resolve(reader.result as ArrayBuffer);\n };\n reader.onerror = (error) => {\n reject(error);\n };\n reader.readAsArrayBuffer(blob);\n });\n}\n\nasync function imageUrlToBase64(url: string): Promise<string> {\n const response = await fetch(url);\n const blob = await response.blob();\n return new Promise((onSuccess, onError) => {\n try {\n const reader = new FileReader();\n reader.onload = function () {\n onSuccess(reader.result as string);\n };\n reader.readAsDataURL(blob);\n } catch (e) {\n onError(e);\n }\n });\n}\n"],"mappings":"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","names":[]}