@metamask/profile-sync-controller 0.8.1 → 0.9.1

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 (72) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/dist/controllers/user-storage/UserStorageController.cjs +55 -14
  3. package/dist/controllers/user-storage/UserStorageController.cjs.map +1 -1
  4. package/dist/controllers/user-storage/UserStorageController.d.cts +12 -3
  5. package/dist/controllers/user-storage/UserStorageController.d.cts.map +1 -1
  6. package/dist/controllers/user-storage/UserStorageController.d.mts +12 -3
  7. package/dist/controllers/user-storage/UserStorageController.d.mts.map +1 -1
  8. package/dist/controllers/user-storage/UserStorageController.mjs +57 -15
  9. package/dist/controllers/user-storage/UserStorageController.mjs.map +1 -1
  10. package/dist/controllers/user-storage/__fixtures__/mockAccounts.cjs +38 -0
  11. package/dist/controllers/user-storage/__fixtures__/mockAccounts.cjs.map +1 -1
  12. package/dist/controllers/user-storage/__fixtures__/mockAccounts.d.cts +26 -0
  13. package/dist/controllers/user-storage/__fixtures__/mockAccounts.d.cts.map +1 -1
  14. package/dist/controllers/user-storage/__fixtures__/mockAccounts.d.mts +26 -0
  15. package/dist/controllers/user-storage/__fixtures__/mockAccounts.d.mts.map +1 -1
  16. package/dist/controllers/user-storage/__fixtures__/mockAccounts.mjs +39 -0
  17. package/dist/controllers/user-storage/__fixtures__/mockAccounts.mjs.map +1 -1
  18. package/dist/controllers/user-storage/__fixtures__/mockResponses.cjs +9 -1
  19. package/dist/controllers/user-storage/__fixtures__/mockResponses.cjs.map +1 -1
  20. package/dist/controllers/user-storage/__fixtures__/mockResponses.d.cts +5 -0
  21. package/dist/controllers/user-storage/__fixtures__/mockResponses.d.cts.map +1 -1
  22. package/dist/controllers/user-storage/__fixtures__/mockResponses.d.mts +5 -0
  23. package/dist/controllers/user-storage/__fixtures__/mockResponses.d.mts.map +1 -1
  24. package/dist/controllers/user-storage/__fixtures__/mockResponses.mjs +7 -0
  25. package/dist/controllers/user-storage/__fixtures__/mockResponses.mjs.map +1 -1
  26. package/dist/controllers/user-storage/__fixtures__/mockServices.cjs +15 -3
  27. package/dist/controllers/user-storage/__fixtures__/mockServices.cjs.map +1 -1
  28. package/dist/controllers/user-storage/__fixtures__/mockServices.d.cts +2 -1
  29. package/dist/controllers/user-storage/__fixtures__/mockServices.d.cts.map +1 -1
  30. package/dist/controllers/user-storage/__fixtures__/mockServices.d.mts +2 -1
  31. package/dist/controllers/user-storage/__fixtures__/mockServices.d.mts.map +1 -1
  32. package/dist/controllers/user-storage/__fixtures__/mockServices.mjs +14 -3
  33. package/dist/controllers/user-storage/__fixtures__/mockServices.mjs.map +1 -1
  34. package/dist/controllers/user-storage/services.cjs +58 -2
  35. package/dist/controllers/user-storage/services.cjs.map +1 -1
  36. package/dist/controllers/user-storage/services.d.cts +10 -1
  37. package/dist/controllers/user-storage/services.d.cts.map +1 -1
  38. package/dist/controllers/user-storage/services.d.mts +10 -1
  39. package/dist/controllers/user-storage/services.d.mts.map +1 -1
  40. package/dist/controllers/user-storage/services.mjs +33 -1
  41. package/dist/controllers/user-storage/services.mjs.map +1 -1
  42. package/dist/controllers/user-storage/utils.cjs +27 -1
  43. package/dist/controllers/user-storage/utils.cjs.map +1 -1
  44. package/dist/controllers/user-storage/utils.d.cts +11 -0
  45. package/dist/controllers/user-storage/utils.d.cts.map +1 -1
  46. package/dist/controllers/user-storage/utils.d.mts +11 -0
  47. package/dist/controllers/user-storage/utils.d.mts.map +1 -1
  48. package/dist/controllers/user-storage/utils.mjs +25 -0
  49. package/dist/controllers/user-storage/utils.mjs.map +1 -1
  50. package/dist/sdk/__fixtures__/mock-userstorage.cjs +4 -2
  51. package/dist/sdk/__fixtures__/mock-userstorage.cjs.map +1 -1
  52. package/dist/sdk/__fixtures__/mock-userstorage.d.cts +1 -1
  53. package/dist/sdk/__fixtures__/mock-userstorage.d.cts.map +1 -1
  54. package/dist/sdk/__fixtures__/mock-userstorage.d.mts +1 -1
  55. package/dist/sdk/__fixtures__/mock-userstorage.d.mts.map +1 -1
  56. package/dist/sdk/__fixtures__/mock-userstorage.mjs +4 -2
  57. package/dist/sdk/__fixtures__/mock-userstorage.mjs.map +1 -1
  58. package/dist/sdk/user-storage.cjs +39 -1
  59. package/dist/sdk/user-storage.cjs.map +1 -1
  60. package/dist/sdk/user-storage.d.cts +2 -1
  61. package/dist/sdk/user-storage.d.cts.map +1 -1
  62. package/dist/sdk/user-storage.d.mts +2 -1
  63. package/dist/sdk/user-storage.d.mts.map +1 -1
  64. package/dist/sdk/user-storage.mjs +39 -1
  65. package/dist/sdk/user-storage.mjs.map +1 -1
  66. package/dist/shared/storage-schema.cjs.map +1 -1
  67. package/dist/shared/storage-schema.d.cts +5 -2
  68. package/dist/shared/storage-schema.d.cts.map +1 -1
  69. package/dist/shared/storage-schema.d.mts +5 -2
  70. package/dist/shared/storage-schema.d.mts.map +1 -1
  71. package/dist/shared/storage-schema.mjs.map +1 -1
  72. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"services.cjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/services.ts"],"names":[],"mappings":"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","sourcesContent":["import log from 'loglevel';\n\nimport encryption from '../../shared/encryption';\nimport { Env, getEnvUrls } from '../../shared/env';\nimport type {\n UserStoragePathWithFeatureAndKey,\n UserStoragePathWithFeatureOnly,\n} from '../../shared/storage-schema';\nimport { createEntryPath } from '../../shared/storage-schema';\nimport type { NativeScrypt } from '../../shared/types/encryption';\n\nconst ENV_URLS = getEnvUrls(Env.PRD);\n\nexport const USER_STORAGE_API: string = ENV_URLS.userStorageApiUrl;\nexport const USER_STORAGE_ENDPOINT = `${USER_STORAGE_API}/api/v1/userstorage`;\n\n/**\n * This is the Server Response shape for a feature entry.\n */\nexport type GetUserStorageResponse = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n HashedKey: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Data: string;\n};\n\nexport type GetUserStorageAllFeatureEntriesResponse = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n HashedKey: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Data: string;\n}[];\n\nexport type UserStorageBaseOptions = {\n bearerToken: string;\n storageKey: string;\n nativeScryptCrypto?: NativeScrypt;\n};\n\nexport type UserStorageOptions = UserStorageBaseOptions & {\n path: UserStoragePathWithFeatureAndKey;\n};\n\nexport type UserStorageAllFeatureEntriesOptions = UserStorageBaseOptions & {\n path: UserStoragePathWithFeatureOnly;\n};\n\n/**\n * User Storage Service - Get Storage Entry.\n *\n * @param opts - User Storage Options\n * @returns The storage entry, or null if fails to find entry\n */\nexport async function getUserStorage(\n opts: UserStorageOptions,\n): Promise<string | null> {\n try {\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedPath = createEntryPath(path, storageKey);\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${encryptedPath}`);\n\n const userStorageResponse = await fetch(url.toString(), {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n });\n\n // Acceptable error - since indicates entry does not exist.\n if (userStorageResponse.status === 404) {\n return null;\n }\n\n if (userStorageResponse.status !== 200) {\n throw new Error('Unable to get User Storage');\n }\n\n const userStorage: GetUserStorageResponse | null =\n await userStorageResponse.json();\n const encryptedData = userStorage?.Data ?? null;\n\n if (!encryptedData) {\n return null;\n }\n\n const decryptedData = await encryption.decryptString(\n encryptedData,\n opts.storageKey,\n nativeScryptCrypto,\n );\n\n return decryptedData;\n } catch (e) {\n log.error('Failed to get user storage', e);\n return null;\n }\n}\n\n/**\n * User Storage Service - Get all storage entries for a specific feature.\n *\n * @param opts - User Storage Options\n * @returns The storage entry, or null if fails to find entry\n */\nexport async function getUserStorageAllFeatureEntries(\n opts: UserStorageAllFeatureEntriesOptions,\n): Promise<string[] | null> {\n try {\n const { bearerToken, path, nativeScryptCrypto } = opts;\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${path}`);\n\n const userStorageResponse = await fetch(url.toString(), {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n });\n\n // Acceptable error - since indicates feature does not exist.\n if (userStorageResponse.status === 404) {\n return null;\n }\n\n if (userStorageResponse.status !== 200) {\n throw new Error('Unable to get User Storage');\n }\n\n const userStorage: GetUserStorageAllFeatureEntriesResponse | null =\n await userStorageResponse.json();\n\n if (!Array.isArray(userStorage)) {\n return null;\n }\n\n const decryptedData = userStorage?.flatMap((entry) => {\n if (!entry.Data) {\n return [];\n }\n\n return encryption.decryptString(\n entry.Data,\n opts.storageKey,\n nativeScryptCrypto,\n );\n });\n\n return (await Promise.allSettled(decryptedData))\n .map((d) => (d.status === 'fulfilled' ? d.value : undefined))\n .filter((d): d is string => d !== undefined);\n } catch (e) {\n log.error('Failed to get user storage', e);\n return null;\n }\n}\n\n/**\n * User Storage Service - Set Storage Entry.\n *\n * @param data - data to store\n * @param opts - storage options\n */\nexport async function upsertUserStorage(\n data: string,\n opts: UserStorageOptions,\n): Promise<void> {\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedData = await encryption.encryptString(\n data,\n opts.storageKey,\n nativeScryptCrypto,\n );\n const encryptedPath = createEntryPath(path, storageKey);\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${encryptedPath}`);\n\n const res = await fetch(url.toString(), {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n body: JSON.stringify({ data: encryptedData }),\n });\n\n if (!res.ok) {\n throw new Error('user-storage - unable to upsert data');\n }\n}\n"]}
