@eluvio/elv-client-js 4.0.142 → 4.0.144

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-client-js",
3
- "version": "4.0.142",
3
+ "version": "4.0.144",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/index.js",
6
6
  "author": "Kevin Talmadge",
@@ -575,6 +575,7 @@ class FrameClient {
575
575
  "Profile",
576
576
  "ProfileMetadata",
577
577
  "PurchaseStatus",
578
+ "PurgeUrl",
578
579
  "PushNotification",
579
580
  "RejectMarketplaceOffer",
580
581
  "RemoveListing",
@@ -831,7 +831,7 @@ exports.FinalizeABRMezzanine = async function({libraryId, objectId, preFinalizeF
831
831
  }
832
832
  }
833
833
 
834
- const finalizeResponse = {};
834
+ let finalizeResponse = {};
835
835
  if(!writeToken) {
836
836
  finalizeResponse = await this.FinalizeContentObject({
837
837
  libraryId,
@@ -1098,8 +1098,12 @@ exports.ContentObjectVersions = async function({libraryId, objectId}) {
1098
1098
  * @returns {Promise<string>} - The latest version hash of the object
1099
1099
  */
1100
1100
  exports.LatestVersionHash = async function({objectId, versionHash}) {
1101
+ if(versionHash) {
1102
+ objectId = this.utils.DecodeVersionHash(versionHash).objectId;
1103
+ }
1104
+
1101
1105
  try {
1102
- return (await this.ContentObject({objectId, versionHash})).hash;
1106
+ return (await this.ContentObject({objectId})).hash;
1103
1107
  } catch(error) {
1104
1108
  error.message = `Unable to determine latest version hash for ${versionHash || objectId}`;
1105
1109
  throw error;
@@ -928,4 +928,262 @@ exports.ResetTenantId = async function({contractAddress, objectId, versionHash})
928
928
  }
929
929
  };
930
930
 
931
+ /**
932
+ * Enum for object types that can be cleaned up after object deletion.
933
+ * Used by the ObjectCleanup method to determine which associated objects to clean.
934
+ *
935
+ * @property {string=} LIBRARY - Cleanup libraries
936
+ * @property {string=} CONTENT_OBJECT - Cleanup content objects
937
+ * @property {string=} GROUP - Cleanup access groups
938
+ * @property {string=} CONTENT_TYPE - Cleanup content types
939
+ * @property {string=} ALL - Cleanup all of the above
940
+ */
941
+ const ObjectTypesToClean = Object.freeze({
942
+ LIBRARY: "library",
943
+ CONTENT_OBJECT: "content_object",
944
+ GROUP: "group",
945
+ CONTENT_TYPE: "content_type",
946
+ ALL: "all"
947
+ });
948
+
949
+ /**
950
+ * Cleans up deleted objects pointed to by the access index of a given "access group" or "user wallet"
951
+ * Contracts of type "access group" and "user wallet" contain an "access index" - a list of objects that they have access to.
952
+ *
953
+ * There are 4 specific indexes, one for each object type:
954
+ * - content
955
+ * - library
956
+ * - access groups
957
+ * - content types
958
+ *
959
+ * If an object gets deleted and the access index still points to it, it will cause errors in API calls for the access
960
+ * group or user wallet.
961
+ *
962
+ * This function checks each index for objects that are deleted, and removes them from the index (either all indexes or
963
+ * just the one specified by parameter 'objectTypeToClean')
964
+ *
965
+ * For user, the cleanup is performed on the user wallet and on all its access group
966
+ *
967
+ * @methodGroup Contracts
968
+ * @namedParams
969
+ * @param {string=} contractAddress - The address of the object
970
+ * @param {string=} objectId - The ID of the object
971
+ * @param {string=} versionHash - A version hash of the object
972
+ * @param {string=} objectTypeToClean - The type of object to clean: one of "library", "content_object", "group", "content_type", or "all"
973
+ * @returns {Promise<Object>} - Resolves with an object showing the count of items before and after cleanup.
974
+ *
975
+ * Example return value:
976
+ * {
977
+ * "0x123...": {
978
+ * beforeCleanup: {
979
+ * librariesLength: 2,
980
+ * contentObjectsLength: 4,
981
+ * accessGroupsLength: 1,
982
+ * contentTypesLength: 3
983
+ * },
984
+ * afterCleanup: {
985
+ * librariesLength: 0,
986
+ * contentObjectsLength: 0,
987
+ * accessGroupsLength: 0,
988
+ * contentTypesLength: 0
989
+ * }
990
+ * },
991
+ * "groups": {
992
+ * "0x123...": {
993
+ * beforeCleanup: {
994
+ * contentObjectsLength: 1
995
+ * },
996
+ * afterCleanup: {
997
+ * contentObjectsLength: 0
998
+ * }
999
+ * }
1000
+ * }
1001
+ * }
1002
+ */
1003
+ exports.ObjectCleanup = async function ({
1004
+ contractAddress,
1005
+ objectId,
1006
+ versionHash,
1007
+ objectTypeToClean = ObjectTypesToClean.ALL
1008
+ }) {
1009
+ objectInfo = await GetObjectIDAndContractAddress({contractAddress, objectId, versionHash});
1010
+ contractAddress = objectInfo.contractAddress;
1011
+ let isUserWallet = false;
1012
+ let userAddress;
1013
+
1014
+ // Check if the contract is a user wallet address
1015
+ try {
1016
+ await this.CallContractMethod({
1017
+ contractAddress,
1018
+ methodName: "getLibrariesLength",
1019
+ formatArguments: false,
1020
+ });
1021
+ } catch(e) {
1022
+ try {
1023
+ userAddress = contractAddress;
1024
+ contractAddress = await this.userProfileClient.UserWalletAddress({address: contractAddress});
1025
+ isUserWallet = true;
1026
+ } catch(walletError) {
1027
+ throw new Error(`Invalid object: ${walletError.message}`);
1028
+ }
1029
+ }
1030
+
1031
+ const allowedTypes = Object.values(ObjectTypesToClean);
1032
+ if(!allowedTypes.includes(objectTypeToClean)) {
1033
+ throw Error(`Invalid objectType '${objectTypeToClean}'. Allowed types: ${allowedTypes.join(", ")}`);
1034
+ }
1035
+
1036
+ const cleanupTasks = {
1037
+ [ObjectTypesToClean.LIBRARY]: async ({contractAddress, res}) => {
1038
+ const before = await this.CallContractMethod({
1039
+ contractAddress,
1040
+ methodName: "getLibrariesLength",
1041
+ formatArguments: false,
1042
+ });
1043
+ res.beforeCleanup.librariesLength = before.toNumber();
1044
+
1045
+ await this.CallContractMethodAndWait({
1046
+ contractAddress,
1047
+ methodName: "cleanUpLibraries",
1048
+ formatArguments: true,
1049
+ });
1050
+
1051
+ const after = await this.CallContractMethod({
1052
+ contractAddress,
1053
+ methodName: "getLibrariesLength",
1054
+ formatArguments: false,
1055
+ });
1056
+ res.afterCleanup.librariesLength = after.toNumber();
1057
+ },
1058
+
1059
+ [ObjectTypesToClean.CONTENT_OBJECT]: async ({contractAddress, res}) => {
1060
+ const before = await this.CallContractMethod({
1061
+ contractAddress,
1062
+ methodName: "getContentObjectsLength",
1063
+ formatArguments: false,
1064
+ });
1065
+ res.beforeCleanup.contentObjectsLength = before.toNumber();
1066
+
1067
+ await this.CallContractMethodAndWait({
1068
+ contractAddress,
1069
+ methodName: "cleanUpContentObjects",
1070
+ formatArguments: true,
1071
+ });
1072
+
1073
+ const after = await this.CallContractMethod({
1074
+ contractAddress,
1075
+ methodName: "getContentObjectsLength",
1076
+ formatArguments: false,
1077
+ });
1078
+ res.afterCleanup.contentObjectsLength = after.toNumber();
1079
+ },
1080
+
1081
+ [ObjectTypesToClean.GROUP]: async ({contractAddress, res}) => {
1082
+ let before = await this.CallContractMethod({
1083
+ contractAddress,
1084
+ methodName: "getAccessGroupsLength",
1085
+ formatArguments: false,
1086
+ });
1087
+ res.beforeCleanup.accessGroupsLength = before.toNumber();
1088
+
1089
+ await this.CallContractMethodAndWait({
1090
+ contractAddress,
1091
+ methodName: "cleanUpAccessGroups",
1092
+ formatArguments: true,
1093
+ });
1094
+
1095
+ const after = await this.CallContractMethod({
1096
+ contractAddress,
1097
+ methodName: "getAccessGroupsLength",
1098
+ formatArguments: false,
1099
+ });
1100
+ res.afterCleanup.accessGroupsLength = after.toNumber();
1101
+ },
1102
+
1103
+ [ObjectTypesToClean.CONTENT_TYPE]: async ({contractAddress, res}) => {
1104
+ const before = await this.CallContractMethod({
1105
+ contractAddress,
1106
+ methodName: "getContentTypesLength",
1107
+ formatArguments: false,
1108
+ });
1109
+ res.beforeCleanup.contentTypesLength = before.toNumber();
1110
+
1111
+ await this.CallContractMethodAndWait({
1112
+ contractAddress,
1113
+ methodName: "cleanUpContentTypes",
1114
+ formatArguments: true,
1115
+ });
1116
+
1117
+ const after = await this.CallContractMethod({
1118
+ contractAddress,
1119
+ methodName: "getContentTypesLength",
1120
+ formatArguments: false,
1121
+ });
1122
+ res.afterCleanup.contentTypesLength = after.toNumber();
1123
+ }
1124
+ };
1125
+
1126
+ const runCleanupTasks = async ({contractAddress}) => {
1127
+ try {
1128
+ const res = {
1129
+ beforeCleanup: {},
1130
+ afterCleanup: {}
1131
+ };
1132
+ if(objectTypeToClean === ObjectTypesToClean.ALL) {
1133
+ for(const type of Object.keys(cleanupTasks)) {
1134
+ await cleanupTasks[type]({contractAddress, res});
1135
+ }
1136
+ } else {
1137
+ await cleanupTasks[objectTypeToClean]({contractAddress, res});
1138
+ }
1139
+ return res;
1140
+ } catch(e) {
1141
+ throw new Error(`Error during '${objectTypeToClean}' cleanup for ${contractAddress}: ${e.message}`);
1142
+ }
1143
+ };
1144
+
1145
+ let results = {};
1146
+ // run cleanup on main contract
1147
+ const res = await runCleanupTasks({contractAddress});
1148
+ if(isUserWallet){
1149
+ results[userAddress] = res;
1150
+ } else {
1151
+ results[contractAddress] = res;
1152
+ }
1153
+
1154
+ // run cleanup on access group contracts if this is a user wallet
1155
+ if(isUserWallet) {
1156
+ const groupsLength = await this.CallContractMethod({
1157
+ contractAddress,
1158
+ methodName: "getAccessGroupsLength",
1159
+ formatArguments: false,
1160
+ });
1161
+ if(groupsLength > 0) {
1162
+ results["groups"] = {};
1163
+ }
1164
+
1165
+ const groupAddressPromises = [];
1166
+ for(let i=0; i<groupsLength; i++) {
1167
+ groupAddressPromises.push(
1168
+ this.CallContractMethod({
1169
+ contractAddress,
1170
+ methodName: "getAccessGroup",
1171
+ methodArgs: [i],
1172
+ formatArguments: false,
1173
+ })
1174
+ );
1175
+ }
1176
+
1177
+ const groupAddresses = await Promise.all(groupAddressPromises);
1178
+ const cleanupResults = await Promise.all(
1179
+ groupAddresses.map(addr =>
1180
+ runCleanupTasks({contractAddress: addr}).then(res => [addr, res]))
1181
+ );
1182
+
1183
+ for(const [addr, res] of cleanupResults) {
1184
+ results["groups"][addr] = res;
1185
+ }
1186
+ }
1187
+ return results;
1188
+ };
931
1189
 
@@ -1344,6 +1344,19 @@ class ElvWalletClient {
1344
1344
  }
1345
1345
  });
1346
1346
  }
1347
+
1348
+ async PurgeUrl({tenantId, url}) {
1349
+ const body = { url };
1350
+ const token = await this.client.CreateFabricToken({});
1351
+ await this.client.authClient.MakeAuthServiceRequest({
1352
+ path: UrlJoin("as", "tnt", tenantId, "purge"),
1353
+ method: "POST",
1354
+ body,
1355
+ headers: {
1356
+ Authorization: `Bearer ${token}`
1357
+ }
1358
+ });
1359
+ }
1347
1360
  }
1348
1361
 
1349
1362
  Object.assign(ElvWalletClient.prototype, require("./ClientMethods"));