1
+ {"version":3,"file":"services.cjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/services.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wDAA2B;AAE3B,gFAAuE;AACvE,8CAAmD;AAMnD,oEAA8D;AAG9D,MAAM,QAAQ,GAAG,IAAA,gBAAU,EAAC,SAAG,CAAC,GAAG,CAAC,CAAC;AAExB,QAAA,gBAAgB,GAAW,QAAQ,CAAC,iBAAiB,CAAC;AACtD,QAAA,qBAAqB,GAAG,GAAG,wBAAgB,qBAAqB,CAAC;AAmC9E;;;;;GAKG;AACI,KAAK,UAAU,cAAc,CAClC,IAAwB;IAExB,IAAI;QACF,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC;QAEnE,MAAM,aAAa,GAAG,IAAA,gCAAe,EAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,6BAAqB,IAAI,aAAa,EAAE,CAAC,CAAC;QAEjE,MAAM,mBAAmB,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACtD,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,WAAW,EAAE;aACvC;SACF,CAAC,CAAC;QAEH,2DAA2D;QAC3D,IAAI,mBAAmB,CAAC,MAAM,KAAK,GAAG,EAAE;YACtC,OAAO,IAAI,CAAC;SACb;QAED,IAAI,mBAAmB,CAAC,MAAM,KAAK,GAAG,EAAE;YACtC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;SAC/C;QAED,MAAM,WAAW,GACf,MAAM,mBAAmB,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,aAAa,GAAG,WAAW,EAAE,IAAI,IAAI,IAAI,CAAC;QAEhD,IAAI,CAAC,aAAa,EAAE;YAClB,OAAO,IAAI,CAAC;SACb;QAED,MAAM,aAAa,GAAG,MAAM,oBAAU,CAAC,aAAa,CAClD,aAAa,EACb,IAAI,CAAC,UAAU,EACf,kBAAkB,CACnB,CAAC;QAEF,OAAO,aAAa,CAAC;KACtB;IAAC,OAAO,CAAC,EAAE;QACV,kBAAG,CAAC,KAAK,CAAC,4BAA4B,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC;KACb;AACH,CAAC;AA5CD,wCA4CC;AAED;;;;;GAKG;AACI,KAAK,UAAU,+BAA+B,CACnD,IAAyC;IAEzC,IAAI;QACF,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC;QACvD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,6BAAqB,IAAI,IAAI,EAAE,CAAC,CAAC;QAExD,MAAM,mBAAmB,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACtD,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,WAAW,EAAE;aACvC;SACF,CAAC,CAAC;QAEH,6DAA6D;QAC7D,IAAI,mBAAmB,CAAC,MAAM,KAAK,GAAG,EAAE;YACtC,OAAO,IAAI,CAAC;SACb;QAED,IAAI,mBAAmB,CAAC,MAAM,KAAK,GAAG,EAAE;YACtC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;SAC/C;QAED,MAAM,WAAW,GACf,MAAM,mBAAmB,CAAC,IAAI,EAAE,CAAC;QAEnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;YAC/B,OAAO,IAAI,CAAC;SACb;QAED,MAAM,aAAa,GAAG,WAAW,EAAE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACnD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;gBACf,OAAO,EAAE,CAAC;aACX;YAED,OAAO,oBAAU,CAAC,aAAa,CAC7B,KAAK,CAAC,IAAI,EACV,IAAI,CAAC,UAAU,EACf,kBAAkB,CACnB,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;aAC7C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;aAC5D,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;KAChD;IAAC,OAAO,CAAC,EAAE;QACV,kBAAG,CAAC,KAAK,CAAC,4BAA4B,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC;KACb;AACH,CAAC;AAjDD,0EAiDC;AAED;;;;;GAKG;AACI,KAAK,UAAU,iBAAiB,CACrC,IAAY,EACZ,IAAwB;IAExB,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAEnE,MAAM,aAAa,GAAG,MAAM,oBAAU,CAAC,aAAa,CAClD,IAAI,EACJ,IAAI,CAAC,UAAU,EACf,kBAAkB,CACnB,CAAC;IACF,MAAM,aAAa,GAAG,IAAA,gCAAe,EAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,6BAAqB,IAAI,aAAa,EAAE,CAAC,CAAC;IAEjE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;QACtC,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;KAC9C,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;QACX,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;KACzD;AACH,CAAC;AA1BD,8CA0BC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,sBAAsB,CAC1C,IAA4C,EAC5C,IAAmC;IAEnC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;QAChB,OAAO;KACR;IAED,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAEnE,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CACrC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QACnB,OAAO;YACL,IAAA,6BAAgB,EAAC,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;YACnC,MAAM,oBAAU,CAAC,aAAa,CAC5B,CAAC,CAAC,CAAC,CAAC,EACJ,IAAI,CAAC,UAAU,EACf,kBAAkB,CACnB;SACF,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,6BAAqB,IAAI,IAAI,EAAE,CAAC,CAAC;IAExD,MAAM,aAAa,GAAG,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IAExD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;QACtC,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;KAC9C,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;QACX,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;KAC/D;AACH,CAAC;AAvCD,wDAuCC","sourcesContent":["import log from 'loglevel';\n\nimport encryption, { createSHA256Hash } from '../../shared/encryption';\nimport { Env, getEnvUrls } from '../../shared/env';\nimport type {\n UserStoragePathWithFeatureAndKey,\n UserStoragePathWithFeatureOnly,\n UserStoragePathWithKeyOnly,\n} from '../../shared/storage-schema';\nimport { createEntryPath } from '../../shared/storage-schema';\nimport type { NativeScrypt } from '../../shared/types/encryption';\n\nconst ENV_URLS = getEnvUrls(Env.PRD);\n\nexport const USER_STORAGE_API: string = ENV_URLS.userStorageApiUrl;\nexport const USER_STORAGE_ENDPOINT = `${USER_STORAGE_API}/api/v1/userstorage`;\n\n/**\n * This is the Server Response shape for a feature entry.\n */\nexport type GetUserStorageResponse = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n HashedKey: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Data: string;\n};\n\nexport type GetUserStorageAllFeatureEntriesResponse = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n HashedKey: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Data: string;\n}[];\n\nexport type UserStorageBaseOptions = {\n bearerToken: string;\n storageKey: string;\n nativeScryptCrypto?: NativeScrypt;\n};\n\nexport type UserStorageOptions = UserStorageBaseOptions & {\n path: UserStoragePathWithFeatureAndKey;\n};\n\nexport type UserStorageAllFeatureEntriesOptions = UserStorageBaseOptions & {\n path: UserStoragePathWithFeatureOnly;\n};\n\nexport type UserStorageBatchUpsertOptions = UserStorageAllFeatureEntriesOptions;\n\n/**\n * User Storage Service - Get Storage Entry.\n *\n * @param opts - User Storage Options\n * @returns The storage entry, or null if fails to find entry\n */\nexport async function getUserStorage(\n opts: UserStorageOptions,\n): Promise<string | null> {\n try {\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedPath = createEntryPath(path, storageKey);\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${encryptedPath}`);\n\n const userStorageResponse = await fetch(url.toString(), {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n });\n\n // Acceptable error - since indicates entry does not exist.\n if (userStorageResponse.status === 404) {\n return null;\n }\n\n if (userStorageResponse.status !== 200) {\n throw new Error('Unable to get User Storage');\n }\n\n const userStorage: GetUserStorageResponse | null =\n await userStorageResponse.json();\n const encryptedData = userStorage?.Data ?? null;\n\n if (!encryptedData) {\n return null;\n }\n\n const decryptedData = await encryption.decryptString(\n encryptedData,\n opts.storageKey,\n nativeScryptCrypto,\n );\n\n return decryptedData;\n } catch (e) {\n log.error('Failed to get user storage', e);\n return null;\n }\n}\n\n/**\n * User Storage Service - Get all storage entries for a specific feature.\n *\n * @param opts - User Storage Options\n * @returns The storage entry, or null if fails to find entry\n */\nexport async function getUserStorageAllFeatureEntries(\n opts: UserStorageAllFeatureEntriesOptions,\n): Promise<string[] | null> {\n try {\n const { bearerToken, path, nativeScryptCrypto } = opts;\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${path}`);\n\n const userStorageResponse = await fetch(url.toString(), {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n });\n\n // Acceptable error - since indicates feature does not exist.\n if (userStorageResponse.status === 404) {\n return null;\n }\n\n if (userStorageResponse.status !== 200) {\n throw new Error('Unable to get User Storage');\n }\n\n const userStorage: GetUserStorageAllFeatureEntriesResponse | null =\n await userStorageResponse.json();\n\n if (!Array.isArray(userStorage)) {\n return null;\n }\n\n const decryptedData = userStorage?.flatMap((entry) => {\n if (!entry.Data) {\n return [];\n }\n\n return encryption.decryptString(\n entry.Data,\n opts.storageKey,\n nativeScryptCrypto,\n );\n });\n\n return (await Promise.allSettled(decryptedData))\n .map((d) => (d.status === 'fulfilled' ? d.value : undefined))\n .filter((d): d is string => d !== undefined);\n } catch (e) {\n log.error('Failed to get user storage', e);\n return null;\n }\n}\n\n/**\n * User Storage Service - Set Storage Entry.\n *\n * @param data - data to store\n * @param opts - storage options\n */\nexport async function upsertUserStorage(\n data: string,\n opts: UserStorageOptions,\n): Promise<void> {\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedData = await encryption.encryptString(\n data,\n opts.storageKey,\n nativeScryptCrypto,\n );\n const encryptedPath = createEntryPath(path, storageKey);\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${encryptedPath}`);\n\n const res = await fetch(url.toString(), {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n body: JSON.stringify({ data: encryptedData }),\n });\n\n if (!res.ok) {\n throw new Error('user-storage - unable to upsert data');\n }\n}\n\n/**\n * User Storage Service - Set multiple storage entries for one specific feature.\n * You cannot use this method to set multiple features at once.\n *\n * @param data - data to store, in the form of an array of [entryKey, entryValue] pairs\n * @param opts - storage options\n */\nexport async function batchUpsertUserStorage(\n data: [UserStoragePathWithKeyOnly, string][],\n opts: UserStorageBatchUpsertOptions,\n): Promise<void> {\n if (!data.length) {\n return;\n }\n\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedData = await Promise.all(\n data.map(async (d) => {\n return [\n createSHA256Hash(d[0] + storageKey),\n await encryption.encryptString(\n d[1],\n opts.storageKey,\n nativeScryptCrypto,\n ),\n ];\n }),\n );\n\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${path}`);\n\n const formattedData = Object.fromEntries(encryptedData);\n\n const res = await fetch(url.toString(), {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n body: JSON.stringify({ data: formattedData }),\n });\n\n if (!res.ok) {\n throw new Error('user-storage - unable to batch upsert data');\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { UserStoragePathWithFeatureAndKey, UserStoragePathWithFeatureOnly } from "../../shared/storage-schema.cjs";
1
+ import type { UserStoragePathWithFeatureAndKey, UserStoragePathWithFeatureOnly, UserStoragePathWithKeyOnly } from "../../shared/storage-schema.cjs";
2
2
  import type { NativeScrypt } from "../../shared/types/encryption.cjs";
3
3
  export declare const USER_STORAGE_API: string;
4
4
  export declare const USER_STORAGE_ENDPOINT: string;
@@ -24,6 +24,7 @@ export type UserStorageOptions = UserStorageBaseOptions & {
24
24
  export type UserStorageAllFeatureEntriesOptions = UserStorageBaseOptions & {
25
25
  path: UserStoragePathWithFeatureOnly;
26
26
  };
27
+ export type UserStorageBatchUpsertOptions = UserStorageAllFeatureEntriesOptions;
27
28
  /**
28
29
  * User Storage Service - Get Storage Entry.
29
30
  *
@@ -45,4 +46,12 @@ export declare function getUserStorageAllFeatureEntries(opts: UserStorageAllFeat
45
46
  * @param opts - storage options
46
47
  */
47
48
  export declare function upsertUserStorage(data: string, opts: UserStorageOptions): Promise<void>;
49
+ /**
50
+ * User Storage Service - Set multiple storage entries for one specific feature.
51
+ * You cannot use this method to set multiple features at once.
52
+ *
53
+ * @param data - data to store, in the form of an array of [entryKey, entryValue] pairs
54
+ * @param opts - storage options
55
+ */
56
+ export declare function batchUpsertUserStorage(data: [UserStoragePathWithKeyOnly, string][], opts: UserStorageBatchUpsertOptions): Promise<void>;
48
57
  //# sourceMappingURL=services.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.cts","sourceRoot":"","sources":["../../../src/controllers/user-storage/services.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gCAAgC,EAChC,8BAA8B,EAC/B,wCAAoC;AAErC,OAAO,KAAK,EAAE,YAAY,EAAE,0CAAsC;AAIlE,eAAO,MAAM,gBAAgB,EAAE,MAAmC,CAAC;AACnE,eAAO,MAAM,qBAAqB,QAA2C,CAAC;AAE9E;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IAEnC,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,uCAAuC,GAAG;IAEpD,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;CACd,EAAE,CAAC;AAEJ,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,YAAY,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,IAAI,EAAE,gCAAgC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG,sBAAsB,GAAG;IACzE,IAAI,EAAE,8BAA8B,CAAC;CACtC,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0CxB;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,mCAAmC,GACxC,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CA+C1B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC,CAuBf"}
1
+ {"version":3,"file":"services.d.cts","sourceRoot":"","sources":["../../../src/controllers/user-storage/services.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gCAAgC,EAChC,8BAA8B,EAC9B,0BAA0B,EAC3B,wCAAoC;AAErC,OAAO,KAAK,EAAE,YAAY,EAAE,0CAAsC;AAIlE,eAAO,MAAM,gBAAgB,EAAE,MAAmC,CAAC;AACnE,eAAO,MAAM,qBAAqB,QAA2C,CAAC;AAE9E;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IAEnC,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,uCAAuC,GAAG;IAEpD,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;CACd,EAAE,CAAC;AAEJ,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,YAAY,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,IAAI,EAAE,gCAAgC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG,sBAAsB,GAAG;IACzE,IAAI,EAAE,8BAA8B,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,mCAAmC,CAAC;AAEhF;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0CxB;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,mCAAmC,GACxC,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CA+C1B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,CAAC,0BAA0B,EAAE,MAAM,CAAC,EAAE,EAC5C,IAAI,EAAE,6BAA6B,GAClC,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -1,4 +1,4 @@
1
- import type { UserStoragePathWithFeatureAndKey, UserStoragePathWithFeatureOnly } from "../../shared/storage-schema.mjs";
1
+ import type { UserStoragePathWithFeatureAndKey, UserStoragePathWithFeatureOnly, UserStoragePathWithKeyOnly } from "../../shared/storage-schema.mjs";
2
2
  import type { NativeScrypt } from "../../shared/types/encryption.mjs";
3
3
  export declare const USER_STORAGE_API: string;
4
4
  export declare const USER_STORAGE_ENDPOINT: string;
@@ -24,6 +24,7 @@ export type UserStorageOptions = UserStorageBaseOptions & {
24
24
  export type UserStorageAllFeatureEntriesOptions = UserStorageBaseOptions & {
25
25
  path: UserStoragePathWithFeatureOnly;
26
26
  };
27
+ export type UserStorageBatchUpsertOptions = UserStorageAllFeatureEntriesOptions;
27
28
  /**
28
29
  * User Storage Service - Get Storage Entry.
29
30
  *
@@ -45,4 +46,12 @@ export declare function getUserStorageAllFeatureEntries(opts: UserStorageAllFeat
45
46
  * @param opts - storage options
46
47
  */
47
48
  export declare function upsertUserStorage(data: string, opts: UserStorageOptions): Promise<void>;
49
+ /**
50
+ * User Storage Service - Set multiple storage entries for one specific feature.
51
+ * You cannot use this method to set multiple features at once.
52
+ *
53
+ * @param data - data to store, in the form of an array of [entryKey, entryValue] pairs
54
+ * @param opts - storage options
55
+ */
56
+ export declare function batchUpsertUserStorage(data: [UserStoragePathWithKeyOnly, string][], opts: UserStorageBatchUpsertOptions): Promise<void>;
48
57
  //# sourceMappingURL=services.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.mts","sourceRoot":"","sources":["../../../src/controllers/user-storage/services.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gCAAgC,EAChC,8BAA8B,EAC/B,wCAAoC;AAErC,OAAO,KAAK,EAAE,YAAY,EAAE,0CAAsC;AAIlE,eAAO,MAAM,gBAAgB,EAAE,MAAmC,CAAC;AACnE,eAAO,MAAM,qBAAqB,QAA2C,CAAC;AAE9E;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IAEnC,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,uCAAuC,GAAG;IAEpD,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;CACd,EAAE,CAAC;AAEJ,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,YAAY,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,IAAI,EAAE,gCAAgC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG,sBAAsB,GAAG;IACzE,IAAI,EAAE,8BAA8B,CAAC;CACtC,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0CxB;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,mCAAmC,GACxC,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CA+C1B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC,CAuBf"}
1
+ {"version":3,"file":"services.d.mts","sourceRoot":"","sources":["../../../src/controllers/user-storage/services.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gCAAgC,EAChC,8BAA8B,EAC9B,0BAA0B,EAC3B,wCAAoC;AAErC,OAAO,KAAK,EAAE,YAAY,EAAE,0CAAsC;AAIlE,eAAO,MAAM,gBAAgB,EAAE,MAAmC,CAAC;AACnE,eAAO,MAAM,qBAAqB,QAA2C,CAAC;AAE9E;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IAEnC,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,uCAAuC,GAAG;IAEpD,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,MAAM,CAAC;CACd,EAAE,CAAC;AAEJ,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,YAAY,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,IAAI,EAAE,gCAAgC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG,sBAAsB,GAAG;IACzE,IAAI,EAAE,8BAA8B,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,mCAAmC,CAAC;AAEhF;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0CxB;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,mCAAmC,GACxC,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CA+C1B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,CAAC,0BAA0B,EAAE,MAAM,CAAC,EAAE,EAC5C,IAAI,EAAE,6BAA6B,GAClC,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -6,7 +6,7 @@ function $importDefault(module) {
6
6
  }
7
7
  import $log from "loglevel";
8
8
  const log = $importDefault($log);
9
- import encryption from "../../shared/encryption/index.mjs";
9
+ import encryption, { createSHA256Hash } from "../../shared/encryption/index.mjs";
10
10
  import { Env, getEnvUrls } from "../../shared/env.mjs";
11
11
  import { createEntryPath } from "../../shared/storage-schema.mjs";
12
12
  const ENV_URLS = getEnvUrls(Env.PRD);
@@ -114,4 +114,36 @@ export async function upsertUserStorage(data, opts) {
114
114
  throw new Error('user-storage - unable to upsert data');
115
115
  }
116
116
  }
117
+ /**
118
+ * User Storage Service - Set multiple storage entries for one specific feature.
119
+ * You cannot use this method to set multiple features at once.
120
+ *
121
+ * @param data - data to store, in the form of an array of [entryKey, entryValue] pairs
122
+ * @param opts - storage options
123
+ */
124
+ export async function batchUpsertUserStorage(data, opts) {
125
+ if (!data.length) {
126
+ return;
127
+ }
128
+ const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;
129
+ const encryptedData = await Promise.all(data.map(async (d) => {
130
+ return [
131
+ createSHA256Hash(d[0] + storageKey),
132
+ await encryption.encryptString(d[1], opts.storageKey, nativeScryptCrypto),
133
+ ];
134
+ }));
135
+ const url = new URL(`${USER_STORAGE_ENDPOINT}/${path}`);
136
+ const formattedData = Object.fromEntries(encryptedData);
137
+ const res = await fetch(url.toString(), {
138
+ method: 'PUT',
139
+ headers: {
140
+ 'Content-Type': 'application/json',
141
+ Authorization: `Bearer ${bearerToken}`,
142
+ },
143
+ body: JSON.stringify({ data: formattedData }),
144
+ });
145
+ if (!res.ok) {
146
+ throw new Error('user-storage - unable to batch upsert data');
147
+ }
148
+ }
117
149
  //# sourceMappingURL=services.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.mjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/services.ts"],"names":[],"mappings":"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","sourcesContent":["import log from 'loglevel';\n\nimport encryption from '../../shared/encryption';\nimport { Env, getEnvUrls } from '../../shared/env';\nimport type {\n UserStoragePathWithFeatureAndKey,\n UserStoragePathWithFeatureOnly,\n} from '../../shared/storage-schema';\nimport { createEntryPath } from '../../shared/storage-schema';\nimport type { NativeScrypt } from '../../shared/types/encryption';\n\nconst ENV_URLS = getEnvUrls(Env.PRD);\n\nexport const USER_STORAGE_API: string = ENV_URLS.userStorageApiUrl;\nexport const USER_STORAGE_ENDPOINT = `${USER_STORAGE_API}/api/v1/userstorage`;\n\n/**\n * This is the Server Response shape for a feature entry.\n */\nexport type GetUserStorageResponse = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n HashedKey: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Data: string;\n};\n\nexport type GetUserStorageAllFeatureEntriesResponse = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n HashedKey: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Data: string;\n}[];\n\nexport type UserStorageBaseOptions = {\n bearerToken: string;\n storageKey: string;\n nativeScryptCrypto?: NativeScrypt;\n};\n\nexport type UserStorageOptions = UserStorageBaseOptions & {\n path: UserStoragePathWithFeatureAndKey;\n};\n\nexport type UserStorageAllFeatureEntriesOptions = UserStorageBaseOptions & {\n path: UserStoragePathWithFeatureOnly;\n};\n\n/**\n * User Storage Service - Get Storage Entry.\n *\n * @param opts - User Storage Options\n * @returns The storage entry, or null if fails to find entry\n */\nexport async function getUserStorage(\n opts: UserStorageOptions,\n): Promise<string | null> {\n try {\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedPath = createEntryPath(path, storageKey);\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${encryptedPath}`);\n\n const userStorageResponse = await fetch(url.toString(), {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n });\n\n // Acceptable error - since indicates entry does not exist.\n if (userStorageResponse.status === 404) {\n return null;\n }\n\n if (userStorageResponse.status !== 200) {\n throw new Error('Unable to get User Storage');\n }\n\n const userStorage: GetUserStorageResponse | null =\n await userStorageResponse.json();\n const encryptedData = userStorage?.Data ?? null;\n\n if (!encryptedData) {\n return null;\n }\n\n const decryptedData = await encryption.decryptString(\n encryptedData,\n opts.storageKey,\n nativeScryptCrypto,\n );\n\n return decryptedData;\n } catch (e) {\n log.error('Failed to get user storage', e);\n return null;\n }\n}\n\n/**\n * User Storage Service - Get all storage entries for a specific feature.\n *\n * @param opts - User Storage Options\n * @returns The storage entry, or null if fails to find entry\n */\nexport async function getUserStorageAllFeatureEntries(\n opts: UserStorageAllFeatureEntriesOptions,\n): Promise<string[] | null> {\n try {\n const { bearerToken, path, nativeScryptCrypto } = opts;\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${path}`);\n\n const userStorageResponse = await fetch(url.toString(), {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n });\n\n // Acceptable error - since indicates feature does not exist.\n if (userStorageResponse.status === 404) {\n return null;\n }\n\n if (userStorageResponse.status !== 200) {\n throw new Error('Unable to get User Storage');\n }\n\n const userStorage: GetUserStorageAllFeatureEntriesResponse | null =\n await userStorageResponse.json();\n\n if (!Array.isArray(userStorage)) {\n return null;\n }\n\n const decryptedData = userStorage?.flatMap((entry) => {\n if (!entry.Data) {\n return [];\n }\n\n return encryption.decryptString(\n entry.Data,\n opts.storageKey,\n nativeScryptCrypto,\n );\n });\n\n return (await Promise.allSettled(decryptedData))\n .map((d) => (d.status === 'fulfilled' ? d.value : undefined))\n .filter((d): d is string => d !== undefined);\n } catch (e) {\n log.error('Failed to get user storage', e);\n return null;\n }\n}\n\n/**\n * User Storage Service - Set Storage Entry.\n *\n * @param data - data to store\n * @param opts - storage options\n */\nexport async function upsertUserStorage(\n data: string,\n opts: UserStorageOptions,\n): Promise<void> {\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedData = await encryption.encryptString(\n data,\n opts.storageKey,\n nativeScryptCrypto,\n );\n const encryptedPath = createEntryPath(path, storageKey);\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${encryptedPath}`);\n\n const res = await fetch(url.toString(), {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n body: JSON.stringify({ data: encryptedData }),\n });\n\n if (!res.ok) {\n throw new Error('user-storage - unable to upsert data');\n }\n}\n"]}
1
+ {"version":3,"file":"services.mjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/services.ts"],"names":[],"mappings":"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","sourcesContent":["import log from 'loglevel';\n\nimport encryption, { createSHA256Hash } from '../../shared/encryption';\nimport { Env, getEnvUrls } from '../../shared/env';\nimport type {\n UserStoragePathWithFeatureAndKey,\n UserStoragePathWithFeatureOnly,\n UserStoragePathWithKeyOnly,\n} from '../../shared/storage-schema';\nimport { createEntryPath } from '../../shared/storage-schema';\nimport type { NativeScrypt } from '../../shared/types/encryption';\n\nconst ENV_URLS = getEnvUrls(Env.PRD);\n\nexport const USER_STORAGE_API: string = ENV_URLS.userStorageApiUrl;\nexport const USER_STORAGE_ENDPOINT = `${USER_STORAGE_API}/api/v1/userstorage`;\n\n/**\n * This is the Server Response shape for a feature entry.\n */\nexport type GetUserStorageResponse = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n HashedKey: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Data: string;\n};\n\nexport type GetUserStorageAllFeatureEntriesResponse = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n HashedKey: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Data: string;\n}[];\n\nexport type UserStorageBaseOptions = {\n bearerToken: string;\n storageKey: string;\n nativeScryptCrypto?: NativeScrypt;\n};\n\nexport type UserStorageOptions = UserStorageBaseOptions & {\n path: UserStoragePathWithFeatureAndKey;\n};\n\nexport type UserStorageAllFeatureEntriesOptions = UserStorageBaseOptions & {\n path: UserStoragePathWithFeatureOnly;\n};\n\nexport type UserStorageBatchUpsertOptions = UserStorageAllFeatureEntriesOptions;\n\n/**\n * User Storage Service - Get Storage Entry.\n *\n * @param opts - User Storage Options\n * @returns The storage entry, or null if fails to find entry\n */\nexport async function getUserStorage(\n opts: UserStorageOptions,\n): Promise<string | null> {\n try {\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedPath = createEntryPath(path, storageKey);\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${encryptedPath}`);\n\n const userStorageResponse = await fetch(url.toString(), {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n });\n\n // Acceptable error - since indicates entry does not exist.\n if (userStorageResponse.status === 404) {\n return null;\n }\n\n if (userStorageResponse.status !== 200) {\n throw new Error('Unable to get User Storage');\n }\n\n const userStorage: GetUserStorageResponse | null =\n await userStorageResponse.json();\n const encryptedData = userStorage?.Data ?? null;\n\n if (!encryptedData) {\n return null;\n }\n\n const decryptedData = await encryption.decryptString(\n encryptedData,\n opts.storageKey,\n nativeScryptCrypto,\n );\n\n return decryptedData;\n } catch (e) {\n log.error('Failed to get user storage', e);\n return null;\n }\n}\n\n/**\n * User Storage Service - Get all storage entries for a specific feature.\n *\n * @param opts - User Storage Options\n * @returns The storage entry, or null if fails to find entry\n */\nexport async function getUserStorageAllFeatureEntries(\n opts: UserStorageAllFeatureEntriesOptions,\n): Promise<string[] | null> {\n try {\n const { bearerToken, path, nativeScryptCrypto } = opts;\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${path}`);\n\n const userStorageResponse = await fetch(url.toString(), {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n });\n\n // Acceptable error - since indicates feature does not exist.\n if (userStorageResponse.status === 404) {\n return null;\n }\n\n if (userStorageResponse.status !== 200) {\n throw new Error('Unable to get User Storage');\n }\n\n const userStorage: GetUserStorageAllFeatureEntriesResponse | null =\n await userStorageResponse.json();\n\n if (!Array.isArray(userStorage)) {\n return null;\n }\n\n const decryptedData = userStorage?.flatMap((entry) => {\n if (!entry.Data) {\n return [];\n }\n\n return encryption.decryptString(\n entry.Data,\n opts.storageKey,\n nativeScryptCrypto,\n );\n });\n\n return (await Promise.allSettled(decryptedData))\n .map((d) => (d.status === 'fulfilled' ? d.value : undefined))\n .filter((d): d is string => d !== undefined);\n } catch (e) {\n log.error('Failed to get user storage', e);\n return null;\n }\n}\n\n/**\n * User Storage Service - Set Storage Entry.\n *\n * @param data - data to store\n * @param opts - storage options\n */\nexport async function upsertUserStorage(\n data: string,\n opts: UserStorageOptions,\n): Promise<void> {\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedData = await encryption.encryptString(\n data,\n opts.storageKey,\n nativeScryptCrypto,\n );\n const encryptedPath = createEntryPath(path, storageKey);\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${encryptedPath}`);\n\n const res = await fetch(url.toString(), {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n body: JSON.stringify({ data: encryptedData }),\n });\n\n if (!res.ok) {\n throw new Error('user-storage - unable to upsert data');\n }\n}\n\n/**\n * User Storage Service - Set multiple storage entries for one specific feature.\n * You cannot use this method to set multiple features at once.\n *\n * @param data - data to store, in the form of an array of [entryKey, entryValue] pairs\n * @param opts - storage options\n */\nexport async function batchUpsertUserStorage(\n data: [UserStoragePathWithKeyOnly, string][],\n opts: UserStorageBatchUpsertOptions,\n): Promise<void> {\n if (!data.length) {\n return;\n }\n\n const { bearerToken, path, storageKey, nativeScryptCrypto } = opts;\n\n const encryptedData = await Promise.all(\n data.map(async (d) => {\n return [\n createSHA256Hash(d[0] + storageKey),\n await encryption.encryptString(\n d[1],\n opts.storageKey,\n nativeScryptCrypto,\n ),\n ];\n }),\n );\n\n const url = new URL(`${USER_STORAGE_ENDPOINT}/${path}`);\n\n const formattedData = Object.fromEntries(encryptedData);\n\n const res = await fetch(url.toString(), {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n body: JSON.stringify({ data: formattedData }),\n });\n\n if (!res.ok) {\n throw new Error('user-storage - unable to batch upsert data');\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setIntersection = exports.setDifference = void 0;
3
+ exports.waitForExpectedValue = exports.setIntersection = exports.setDifference = void 0;
4
4
  /**
5
5
  * Returns the difference between 2 sets.
6
6
  * NOTE - this is temporary until we can support Set().difference method
@@ -27,4 +27,30 @@ function setIntersection(a, b) {
27
27
  return intersection;
28
28
  }
29
29
  exports.setIntersection = setIntersection;
30
+ /**
31
+ *
32
+ * Waits for a value to be returned from a getter function.
33
+ *
34
+ * @param getter - Function that returns the value to check
35
+ * @param expectedValue - The value to wait for
36
+ * @param timeout - The time to wait before timing out
37
+ * @returns A promise that resolves when the expected value is returned
38
+ * or rejects if the timeout is reached.
39
+ */
40
+ function waitForExpectedValue(getter, expectedValue, timeout = 1000) {
41
+ return new Promise((resolve, reject) => {
42
+ const interval = setInterval(() => {
43
+ const value = getter();
44
+ if (value === expectedValue) {
45
+ clearInterval(interval);
46
+ resolve(value);
47
+ }
48
+ }, 100);
49
+ setTimeout(() => {
50
+ clearInterval(interval);
51
+ reject(new Error('Timed out waiting for expected value'));
52
+ }, timeout);
53
+ });
54
+ }
55
+ exports.waitForExpectedValue = waitForExpectedValue;
30
56
  //# sourceMappingURL=utils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/utils.ts"],"names":[],"mappings":";;;AAAA;;;;;;GAMG;AACH,SAAgB,aAAa,CAAQ,CAAa,EAAE,CAAa;IAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAS,CAAC;IACpC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,UAAU,CAAC;AACpB,CAAC;AAJD,sCAIC;AAED;;;;;;GAMG;AACH,SAAgB,eAAe,CAC7B,CAAa,EACb,CAAa;IAEb,MAAM,YAAY,GAAG,IAAI,GAAG,EAAS,CAAC;IACtC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,OAAO,YAAY,CAAC;AACtB,CAAC;AAPD,0CAOC","sourcesContent":["/**\n * Returns the difference between 2 sets.\n * NOTE - this is temporary until we can support Set().difference method\n * @param a - First Set\n * @param b - Second Set\n * @returns The difference between the first and second set.\n */\nexport function setDifference<TItem>(a: Set<TItem>, b: Set<TItem>): Set<TItem> {\n const difference = new Set<TItem>();\n a.forEach((e) => !b.has(e) && difference.add(e));\n return difference;\n}\n\n/**\n * Returns the intersection between 2 sets.\n * NOTE - this is temporary until we can support Set().intersection method\n * @param a - First Set\n * @param b - Second Set\n * @returns The intersection between the first and second set.\n */\nexport function setIntersection<TItem>(\n a: Set<TItem>,\n b: Set<TItem>,\n): Set<TItem> {\n const intersection = new Set<TItem>();\n a.forEach((e) => b.has(e) && intersection.add(e));\n return intersection;\n}\n"]}
1
+ {"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/utils.ts"],"names":[],"mappings":";;;AAAA;;;;;;GAMG;AACH,SAAgB,aAAa,CAAQ,CAAa,EAAE,CAAa;IAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAS,CAAC;IACpC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,UAAU,CAAC;AACpB,CAAC;AAJD,sCAIC;AAED;;;;;;GAMG;AACH,SAAgB,eAAe,CAC7B,CAAa,EACb,CAAa;IAEb,MAAM,YAAY,GAAG,IAAI,GAAG,EAAS,CAAC;IACtC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,OAAO,YAAY,CAAC;AACtB,CAAC;AAPD,0CAOC;AAED;;;;;;;;;GASG;AACH,SAAgB,oBAAoB,CAClC,MAAuB,EACvB,aAAwB,EACxB,OAAO,GAAG,IAAI;IAEd,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;YAChC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;YACvB,IAAI,KAAK,KAAK,aAAa,EAAE;gBAC3B,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACxB,OAAO,CAAC,KAAK,CAAC,CAAC;aAChB;QACH,CAAC,EAAE,GAAG,CAAC,CAAC;QAER,UAAU,CAAC,GAAG,EAAE;YACd,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,MAAM,CAAC,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAC5D,CAAC,EAAE,OAAO,CAAC,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAnBD,oDAmBC","sourcesContent":["/**\n * Returns the difference between 2 sets.\n * NOTE - this is temporary until we can support Set().difference method\n * @param a - First Set\n * @param b - Second Set\n * @returns The difference between the first and second set.\n */\nexport function setDifference<TItem>(a: Set<TItem>, b: Set<TItem>): Set<TItem> {\n const difference = new Set<TItem>();\n a.forEach((e) => !b.has(e) && difference.add(e));\n return difference;\n}\n\n/**\n * Returns the intersection between 2 sets.\n * NOTE - this is temporary until we can support Set().intersection method\n * @param a - First Set\n * @param b - Second Set\n * @returns The intersection between the first and second set.\n */\nexport function setIntersection<TItem>(\n a: Set<TItem>,\n b: Set<TItem>,\n): Set<TItem> {\n const intersection = new Set<TItem>();\n a.forEach((e) => b.has(e) && intersection.add(e));\n return intersection;\n}\n\n/**\n *\n * Waits for a value to be returned from a getter function.\n *\n * @param getter - Function that returns the value to check\n * @param expectedValue - The value to wait for\n * @param timeout - The time to wait before timing out\n * @returns A promise that resolves when the expected value is returned\n * or rejects if the timeout is reached.\n */\nexport function waitForExpectedValue<TVariable>(\n getter: () => TVariable,\n expectedValue: TVariable,\n timeout = 1000,\n): Promise<TVariable> {\n return new Promise((resolve, reject) => {\n const interval = setInterval(() => {\n const value = getter();\n if (value === expectedValue) {\n clearInterval(interval);\n resolve(value);\n }\n }, 100);\n\n setTimeout(() => {\n clearInterval(interval);\n reject(new Error('Timed out waiting for expected value'));\n }, timeout);\n });\n}\n"]}
@@ -14,4 +14,15 @@ export declare function setDifference<TItem>(a: Set<TItem>, b: Set<TItem>): Set<
14
14
  * @returns The intersection between the first and second set.
15
15
  */
16
16
  export declare function setIntersection<TItem>(a: Set<TItem>, b: Set<TItem>): Set<TItem>;
17
+ /**
18
+ *
19
+ * Waits for a value to be returned from a getter function.
20
+ *
21
+ * @param getter - Function that returns the value to check
22
+ * @param expectedValue - The value to wait for
23
+ * @param timeout - The time to wait before timing out
24
+ * @returns A promise that resolves when the expected value is returned
25
+ * or rejects if the timeout is reached.
26
+ */
27
+ export declare function waitForExpectedValue<TVariable>(getter: () => TVariable, expectedValue: TVariable, timeout?: number): Promise<TVariable>;
17
28
  //# sourceMappingURL=utils.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../../src/controllers/user-storage/utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAI7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EACnC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EACb,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GACZ,GAAG,CAAC,KAAK,CAAC,CAIZ"}
1
+ {"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../../src/controllers/user-storage/utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAI7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EACnC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EACb,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GACZ,GAAG,CAAC,KAAK,CAAC,CAIZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAC5C,MAAM,EAAE,MAAM,SAAS,EACvB,aAAa,EAAE,SAAS,EACxB,OAAO,SAAO,GACb,OAAO,CAAC,SAAS,CAAC,CAepB"}
@@ -14,4 +14,15 @@ export declare function setDifference<TItem>(a: Set<TItem>, b: Set<TItem>): Set<
14
14
  * @returns The intersection between the first and second set.
15
15
  */
16
16
  export declare function setIntersection<TItem>(a: Set<TItem>, b: Set<TItem>): Set<TItem>;
17
+ /**
18
+ *
19
+ * Waits for a value to be returned from a getter function.
20
+ *
21
+ * @param getter - Function that returns the value to check
22
+ * @param expectedValue - The value to wait for
23
+ * @param timeout - The time to wait before timing out
24
+ * @returns A promise that resolves when the expected value is returned
25
+ * or rejects if the timeout is reached.
26
+ */
27
+ export declare function waitForExpectedValue<TVariable>(getter: () => TVariable, expectedValue: TVariable, timeout?: number): Promise<TVariable>;
17
28
  //# sourceMappingURL=utils.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../../src/controllers/user-storage/utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAI7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EACnC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EACb,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GACZ,GAAG,CAAC,KAAK,CAAC,CAIZ"}
1
+ {"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../../src/controllers/user-storage/utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAI7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EACnC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,EACb,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,GACZ,GAAG,CAAC,KAAK,CAAC,CAIZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAC5C,MAAM,EAAE,MAAM,SAAS,EACvB,aAAa,EAAE,SAAS,EACxB,OAAO,SAAO,GACb,OAAO,CAAC,SAAS,CAAC,CAepB"}
@@ -22,4 +22,29 @@ export function setIntersection(a, b) {
22
22
  a.forEach((e) => b.has(e) && intersection.add(e));
23
23
  return intersection;
24
24
  }
25
+ /**
26
+ *
27
+ * Waits for a value to be returned from a getter function.
28
+ *
29
+ * @param getter - Function that returns the value to check
30
+ * @param expectedValue - The value to wait for
31
+ * @param timeout - The time to wait before timing out
32
+ * @returns A promise that resolves when the expected value is returned
33
+ * or rejects if the timeout is reached.
34
+ */
35
+ export function waitForExpectedValue(getter, expectedValue, timeout = 1000) {
36
+ return new Promise((resolve, reject) => {
37
+ const interval = setInterval(() => {
38
+ const value = getter();
39
+ if (value === expectedValue) {
40
+ clearInterval(interval);
41
+ resolve(value);
42
+ }
43
+ }, 100);
44
+ setTimeout(() => {
45
+ clearInterval(interval);
46
+ reject(new Error('Timed out waiting for expected value'));
47
+ }, timeout);
48
+ });
49
+ }
25
50
  //# sourceMappingURL=utils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAQ,CAAa,EAAE,CAAa;IAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAS,CAAC;IACpC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,CAAa,EACb,CAAa;IAEb,MAAM,YAAY,GAAG,IAAI,GAAG,EAAS,CAAC;IACtC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["/**\n * Returns the difference between 2 sets.\n * NOTE - this is temporary until we can support Set().difference method\n * @param a - First Set\n * @param b - Second Set\n * @returns The difference between the first and second set.\n */\nexport function setDifference<TItem>(a: Set<TItem>, b: Set<TItem>): Set<TItem> {\n const difference = new Set<TItem>();\n a.forEach((e) => !b.has(e) && difference.add(e));\n return difference;\n}\n\n/**\n * Returns the intersection between 2 sets.\n * NOTE - this is temporary until we can support Set().intersection method\n * @param a - First Set\n * @param b - Second Set\n * @returns The intersection between the first and second set.\n */\nexport function setIntersection<TItem>(\n a: Set<TItem>,\n b: Set<TItem>,\n): Set<TItem> {\n const intersection = new Set<TItem>();\n a.forEach((e) => b.has(e) && intersection.add(e));\n return intersection;\n}\n"]}
1
+ {"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAQ,CAAa,EAAE,CAAa;IAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAS,CAAC;IACpC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,CAAa,EACb,CAAa;IAEb,MAAM,YAAY,GAAG,IAAI,GAAG,EAAS,CAAC;IACtC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAuB,EACvB,aAAwB,EACxB,OAAO,GAAG,IAAI;IAEd,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;YAChC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;YACvB,IAAI,KAAK,KAAK,aAAa,EAAE;gBAC3B,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACxB,OAAO,CAAC,KAAK,CAAC,CAAC;aAChB;QACH,CAAC,EAAE,GAAG,CAAC,CAAC;QAER,UAAU,CAAC,GAAG,EAAE;YACd,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,MAAM,CAAC,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAC5D,CAAC,EAAE,OAAO,CAAC,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Returns the difference between 2 sets.\n * NOTE - this is temporary until we can support Set().difference method\n * @param a - First Set\n * @param b - Second Set\n * @returns The difference between the first and second set.\n */\nexport function setDifference<TItem>(a: Set<TItem>, b: Set<TItem>): Set<TItem> {\n const difference = new Set<TItem>();\n a.forEach((e) => !b.has(e) && difference.add(e));\n return difference;\n}\n\n/**\n * Returns the intersection between 2 sets.\n * NOTE - this is temporary until we can support Set().intersection method\n * @param a - First Set\n * @param b - Second Set\n * @returns The intersection between the first and second set.\n */\nexport function setIntersection<TItem>(\n a: Set<TItem>,\n b: Set<TItem>,\n): Set<TItem> {\n const intersection = new Set<TItem>();\n a.forEach((e) => b.has(e) && intersection.add(e));\n return intersection;\n}\n\n/**\n *\n * Waits for a value to be returned from a getter function.\n *\n * @param getter - Function that returns the value to check\n * @param expectedValue - The value to wait for\n * @param timeout - The time to wait before timing out\n * @returns A promise that resolves when the expected value is returned\n * or rejects if the timeout is reached.\n */\nexport function waitForExpectedValue<TVariable>(\n getter: () => TVariable,\n expectedValue: TVariable,\n timeout = 1000,\n): Promise<TVariable> {\n return new Promise((resolve, reject) => {\n const interval = setInterval(() => {\n const value = getter();\n if (value === expectedValue) {\n clearInterval(interval);\n resolve(value);\n }\n }, 100);\n\n setTimeout(() => {\n clearInterval(interval);\n reject(new Error('Timed out waiting for expected value'));\n }, timeout);\n });\n}\n"]}
@@ -46,12 +46,14 @@ const handleMockUserStorageGetAllFeatureEntries = async (mockReply) => {
46
46
  return mockEndpoint;
47
47
  };
48
48
  exports.handleMockUserStorageGetAllFeatureEntries = handleMockUserStorageGetAllFeatureEntries;
49
- const handleMockUserStoragePut = (mockReply) => {
49
+ const handleMockUserStoragePut = (mockReply, callback) => {
50
50
  const reply = mockReply ?? { status: 204 };
51
51
  const mockEndpoint = (0, nock_1.default)(MOCK_STORAGE_URL)
52
52
  .persist()
53
53
  .put(/.*/u)
54
- .reply(reply.status);
54
+ .reply(reply.status, async (uri, requestBody) => {
55
+ return await callback?.(uri, requestBody);
56
+ });
55
57
  return mockEndpoint;
56
58
  };
57
59
  exports.handleMockUserStoragePut = handleMockUserStoragePut;
@@ -1 +1 @@
1
- {"version":3,"file":"mock-userstorage.cjs","sourceRoot":"","sources":["../../../src/sdk/__fixtures__/mock-userstorage.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AAExB,mFAAiD;AACjD,8CAAuC;AACvC,sDAA8C;AAO9C,sDAAsD;AACtD,MAAM,gBAAgB,GAAG,IAAA,0BAAW,EAClC,SAAG,CAAC,GAAG,EACP,qCAAqC,CACtC,CAAC;AACF,MAAM,oCAAoC,GAAG,IAAA,0BAAW,EACtD,SAAG,CAAC,GAAG,EACP,eAAe,CAChB,CAAC;AAEW,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AACnD,gFAAgF;AAChF,gEAAgE;AACnD,QAAA,uBAAuB,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AACtD,MAAM,iCAAiC,GAAG,KAAK,IAAI,EAAE,CAC1D,MAAM,oBAAU,CAAC,aAAa,CAC5B,IAAI,CAAC,SAAS,CAAC,+BAAuB,CAAC,EACvC,wBAAgB,CACjB,CAAC;AAJS,QAAA,iCAAiC,qCAI1C;AAEG,MAAM,qBAAqB,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;IAChD,SAAS,EAAE,kEAAkE;IAC7E,IAAI,EAAE,MAAM,IAAA,yCAAiC,GAAE;CAChD,CAAC,CAAC;AAHU,QAAA,qBAAqB,yBAG/B;AAEI,MAAM,wBAAwB,GAAG,KAAK,EAAE,SAAqB,EAAE,EAAE;IACtE,MAAM,KAAK,GAAG,SAAS,IAAI;QACzB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,MAAM,IAAA,6BAAqB,GAAE;KACpC,CAAC;IACF,MAAM,YAAY,GAAG,IAAA,cAAI,EAAC,gBAAgB,CAAC;SACxC,OAAO,EAAE;SACT,GAAG,CAAC,KAAK,CAAC;SACV,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAXW,QAAA,wBAAwB,4BAWnC;AAEK,MAAM,yCAAyC,GAAG,KAAK,EAC5D,SAAqB,EACrB,EAAE;IACF,MAAM,KAAK,GAAG,SAAS,IAAI;QACzB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,CAAC,MAAM,IAAA,6BAAqB,GAAE,CAAC;KACtC,CAAC;IACF,MAAM,YAAY,GAAG,IAAA,cAAI,EAAC,oCAAoC,CAAC;SAC5D,OAAO,EAAE;SACT,GAAG,CAAC,EAAE,CAAC;SACP,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAbW,QAAA,yCAAyC,6CAapD;AAEK,MAAM,wBAAwB,GAAG,CAAC,SAAqB,EAAE,EAAE;IAChE,MAAM,KAAK,GAAG,SAAS,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAA,cAAI,EAAC,gBAAgB,CAAC;SACxC,OAAO,EAAE;SACT,GAAG,CAAC,KAAK,CAAC;SACV,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AARW,QAAA,wBAAwB,4BAQnC","sourcesContent":["import nock from 'nock';\n\nimport encryption from '../../shared/encryption';\nimport { Env } from '../../shared/env';\nimport { STORAGE_URL } from '../user-storage';\n\ntype MockReply = {\n status: nock.StatusCode;\n body?: nock.Body;\n};\n\n// Example mock notifications storage entry (wildcard)\nconst MOCK_STORAGE_URL = STORAGE_URL(\n Env.DEV,\n 'notifications/notification_settings',\n);\nconst MOCK_STORAGE_URL_ALL_FEATURE_ENTRIES = STORAGE_URL(\n Env.DEV,\n 'notifications',\n);\n\nexport const MOCK_STORAGE_KEY = 'MOCK_STORAGE_KEY';\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const MOCK_NOTIFICATIONS_DATA = { is_compact: false };\nexport const MOCK_NOTIFICATIONS_DATA_ENCRYPTED = async () =>\n await encryption.encryptString(\n JSON.stringify(MOCK_NOTIFICATIONS_DATA),\n MOCK_STORAGE_KEY,\n );\n\nexport const MOCK_STORAGE_RESPONSE = async () => ({\n HashedKey: '8485d2c14c333ebca415140a276adaf546619b0efc204586b73a5d400a18a5e2',\n Data: await MOCK_NOTIFICATIONS_DATA_ENCRYPTED(),\n});\n\nexport const handleMockUserStorageGet = async (mockReply?: MockReply) => {\n const reply = mockReply ?? {\n status: 200,\n body: await MOCK_STORAGE_RESPONSE(),\n };\n const mockEndpoint = nock(MOCK_STORAGE_URL)\n .persist()\n .get(/.*/u)\n .reply(reply.status, reply.body);\n\n return mockEndpoint;\n};\n\nexport const handleMockUserStorageGetAllFeatureEntries = async (\n mockReply?: MockReply,\n) => {\n const reply = mockReply ?? {\n status: 200,\n body: [await MOCK_STORAGE_RESPONSE()],\n };\n const mockEndpoint = nock(MOCK_STORAGE_URL_ALL_FEATURE_ENTRIES)\n .persist()\n .get('')\n .reply(reply.status, reply.body);\n\n return mockEndpoint;\n};\n\nexport const handleMockUserStoragePut = (mockReply?: MockReply) => {\n const reply = mockReply ?? { status: 204 };\n const mockEndpoint = nock(MOCK_STORAGE_URL)\n .persist()\n .put(/.*/u)\n .reply(reply.status);\n\n return mockEndpoint;\n};\n"]}
1
+ {"version":3,"file":"mock-userstorage.cjs","sourceRoot":"","sources":["../../../src/sdk/__fixtures__/mock-userstorage.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AAExB,mFAAiD;AACjD,8CAAuC;AACvC,sDAA8C;AAO9C,sDAAsD;AACtD,MAAM,gBAAgB,GAAG,IAAA,0BAAW,EAClC,SAAG,CAAC,GAAG,EACP,qCAAqC,CACtC,CAAC;AACF,MAAM,oCAAoC,GAAG,IAAA,0BAAW,EACtD,SAAG,CAAC,GAAG,EACP,eAAe,CAChB,CAAC;AAEW,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AACnD,gFAAgF;AAChF,gEAAgE;AACnD,QAAA,uBAAuB,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AACtD,MAAM,iCAAiC,GAAG,KAAK,IAAI,EAAE,CAC1D,MAAM,oBAAU,CAAC,aAAa,CAC5B,IAAI,CAAC,SAAS,CAAC,+BAAuB,CAAC,EACvC,wBAAgB,CACjB,CAAC;AAJS,QAAA,iCAAiC,qCAI1C;AAEG,MAAM,qBAAqB,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;IAChD,SAAS,EAAE,kEAAkE;IAC7E,IAAI,EAAE,MAAM,IAAA,yCAAiC,GAAE;CAChD,CAAC,CAAC;AAHU,QAAA,qBAAqB,yBAG/B;AAEI,MAAM,wBAAwB,GAAG,KAAK,EAAE,SAAqB,EAAE,EAAE;IACtE,MAAM,KAAK,GAAG,SAAS,IAAI;QACzB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,MAAM,IAAA,6BAAqB,GAAE;KACpC,CAAC;IACF,MAAM,YAAY,GAAG,IAAA,cAAI,EAAC,gBAAgB,CAAC;SACxC,OAAO,EAAE;SACT,GAAG,CAAC,KAAK,CAAC;SACV,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAXW,QAAA,wBAAwB,4BAWnC;AAEK,MAAM,yCAAyC,GAAG,KAAK,EAC5D,SAAqB,EACrB,EAAE;IACF,MAAM,KAAK,GAAG,SAAS,IAAI;QACzB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,CAAC,MAAM,IAAA,6BAAqB,GAAE,CAAC;KACtC,CAAC;IACF,MAAM,YAAY,GAAG,IAAA,cAAI,EAAC,oCAAoC,CAAC;SAC5D,OAAO,EAAE;SACT,GAAG,CAAC,EAAE,CAAC;SACP,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAbW,QAAA,yCAAyC,6CAapD;AAEK,MAAM,wBAAwB,GAAG,CACtC,SAAqB,EACrB,QAAiE,EACjE,EAAE;IACF,MAAM,KAAK,GAAG,SAAS,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAA,cAAI,EAAC,gBAAgB,CAAC;SACxC,OAAO,EAAE;SACT,GAAG,CAAC,KAAK,CAAC;SACV,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE;QAC9C,OAAO,MAAM,QAAQ,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEL,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAbW,QAAA,wBAAwB,4BAanC","sourcesContent":["import nock from 'nock';\n\nimport encryption from '../../shared/encryption';\nimport { Env } from '../../shared/env';\nimport { STORAGE_URL } from '../user-storage';\n\ntype MockReply = {\n status: nock.StatusCode;\n body?: nock.Body;\n};\n\n// Example mock notifications storage entry (wildcard)\nconst MOCK_STORAGE_URL = STORAGE_URL(\n Env.DEV,\n 'notifications/notification_settings',\n);\nconst MOCK_STORAGE_URL_ALL_FEATURE_ENTRIES = STORAGE_URL(\n Env.DEV,\n 'notifications',\n);\n\nexport const MOCK_STORAGE_KEY = 'MOCK_STORAGE_KEY';\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const MOCK_NOTIFICATIONS_DATA = { is_compact: false };\nexport const MOCK_NOTIFICATIONS_DATA_ENCRYPTED = async () =>\n await encryption.encryptString(\n JSON.stringify(MOCK_NOTIFICATIONS_DATA),\n MOCK_STORAGE_KEY,\n );\n\nexport const MOCK_STORAGE_RESPONSE = async () => ({\n HashedKey: '8485d2c14c333ebca415140a276adaf546619b0efc204586b73a5d400a18a5e2',\n Data: await MOCK_NOTIFICATIONS_DATA_ENCRYPTED(),\n});\n\nexport const handleMockUserStorageGet = async (mockReply?: MockReply) => {\n const reply = mockReply ?? {\n status: 200,\n body: await MOCK_STORAGE_RESPONSE(),\n };\n const mockEndpoint = nock(MOCK_STORAGE_URL)\n .persist()\n .get(/.*/u)\n .reply(reply.status, reply.body);\n\n return mockEndpoint;\n};\n\nexport const handleMockUserStorageGetAllFeatureEntries = async (\n mockReply?: MockReply,\n) => {\n const reply = mockReply ?? {\n status: 200,\n body: [await MOCK_STORAGE_RESPONSE()],\n };\n const mockEndpoint = nock(MOCK_STORAGE_URL_ALL_FEATURE_ENTRIES)\n .persist()\n .get('')\n .reply(reply.status, reply.body);\n\n return mockEndpoint;\n};\n\nexport const handleMockUserStoragePut = (\n mockReply?: MockReply,\n callback?: (uri: string, requestBody: nock.Body) => Promise<void>,\n) => {\n const reply = mockReply ?? { status: 204 };\n const mockEndpoint = nock(MOCK_STORAGE_URL)\n .persist()\n .put(/.*/u)\n .reply(reply.status, async (uri, requestBody) => {\n return await callback?.(uri, requestBody);\n });\n\n return mockEndpoint;\n};\n"]}
@@ -14,6 +14,6 @@ export declare const MOCK_STORAGE_RESPONSE: () => Promise<{
14
14
  }>;
15
15
  export declare const handleMockUserStorageGet: (mockReply?: MockReply) => Promise<nock.Scope>;
16
16
  export declare const handleMockUserStorageGetAllFeatureEntries: (mockReply?: MockReply) => Promise<nock.Scope>;
17
- export declare const handleMockUserStoragePut: (mockReply?: MockReply) => nock.Scope;
17
+ export declare const handleMockUserStoragePut: (mockReply?: MockReply, callback?: ((uri: string, requestBody: nock.Body) => Promise<void>) | undefined) => nock.Scope;
18
18
  export {};
19
19
  //# sourceMappingURL=mock-userstorage.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mock-userstorage.d.cts","sourceRoot":"","sources":["../../../src/sdk/__fixtures__/mock-userstorage.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,aAAa;AAMxB,KAAK,SAAS,GAAG;IACf,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;CAClB,CAAC;AAYF,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB;;CAAwB,CAAC;AAC7D,eAAO,MAAM,iCAAiC,uBAI3C,CAAC;AAEJ,eAAO,MAAM,qBAAqB;;;EAGhC,CAAC;AAEH,eAAO,MAAM,wBAAwB,eAAsB,SAAS,wBAWnE,CAAC;AAEF,eAAO,MAAM,yCAAyC,eACxC,SAAS,wBAYtB,CAAC;AAEF,eAAO,MAAM,wBAAwB,eAAgB,SAAS,eAQ7D,CAAC"}
1
+ {"version":3,"file":"mock-userstorage.d.cts","sourceRoot":"","sources":["../../../src/sdk/__fixtures__/mock-userstorage.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,aAAa;AAMxB,KAAK,SAAS,GAAG;IACf,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;CAClB,CAAC;AAYF,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB;;CAAwB,CAAC;AAC7D,eAAO,MAAM,iCAAiC,uBAI3C,CAAC;AAEJ,eAAO,MAAM,qBAAqB;;;EAGhC,CAAC;AAEH,eAAO,MAAM,wBAAwB,eAAsB,SAAS,wBAWnE,CAAC;AAEF,eAAO,MAAM,yCAAyC,eACxC,SAAS,wBAYtB,CAAC;AAEF,eAAO,MAAM,wBAAwB,eACvB,SAAS,oBACJ,MAAM,eAAe,SAAS,KAAK,QAAQ,IAAI,CAAC,4BAWlE,CAAC"}
@@ -14,6 +14,6 @@ export declare const MOCK_STORAGE_RESPONSE: () => Promise<{
14
14
  }>;
15
15
  export declare const handleMockUserStorageGet: (mockReply?: MockReply) => Promise<nock.Scope>;
16
16
  export declare const handleMockUserStorageGetAllFeatureEntries: (mockReply?: MockReply) => Promise<nock.Scope>;
17
- export declare const handleMockUserStoragePut: (mockReply?: MockReply) => nock.Scope;
17
+ export declare const handleMockUserStoragePut: (mockReply?: MockReply, callback?: ((uri: string, requestBody: nock.Body) => Promise<void>) | undefined) => nock.Scope;
18
18
  export {};
19
19
  //# sourceMappingURL=mock-userstorage.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mock-userstorage.d.mts","sourceRoot":"","sources":["../../../src/sdk/__fixtures__/mock-userstorage.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,aAAa;AAMxB,KAAK,SAAS,GAAG;IACf,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;CAClB,CAAC;AAYF,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB;;CAAwB,CAAC;AAC7D,eAAO,MAAM,iCAAiC,uBAI3C,CAAC;AAEJ,eAAO,MAAM,qBAAqB;;;EAGhC,CAAC;AAEH,eAAO,MAAM,wBAAwB,eAAsB,SAAS,wBAWnE,CAAC;AAEF,eAAO,MAAM,yCAAyC,eACxC,SAAS,wBAYtB,CAAC;AAEF,eAAO,MAAM,wBAAwB,eAAgB,SAAS,eAQ7D,CAAC"}
1
+ {"version":3,"file":"mock-userstorage.d.mts","sourceRoot":"","sources":["../../../src/sdk/__fixtures__/mock-userstorage.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,aAAa;AAMxB,KAAK,SAAS,GAAG;IACf,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;CAClB,CAAC;AAYF,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB;;CAAwB,CAAC;AAC7D,eAAO,MAAM,iCAAiC,uBAI3C,CAAC;AAEJ,eAAO,MAAM,qBAAqB;;;EAGhC,CAAC;AAEH,eAAO,MAAM,wBAAwB,eAAsB,SAAS,wBAWnE,CAAC;AAEF,eAAO,MAAM,yCAAyC,eACxC,SAAS,wBAYtB,CAAC;AAEF,eAAO,MAAM,wBAAwB,eACvB,SAAS,oBACJ,MAAM,eAAe,SAAS,KAAK,QAAQ,IAAI,CAAC,4BAWlE,CAAC"}
@@ -43,12 +43,14 @@ export const handleMockUserStorageGetAllFeatureEntries = async (mockReply) => {
43
43
  .reply(reply.status, reply.body);
44
44
  return mockEndpoint;
45
45
  };
46
- export const handleMockUserStoragePut = (mockReply) => {
46
+ export const handleMockUserStoragePut = (mockReply, callback) => {
47
47
  const reply = mockReply ?? { status: 204 };
48
48
  const mockEndpoint = nock(MOCK_STORAGE_URL)
49
49
  .persist()
50
50
  .put(/.*/u)
51
- .reply(reply.status);
51
+ .reply(reply.status, async (uri, requestBody) => {
52
+ return await callback?.(uri, requestBody);
53
+ });
52
54
  return mockEndpoint;
53
55
  };
54
56
  //# sourceMappingURL=mock-userstorage.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mock-userstorage.mjs","sourceRoot":"","sources":["../../../src/sdk/__fixtures__/mock-userstorage.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,KAAI,aAAa;;AAExB,OAAO,UAAU,0CAAgC;AACjD,OAAO,EAAE,GAAG,EAAE,6BAAyB;AACvC,OAAO,EAAE,WAAW,EAAE,4BAAwB;AAO9C,sDAAsD;AACtD,MAAM,gBAAgB,GAAG,WAAW,CAClC,GAAG,CAAC,GAAG,EACP,qCAAqC,CACtC,CAAC;AACF,MAAM,oCAAoC,GAAG,WAAW,CACtD,GAAG,CAAC,GAAG,EACP,eAAe,CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AACnD,gFAAgF;AAChF,gEAAgE;AAChE,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC7D,MAAM,CAAC,MAAM,iCAAiC,GAAG,KAAK,IAAI,EAAE,CAC1D,MAAM,UAAU,CAAC,aAAa,CAC5B,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,EACvC,gBAAgB,CACjB,CAAC;AAEJ,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;IAChD,SAAS,EAAE,kEAAkE;IAC7E,IAAI,EAAE,MAAM,iCAAiC,EAAE;CAChD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,EAAE,SAAqB,EAAE,EAAE;IACtE,MAAM,KAAK,GAAG,SAAS,IAAI;QACzB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,MAAM,qBAAqB,EAAE;KACpC,CAAC;IACF,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC;SACxC,OAAO,EAAE;SACT,GAAG,CAAC,KAAK,CAAC;SACV,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yCAAyC,GAAG,KAAK,EAC5D,SAAqB,EACrB,EAAE;IACF,MAAM,KAAK,GAAG,SAAS,IAAI;QACzB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,CAAC,MAAM,qBAAqB,EAAE,CAAC;KACtC,CAAC;IACF,MAAM,YAAY,GAAG,IAAI,CAAC,oCAAoC,CAAC;SAC5D,OAAO,EAAE;SACT,GAAG,CAAC,EAAE,CAAC;SACP,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,SAAqB,EAAE,EAAE;IAChE,MAAM,KAAK,GAAG,SAAS,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC;SACxC,OAAO,EAAE;SACT,GAAG,CAAC,KAAK,CAAC;SACV,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC","sourcesContent":["import nock from 'nock';\n\nimport encryption from '../../shared/encryption';\nimport { Env } from '../../shared/env';\nimport { STORAGE_URL } from '../user-storage';\n\ntype MockReply = {\n status: nock.StatusCode;\n body?: nock.Body;\n};\n\n// Example mock notifications storage entry (wildcard)\nconst MOCK_STORAGE_URL = STORAGE_URL(\n Env.DEV,\n 'notifications/notification_settings',\n);\nconst MOCK_STORAGE_URL_ALL_FEATURE_ENTRIES = STORAGE_URL(\n Env.DEV,\n 'notifications',\n);\n\nexport const MOCK_STORAGE_KEY = 'MOCK_STORAGE_KEY';\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const MOCK_NOTIFICATIONS_DATA = { is_compact: false };\nexport const MOCK_NOTIFICATIONS_DATA_ENCRYPTED = async () =>\n await encryption.encryptString(\n JSON.stringify(MOCK_NOTIFICATIONS_DATA),\n MOCK_STORAGE_KEY,\n );\n\nexport const MOCK_STORAGE_RESPONSE = async () => ({\n HashedKey: '8485d2c14c333ebca415140a276adaf546619b0efc204586b73a5d400a18a5e2',\n Data: await MOCK_NOTIFICATIONS_DATA_ENCRYPTED(),\n});\n\nexport const handleMockUserStorageGet = async (mockReply?: MockReply) => {\n const reply = mockReply ?? {\n status: 200,\n body: await MOCK_STORAGE_RESPONSE(),\n };\n const mockEndpoint = nock(MOCK_STORAGE_URL)\n .persist()\n .get(/.*/u)\n .reply(reply.status, reply.body);\n\n return mockEndpoint;\n};\n\nexport const handleMockUserStorageGetAllFeatureEntries = async (\n mockReply?: MockReply,\n) => {\n const reply = mockReply ?? {\n status: 200,\n body: [await MOCK_STORAGE_RESPONSE()],\n };\n const mockEndpoint = nock(MOCK_STORAGE_URL_ALL_FEATURE_ENTRIES)\n .persist()\n .get('')\n .reply(reply.status, reply.body);\n\n return mockEndpoint;\n};\n\nexport const handleMockUserStoragePut = (mockReply?: MockReply) => {\n const reply = mockReply ?? { status: 204 };\n const mockEndpoint = nock(MOCK_STORAGE_URL)\n .persist()\n .put(/.*/u)\n .reply(reply.status);\n\n return mockEndpoint;\n};\n"]}
1
+ {"version":3,"file":"mock-userstorage.mjs","sourceRoot":"","sources":["../../../src/sdk/__fixtures__/mock-userstorage.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,KAAI,aAAa;;AAExB,OAAO,UAAU,0CAAgC;AACjD,OAAO,EAAE,GAAG,EAAE,6BAAyB;AACvC,OAAO,EAAE,WAAW,EAAE,4BAAwB;AAO9C,sDAAsD;AACtD,MAAM,gBAAgB,GAAG,WAAW,CAClC,GAAG,CAAC,GAAG,EACP,qCAAqC,CACtC,CAAC;AACF,MAAM,oCAAoC,GAAG,WAAW,CACtD,GAAG,CAAC,GAAG,EACP,eAAe,CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AACnD,gFAAgF;AAChF,gEAAgE;AAChE,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC7D,MAAM,CAAC,MAAM,iCAAiC,GAAG,KAAK,IAAI,EAAE,CAC1D,MAAM,UAAU,CAAC,aAAa,CAC5B,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,EACvC,gBAAgB,CACjB,CAAC;AAEJ,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;IAChD,SAAS,EAAE,kEAAkE;IAC7E,IAAI,EAAE,MAAM,iCAAiC,EAAE;CAChD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,EAAE,SAAqB,EAAE,EAAE;IACtE,MAAM,KAAK,GAAG,SAAS,IAAI;QACzB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,MAAM,qBAAqB,EAAE;KACpC,CAAC;IACF,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC;SACxC,OAAO,EAAE;SACT,GAAG,CAAC,KAAK,CAAC;SACV,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yCAAyC,GAAG,KAAK,EAC5D,SAAqB,EACrB,EAAE;IACF,MAAM,KAAK,GAAG,SAAS,IAAI;QACzB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,CAAC,MAAM,qBAAqB,EAAE,CAAC;KACtC,CAAC;IACF,MAAM,YAAY,GAAG,IAAI,CAAC,oCAAoC,CAAC;SAC5D,OAAO,EAAE;SACT,GAAG,CAAC,EAAE,CAAC;SACP,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,SAAqB,EACrB,QAAiE,EACjE,EAAE;IACF,MAAM,KAAK,GAAG,SAAS,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC;SACxC,OAAO,EAAE;SACT,GAAG,CAAC,KAAK,CAAC;SACV,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE;QAC9C,OAAO,MAAM,QAAQ,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEL,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC","sourcesContent":["import nock from 'nock';\n\nimport encryption from '../../shared/encryption';\nimport { Env } from '../../shared/env';\nimport { STORAGE_URL } from '../user-storage';\n\ntype MockReply = {\n status: nock.StatusCode;\n body?: nock.Body;\n};\n\n// Example mock notifications storage entry (wildcard)\nconst MOCK_STORAGE_URL = STORAGE_URL(\n Env.DEV,\n 'notifications/notification_settings',\n);\nconst MOCK_STORAGE_URL_ALL_FEATURE_ENTRIES = STORAGE_URL(\n Env.DEV,\n 'notifications',\n);\n\nexport const MOCK_STORAGE_KEY = 'MOCK_STORAGE_KEY';\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const MOCK_NOTIFICATIONS_DATA = { is_compact: false };\nexport const MOCK_NOTIFICATIONS_DATA_ENCRYPTED = async () =>\n await encryption.encryptString(\n JSON.stringify(MOCK_NOTIFICATIONS_DATA),\n MOCK_STORAGE_KEY,\n );\n\nexport const MOCK_STORAGE_RESPONSE = async () => ({\n HashedKey: '8485d2c14c333ebca415140a276adaf546619b0efc204586b73a5d400a18a5e2',\n Data: await MOCK_NOTIFICATIONS_DATA_ENCRYPTED(),\n});\n\nexport const handleMockUserStorageGet = async (mockReply?: MockReply) => {\n const reply = mockReply ?? {\n status: 200,\n body: await MOCK_STORAGE_RESPONSE(),\n };\n const mockEndpoint = nock(MOCK_STORAGE_URL)\n .persist()\n .get(/.*/u)\n .reply(reply.status, reply.body);\n\n return mockEndpoint;\n};\n\nexport const handleMockUserStorageGetAllFeatureEntries = async (\n mockReply?: MockReply,\n) => {\n const reply = mockReply ?? {\n status: 200,\n body: [await MOCK_STORAGE_RESPONSE()],\n };\n const mockEndpoint = nock(MOCK_STORAGE_URL_ALL_FEATURE_ENTRIES)\n .persist()\n .get('')\n .reply(reply.status, reply.body);\n\n return mockEndpoint;\n};\n\nexport const handleMockUserStoragePut = (\n mockReply?: MockReply,\n callback?: (uri: string, requestBody: nock.Body) => Promise<void>,\n) => {\n const reply = mockReply ?? { status: 204 };\n const mockEndpoint = nock(MOCK_STORAGE_URL)\n .persist()\n .put(/.*/u)\n .reply(reply.status, async (uri, requestBody) => {\n return await callback?.(uri, requestBody);\n });\n\n return mockEndpoint;\n};\n"]}
@@ -27,7 +27,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
27
27
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
28
28
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
29
29
  };
30
- var _UserStorage_instances, _UserStorage_upsertUserStorage, _UserStorage_getUserStorage, _UserStorage_getUserStorageAllFeatureEntries, _UserStorage_createEntryKey, _UserStorage_getAuthorizationHeader;
30
+ var _UserStorage_instances, _UserStorage_upsertUserStorage, _UserStorage_batchUpsertUserStorage, _UserStorage_getUserStorage, _UserStorage_getUserStorageAllFeatureEntries, _UserStorage_createEntryKey, _UserStorage_getAuthorizationHeader;
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
32
  exports.UserStorage = exports.STORAGE_URL = void 0;
33
33
  const encryption_1 = __importStar(require("../shared/encryption/index.cjs"));
@@ -46,6 +46,9 @@ class UserStorage {
46
46
  async setItem(path, value) {
47
47
  await __classPrivateFieldGet(this, _UserStorage_instances, "m", _UserStorage_upsertUserStorage).call(this, path, value);
48
48
  }
49
+ async batchSetItems(path, values) {
50
+ await __classPrivateFieldGet(this, _UserStorage_instances, "m", _UserStorage_batchUpsertUserStorage).call(this, path, values);
51
+ }
49
52
  async getItem(path) {
50
53
  return __classPrivateFieldGet(this, _UserStorage_instances, "m", _UserStorage_getUserStorage).call(this, path);
51
54
  }
@@ -93,6 +96,41 @@ _UserStorage_instances = new WeakSet(), _UserStorage_upsertUserStorage = async f
93
96
  const errorMessage = e instanceof Error ? e.message : JSON.stringify(e ?? '');
94
97
  throw new errors_1.UserStorageError(`failed to upsert user storage for path '${path}'. ${errorMessage}`);
95
98
  }
99
+ }, _UserStorage_batchUpsertUserStorage = async function _UserStorage_batchUpsertUserStorage(path, data) {
100
+ try {
101
+ if (!data.length) {
102
+ return;
103
+ }
104
+ const headers = await __classPrivateFieldGet(this, _UserStorage_instances, "m", _UserStorage_getAuthorizationHeader).call(this);
105
+ const storageKey = await this.getStorageKey();
106
+ const encryptedData = await Promise.all(data.map(async (d) => {
107
+ return [
108
+ __classPrivateFieldGet(this, _UserStorage_instances, "m", _UserStorage_createEntryKey).call(this, d[0], storageKey),
109
+ await encryption_1.default.encryptString(d[1], storageKey),
110
+ ];
111
+ }));
112
+ const url = new URL((0, exports.STORAGE_URL)(this.env, path));
113
+ const response = await fetch(url.toString(), {
114
+ method: 'PUT',
115
+ headers: {
116
+ 'Content-Type': 'application/json',
117
+ ...headers,
118
+ },
119
+ body: JSON.stringify({ data: Object.fromEntries(encryptedData) }),
120
+ });
121
+ if (!response.ok) {
122
+ const responseBody = await response.json().catch(() => ({
123
+ message: 'unknown',
124
+ error: 'unknown',
125
+ }));
126
+ throw new Error(`HTTP error message: ${responseBody.message}, error: ${responseBody.error}`);
127
+ }
128
+ }
129
+ catch (e) {
130
+ /* istanbul ignore next */
131
+ const errorMessage = e instanceof Error ? e.message : JSON.stringify(e ?? '');
132
+ throw new errors_1.UserStorageError(`failed to batch upsert user storage for path '${path}'. ${errorMessage}`);
133
+ }
96
134
  }, _UserStorage_getUserStorage = async function _UserStorage_getUserStorage(path) {
97
135
  try {
98
136
  const headers = await __classPrivateFieldGet(this, _UserStorage_instances, "m", _UserStorage_getAuthorizationHeader).call(this);