@eluvio/elv-client-js 3.2.44 → 4.0.0

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.
@@ -1246,7 +1246,7 @@ var ElvWalletClient = /*#__PURE__*/function () {
1246
1246
  return this.client.ContentObjectMetadata({
1247
1247
  versionHash: marketplaceHash,
1248
1248
  metadataSubtree: "public/asset_metadata/info",
1249
- linkDepthLimit: 2,
1249
+ linkDepthLimit: 1,
1250
1250
  resolveLinks: true,
1251
1251
  resolveIgnoreErrors: true,
1252
1252
  resolveIncludeSource: true,
@@ -1432,7 +1432,11 @@ var ElvWalletClient = /*#__PURE__*/function () {
1432
1432
  start: start,
1433
1433
  limit: limit,
1434
1434
  sort_descending: sortDesc
1435
- };
1435
+ }; // Created isn't a valid sort mode for owned
1436
+
1437
+ if (mode === "owned" && sortBy === "created") {
1438
+ sortBy = "default";
1439
+ }
1436
1440
 
1437
1441
  if (mode !== "leaderboard") {
1438
1442
  params.sort_by = sortBy;
@@ -1443,33 +1447,33 @@ var ElvWalletClient = /*#__PURE__*/function () {
1443
1447
  }
1444
1448
 
1445
1449
  if (!marketplaceParams) {
1446
- _context16.next = 13;
1450
+ _context16.next = 14;
1447
1451
  break;
1448
1452
  }
1449
1453
 
1450
- _context16.next = 8;
1454
+ _context16.next = 9;
1451
1455
  return this.MarketplaceInfo({
1452
1456
  marketplaceParams: marketplaceParams
1453
1457
  });
1454
1458
 
1455
- case 8:
1459
+ case 9:
1456
1460
  marketplaceInfo = _context16.sent;
1457
1461
 
1458
1462
  if (!(collectionIndexes.length > 0)) {
1459
- _context16.next = 13;
1463
+ _context16.next = 14;
1460
1464
  break;
1461
1465
  }
1462
1466
 
1463
- _context16.next = 12;
1467
+ _context16.next = 13;
1464
1468
  return this.Marketplace({
1465
1469
  marketplaceParams: marketplaceParams
1466
1470
  });
1467
1471
 
1468
- case 12:
1472
+ case 13:
1469
1473
  marketplace = _context16.sent;
1470
1474
 
1471
- case 13:
1472
- _context16.prev = 13;
1475
+ case 14:
1476
+ _context16.prev = 14;
1473
1477
  filters = [];
1474
1478
 
1475
1479
  if (sellerAddress) {
@@ -1584,87 +1588,87 @@ var ElvWalletClient = /*#__PURE__*/function () {
1584
1588
  }
1585
1589
 
1586
1590
  _context16.t0 = mode;
1587
- _context16.next = _context16.t0 === "owned" ? 28 : _context16.t0 === "listings" ? 30 : _context16.t0 === "transfers" ? 32 : _context16.t0 === "sales" ? 36 : _context16.t0 === "listing-stats" ? 40 : _context16.t0 === "sales-stats" ? 42 : _context16.t0 === "leaderboard" ? 45 : 47;
1591
+ _context16.next = _context16.t0 === "owned" ? 29 : _context16.t0 === "listings" ? 31 : _context16.t0 === "transfers" ? 33 : _context16.t0 === "sales" ? 37 : _context16.t0 === "listing-stats" ? 41 : _context16.t0 === "sales-stats" ? 43 : _context16.t0 === "leaderboard" ? 46 : 48;
1588
1592
  break;
1589
1593
 
1590
- case 28:
1594
+ case 29:
1591
1595
  path = UrlJoin("as", "wlt", userAddress || this.UserAddress());
1592
- return _context16.abrupt("break", 47);
1596
+ return _context16.abrupt("break", 48);
1593
1597
 
1594
- case 30:
1598
+ case 31:
1595
1599
  path = UrlJoin("as", "mkt", "f");
1596
- return _context16.abrupt("break", 47);
1600
+ return _context16.abrupt("break", 48);
1597
1601
 
1598
- case 32:
1602
+ case 33:
1599
1603
  path = UrlJoin("as", "mkt", "hst", "f");
1600
1604
  filters.push("action:eq:TRANSFERRED");
1601
1605
  filters.push("action:eq:SOLD");
1602
- return _context16.abrupt("break", 47);
1606
+ return _context16.abrupt("break", 48);
1603
1607
 
1604
- case 36:
1608
+ case 37:
1605
1609
  path = UrlJoin("as", "mkt", "hst", "f");
1606
1610
  filters.push("action:eq:SOLD");
1607
1611
  filters.push("seller:co:0x");
1608
- return _context16.abrupt("break", 47);
1612
+ return _context16.abrupt("break", 48);
1609
1613
 
1610
- case 40:
1614
+ case 41:
1611
1615
  path = UrlJoin("as", "mkt", "stats", "listed");
1612
- return _context16.abrupt("break", 47);
1616
+ return _context16.abrupt("break", 48);
1613
1617
 
1614
- case 42:
1618
+ case 43:
1615
1619
  path = UrlJoin("as", "mkt", "stats", "sold");
1616
1620
  filters.push("seller:co:0x");
1617
- return _context16.abrupt("break", 47);
1621
+ return _context16.abrupt("break", 48);
1618
1622
 
1619
- case 45:
1623
+ case 46:
1620
1624
  path = UrlJoin("as", "wlt", "leaders");
1621
- return _context16.abrupt("break", 47);
1625
+ return _context16.abrupt("break", 48);
1622
1626
 
1623
- case 47:
1627
+ case 48:
1624
1628
  if (filters.length > 0) {
1625
1629
  params.filter = filters;
1626
1630
  }
1627
1631
 
1628
1632
  if (!mode.includes("stats")) {
1629
- _context16.next = 52;
1633
+ _context16.next = 53;
1630
1634
  break;
1631
1635
  }
1632
1636
 
1633
- _context16.next = 51;
1637
+ _context16.next = 52;
1634
1638
  return Utils.ResponseToJson(this.client.authClient.MakeAuthServiceRequest({
1635
1639
  path: path,
1636
1640
  method: "GET",
1637
1641
  queryParams: params
1638
1642
  }));
1639
1643
 
1640
- case 51:
1644
+ case 52:
1641
1645
  return _context16.abrupt("return", _context16.sent);
1642
1646
 
1643
- case 52:
1647
+ case 53:
1644
1648
  _context16.t2 = Utils;
1645
- _context16.next = 55;
1649
+ _context16.next = 56;
1646
1650
  return this.client.authClient.MakeAuthServiceRequest({
1647
1651
  path: path,
1648
1652
  method: "GET",
1649
1653
  queryParams: params
1650
1654
  });
1651
1655
 
1652
- case 55:
1656
+ case 56:
1653
1657
  _context16.t3 = _context16.sent;
1654
- _context16.next = 58;
1658
+ _context16.next = 59;
1655
1659
  return _context16.t2.ResponseToJson.call(_context16.t2, _context16.t3);
1656
1660
 
1657
- case 58:
1661
+ case 59:
1658
1662
  _context16.t1 = _context16.sent;
1659
1663
 
1660
1664
  if (_context16.t1) {
1661
- _context16.next = 61;
1665
+ _context16.next = 62;
1662
1666
  break;
1663
1667
  }
1664
1668
 
1665
1669
  _context16.t1 = [];
1666
1670
 
1667
- case 61:
1671
+ case 62:
1668
1672
  _ref16 = _context16.t1;
1669
1673
  contents = _ref16.contents;
1670
1674
  paging = _ref16.paging;
@@ -1680,12 +1684,12 @@ var ElvWalletClient = /*#__PURE__*/function () {
1680
1684
  })
1681
1685
  });
1682
1686
 
1683
- case 67:
1684
- _context16.prev = 67;
1685
- _context16.t4 = _context16["catch"](13);
1687
+ case 68:
1688
+ _context16.prev = 68;
1689
+ _context16.t4 = _context16["catch"](14);
1686
1690
 
1687
1691
  if (!(_context16.t4.status && _context16.t4.status.toString() === "404")) {
1688
- _context16.next = 71;
1692
+ _context16.next = 72;
1689
1693
  break;
1690
1694
  }
1691
1695
 
@@ -1699,15 +1703,15 @@ var ElvWalletClient = /*#__PURE__*/function () {
1699
1703
  results: []
1700
1704
  });
1701
1705
 
1702
- case 71:
1706
+ case 72:
1703
1707
  throw _context16.t4;
1704
1708
 
1705
- case 72:
1709
+ case 73:
1706
1710
  case "end":
1707
1711
  return _context16.stop();
1708
1712
  }
1709
1713
  }
1710
- }, _callee16, this, [[13, 67]]);
1714
+ }, _callee16, this, [[14, 68]]);
1711
1715
  }));
1712
1716
 
1713
1717
  function FilteredQuery() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-client-js",
3
- "version": "3.2.44",
3
+ "version": "4.0.0",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/index.js",
6
6
  "author": "Kevin Talmadge",
@@ -74,7 +74,7 @@
74
74
  "crocks": "^0.12.4",
75
75
  "deep-equal": "^1.0.1",
76
76
  "ellipsize": "^0.1.0",
77
- "ethers": "^4.0.26",
77
+ "ethers": "^5.7.2",
78
78
  "fraction.js": "^4.0.12",
79
79
  "hash.js": "^1.1.7",
80
80
  "image-type": "^4.1.0",
@@ -204,7 +204,7 @@ class AuthorizationClient {
204
204
  addr: Utils.FormatAddress(((this.client.signer && this.client.signer.address) || ""))
205
205
  };
206
206
 
207
- if(!(this.noAuth || noAuth)) {
207
+ if(update) {
208
208
  const { transactionHash } = await this.MakeAccessRequest({
209
209
  libraryId,
210
210
  objectId,
@@ -344,8 +344,8 @@ class AuthorizationClient {
344
344
 
345
345
  // Save request ID if present
346
346
  accessRequest.logs.some(log => {
347
- if(log.values && (log.values.requestID || log.values.requestNonce)) {
348
- this.requestIds[address] = (log.values.requestID || log.values.requestNonce || "").toString().replace(/^0x/, "");
347
+ if(log.args && (log.args.requestID || log.args.requestNonce)) {
348
+ this.requestIds[address] = (log.args.requestID || log.args.requestNonce || "").toString().replace(/^0x/, "");
349
349
  return true;
350
350
  }
351
351
  });
@@ -653,12 +653,12 @@ class AuthorizationClient {
653
653
  if(!isV3) {
654
654
  if(args && args.length > 0) {
655
655
  // Inject public key of requester
656
- args[1] = this.client.signer.signingKey ? this.client.signer.signingKey.publicKey : "";
656
+ args[1] = this.client.signer._signingKey ? this.client.signer._signingKey().publicKey : "";
657
657
  } else {
658
658
  // Set default args
659
659
  args = [
660
660
  0, // Access level
661
- this.client.signer.signingKey ? this.client.signer.signingKey.publicKey : "", // Public key of requester
661
+ this.client.signer._signingKey ? this.client.signer._signingKey().publicKey : "", // Public key of requester
662
662
  publicKey, //cap.public_key,
663
663
  [], // Custom values
664
664
  [] // Stakeholders
@@ -803,7 +803,7 @@ class AuthorizationClient {
803
803
  return await Ethers.utils.joinSignature(
804
804
  this.client.signer.signDigest ?
805
805
  await this.client.signer.signDigest(message) :
806
- await this.client.signer.signingKey.signDigest(message)
806
+ await this.client.signer._signingKey().signDigest(message)
807
807
  );
808
808
  }
809
809
 
package/src/ElvClient.js CHANGED
@@ -998,7 +998,7 @@ class ElvClient {
998
998
 
999
999
  ValidatePresence("message", message);
1000
1000
 
1001
- return await this.Crypto.EncryptConk(message, publicKey || this.signer.signingKey.keyPair.publicKey);
1001
+ return await this.Crypto.EncryptConk(message, publicKey || this.signer._signingKey().publicKey);
1002
1002
  }
1003
1003
 
1004
1004
  /**
@@ -1016,7 +1016,7 @@ class ElvClient {
1016
1016
 
1017
1017
  ValidatePresence("message", message);
1018
1018
 
1019
- return await this.Crypto.DecryptCap(message, this.signer.signingKey.privateKey);
1019
+ return await this.Crypto.DecryptCap(message, this.signer._signingKey().privateKey);
1020
1020
  }
1021
1021
 
1022
1022
  /**
@@ -1061,6 +1061,7 @@ class ElvClient {
1061
1061
  "GenerateWallet",
1062
1062
  "InitializeClients",
1063
1063
  "Log",
1064
+ "PersonalSign",
1064
1065
  "SetRemoteSigner",
1065
1066
  "SetSigner",
1066
1067
  "SetSignerFromWeb3Provider",
package/src/ElvWallet.js CHANGED
@@ -7,8 +7,6 @@ class ElvWallet {
7
7
  * NOTE: It is recommended to initialize wallets from the ElvClient, not using this constructor
8
8
  *
9
9
  * @see ElvClient#GenerateWallet()
10
- *
11
- * @param {string} providerUrl - URL of blockchain provider
12
10
  */
13
11
  constructor(provider) {
14
12
  this.provider = provider;
@@ -21,7 +19,7 @@ class ElvWallet {
21
19
  * @returns {string} - Space-separated list of random words
22
20
  */
23
21
  GenerateMnemonic() {
24
- return Ethers.utils.HDNode.entropyToMnemonic(Ethers.utils.randomBytes(16));
22
+ return Ethers.Wallet.createRandom().mnemonic.phrase;
25
23
  }
26
24
 
27
25
  /**
package/src/EthClient.js CHANGED
@@ -39,7 +39,7 @@ class EthClient {
39
39
  // HTTP client for making misc calls to elv-master
40
40
  this.HttpClient = new HttpClient({uris: this.ethereumURIs, debug: this.debug});
41
41
 
42
- Ethers.errors.setLogLevel("error");
42
+ //Ethers.errors.setLogLevel("error");
43
43
  }
44
44
 
45
45
  SetEthereumURIs(uris) {
@@ -234,7 +234,7 @@ class EthClient {
234
234
 
235
235
  contract = contract || this.Contract({contractAddress, abi, cacheContract, overrideCachedContract});
236
236
 
237
- abi = contract.interface.abi;
237
+ abi = contract.interface.fragments;
238
238
 
239
239
  // Automatically format contract arguments
240
240
  if(formatArguments) {
@@ -262,7 +262,7 @@ class EthClient {
262
262
  Args: [${methodArgs.join(", ")}]`
263
263
  );
264
264
 
265
- const methodAbi = contract.interface.abi.find(method => method.name === methodName);
265
+ const methodAbi = contract.interface.fragments.find(method => method.name === methodName);
266
266
 
267
267
  // Lock if performing a transaction
268
268
  if(!methodAbi || !methodAbi.constant) {
@@ -278,7 +278,7 @@ class EthClient {
278
278
  let success = false;
279
279
  while(!success) {
280
280
  try {
281
- result = await contract.functions[methodName](...methodArgs, overrides);
281
+ result = await contract[methodName](...methodArgs, overrides);
282
282
  success = true;
283
283
  } catch(error) {
284
284
  if(error.code === -32000 || error.code === "REPLACEMENT_UNDERPRICED") {
@@ -343,9 +343,15 @@ class EthClient {
343
343
 
344
344
  if(methodEvent) {
345
345
  methodEvent.logs = methodEvent.logs.map(log => {
346
+ let parsedLogs = {};
347
+ try {
348
+ parsedLogs = contract.interface.parseLog(log);
349
+ // eslint-disable-next-line no-empty
350
+ } catch(error) {}
351
+
346
352
  return {
347
353
  ...log,
348
- ...(contract.interface.parseLog(log))
354
+ ...parsedLogs
349
355
  };
350
356
  });
351
357
 
@@ -378,10 +384,13 @@ class EthClient {
378
384
  const contractInterface = new Ethers.utils.Interface(abi);
379
385
  // Loop through logs to find the desired log
380
386
  for(const log of event.logs) {
381
- const parsedLog = contractInterface.parseLog(log);
382
- if(parsedLog && parsedLog.name === eventName) {
383
- return parsedLog;
384
- }
387
+ try {
388
+ const parsedLog = contractInterface.parseLog(log);
389
+ if(parsedLog && parsedLog.name === eventName) {
390
+ return parsedLog;
391
+ }
392
+ // eslint-disable-next-line no-empty
393
+ } catch(error) {}
385
394
  }
386
395
  }
387
396
 
@@ -400,7 +409,7 @@ class EthClient {
400
409
  throw Error(`${methodName} failed - Log not present in transaction`);
401
410
  }
402
411
 
403
- const newContractAddress = eventLog.values[eventValue];
412
+ const newContractAddress = eventLog.args[eventValue];
404
413
 
405
414
  return {
406
415
  contractAddress: Utils.FormatAddress(newContractAddress),
@@ -243,7 +243,7 @@ class FrameClient {
243
243
  "DeleteUserMetadata",
244
244
  "MergeUserMetadata",
245
245
  "ReplaceUserMetadata",
246
- "UserMetadata"
246
+ "UserMetadata",
247
247
  ];
248
248
  }
249
249
 
@@ -268,6 +268,13 @@ class FrameClient {
268
268
  ];
269
269
  }
270
270
 
271
+ // List of methods that are defined separately in FrameClient
272
+ OverriddenMethods() {
273
+ return [
274
+ "UploadFiles"
275
+ ];
276
+ }
277
+
271
278
  // List of allowed methods available to frames
272
279
  // This should match ElvClient.FrameAvailableMethods()
273
280
  // ElvClient will also reject any disallowed methods
@@ -334,6 +341,7 @@ class FrameClient {
334
341
  "CreateContentObject",
335
342
  "CreateContentType",
336
343
  "CreateEncryptionConk",
344
+ "CreateFabricToken",
337
345
  "CreateFileDirectories",
338
346
  "CreateFileUploadJob",
339
347
  "CreateLinks",
@@ -377,6 +385,7 @@ class FrameClient {
377
385
  "FinalizeUploadJob",
378
386
  "FormatContractArguments",
379
387
  "GenerateStateChannelToken",
388
+ "GenerateSignedLinkToken",
380
389
  "GetBalance",
381
390
  "InitializeAuthPolicy",
382
391
  "IssueNTPCode",
@@ -440,7 +449,6 @@ class FrameClient {
440
449
  "UpdateContentObjectGraph",
441
450
  "UpdateNTPInstance",
442
451
  "UploadFileData",
443
- /*"UploadFiles",*/ //Override
444
452
  "UploadFilesFromS3",
445
453
  "UploadJobStatus",
446
454
  "UploadPart",
package/src/HttpClient.js CHANGED
@@ -22,8 +22,8 @@ class HttpClient {
22
22
  return Fetch(url, params);
23
23
  }
24
24
 
25
- RecordWriteToken(writeToken) {
26
- this.draftURIs[writeToken] = this.BaseURI();
25
+ RecordWriteToken(writeToken, nodeUrlStr) {
26
+ this.draftURIs[writeToken] = nodeUrlStr ? new URI(nodeUrlStr) : this.BaseURI();
27
27
  }
28
28
 
29
29
  RequestHeaders(bodyType, headers={}) {
@@ -54,7 +54,7 @@ class HttpClient {
54
54
  let baseURI = this.BaseURI();
55
55
 
56
56
  // If URL contains a write token, it must go to the correct server and can not fail over
57
- const writeTokenMatch = path.replace(/^\//, "").match(/(qlibs\/ilib[a-zA-Z0-9]+|q|qid)\/(tqw_[a-zA-Z0-9]+)/);
57
+ const writeTokenMatch = path.replace(/^\//, "").match(/(qlibs\/ilib[a-zA-Z0-9]+|q|qid)\/(tqw__[a-zA-Z0-9]+)/);
58
58
  const writeToken = writeTokenMatch ? writeTokenMatch[2] : undefined;
59
59
 
60
60
  if(writeToken) {
@@ -34,6 +34,8 @@ const {
34
34
  * @param {boolean=} encrypt=true - (Local or copied files only) - Unless `false` is passed in explicitly, any uploaded/copied files will be stored encrypted
35
35
  * @param {boolean=} copy=false - (S3) If specified, files will be copied from S3
36
36
  * @param {function=} callback - Progress callback for file upload (See UploadFiles/UploadFilesFromS3 method)
37
+ * @param {("warn"|"info"|"debug")=} respLogLevel=warn - The level of logging to return in http response
38
+ * @param {("none"|"error"|"warn"|"info"|"debug")=} structLogLevel=none - The level of logging to save to object metadata
37
39
  * @param {Array<Object>=} access=[] - Array of cloud credentials, along with path matching regex strings - Required if any files in the masters are cloud references (currently only AWS S3 is supported)
38
40
  * - If this parameter is non-empty, all items in fileInfo are assumed to be items in cloud storage
39
41
  * - Format: [
@@ -76,7 +78,9 @@ exports.CreateProductionMaster = async function({
76
78
  encrypt=true,
77
79
  access=[],
78
80
  copy=false,
79
- callback
81
+ callback,
82
+ respLogLevel = "warn",
83
+ structLogLevel="none"
80
84
  }) {
81
85
  ValidateLibrary(libraryId);
82
86
 
@@ -174,6 +178,10 @@ exports.CreateProductionMaster = async function({
174
178
  objectId: id,
175
179
  writeToken: write_token,
176
180
  method: UrlJoin("media", "production_master", "init"),
181
+ queryParams: {
182
+ response_log_level: respLogLevel,
183
+ struct_log_level: structLogLevel
184
+ },
177
185
  body: {
178
186
  access
179
187
  },
@@ -215,20 +223,25 @@ exports.CreateProductionMaster = async function({
215
223
  };
216
224
 
217
225
  /**
218
- * Create a mezzanine of the given master content object
226
+ * Create (or edit) a mezzanine offering based on the a given master content object version and variant key
219
227
  *
220
228
  * @methodGroup ABR Publishing
221
229
  * @namedParams
230
+ * @param {Object=} abrProfile - Custom ABR profile. If not specified, the profile of the mezzanine library will be used
231
+ * @param {Object=} addlOfferingSpecs - Specs for additional offerings to create by patching the offering being created/edited
232
+ * @param {string=} description - Description for mezzanine content object
233
+ * @param {boolean=} keepOtherStreams=false - If objectId is specified, whether to preserve existing streams with keys other than the ones specified in production master
222
234
  * @param {string} libraryId - ID of the mezzanine library
235
+ * @param {string} masterVersionHash - The version hash of the production master content object
236
+ * @param {Object=} metadata - Additional metadata for mezzanine content object
237
+ * @param {string} name - Name for mezzanine content object
223
238
  * @param {string=} objectId - ID of existing object (if not specified, new object will be created)
239
+ * @param {string=} offeringKey=default - The key of the offering to create
240
+ * @param {("warn"|"info"|"debug")=} respLogLevel=warn - The level of logging to return in http response
241
+ * @param {("none"|"error"|"warn"|"info"|"debug")=} structLogLevel=none - The level of logging to save to object metadata
242
+ * @param {Array<string>} streamKeys - List of stream keys from variant to include. If not supplied all streams will be included.
224
243
  * @param {string=} type - ID or version hash of the content type for the mezzanine
225
- * @param {string} name - Name for mezzanine content object
226
- * @param {string=} description - Description for mezzanine content object
227
- * @param {Object=} metadata - Additional metadata for mezzanine content object
228
- * @param {string} masterVersionHash - The version hash of the production master content object
229
244
  * @param {string=} variant=default - What variant of the master content object to use
230
- * @param {string=} offeringKey=default - The key of the offering to create
231
- * @param {Object=} abrProfile - Custom ABR profile. If not specified, the profile of the mezzanine library will be used
232
245
  *
233
246
  * @return {Object} - The finalize response for the object, as well as logs, warnings and errors from the mezzanine initialization
234
247
  */
@@ -241,8 +254,13 @@ exports.CreateABRMezzanine = async function({
241
254
  metadata,
242
255
  masterVersionHash,
243
256
  abrProfile,
257
+ addlOfferingSpecs,
244
258
  variant="default",
245
- offeringKey="default"
259
+ offeringKey="default",
260
+ keepOtherStreams= false,
261
+ respLogLevel = "warn",
262
+ structLogLevel="none",
263
+ streamKeys
246
264
  }) {
247
265
  ValidateLibrary(libraryId);
248
266
  ValidateVersion(masterVersionHash);
@@ -251,6 +269,14 @@ exports.CreateABRMezzanine = async function({
251
269
  throw Error("Master version hash not specified");
252
270
  }
253
271
 
272
+ if(!objectId && (keepOtherStreams)) {
273
+ throw Error("Existing mezzanine object ID required in order to use 'keepOtherStreams'");
274
+ }
275
+
276
+ if(addlOfferingSpecs && !abrProfile) {
277
+ throw Error("abrProfile required when using addlOfferingSpecs");
278
+ }
279
+
254
280
  const existingMez = !!objectId;
255
281
 
256
282
  let options = type ? { type } : {};
@@ -295,9 +321,12 @@ exports.CreateABRMezzanine = async function({
295
321
  };
296
322
 
297
323
  const body = {
324
+ additional_offering_specs: addlOfferingSpecs,
298
325
  offering_key: offeringKey,
299
- variant_key: variant,
300
- prod_master_hash: masterVersionHash
326
+ keep_other_streams: keepOtherStreams,
327
+ prod_master_hash: masterVersionHash,
328
+ stream_keys: streamKeys,
329
+ variant_key: variant
301
330
  };
302
331
 
303
332
  let storeClear = false;
@@ -327,6 +356,10 @@ exports.CreateABRMezzanine = async function({
327
356
  objectId: id,
328
357
  writeToken: write_token,
329
358
  method: UrlJoin("media", "abr_mezzanine", "init"),
359
+ queryParams: {
360
+ response_log_level: respLogLevel,
361
+ struct_log_level: structLogLevel
362
+ },
330
363
  headers,
331
364
  body,
332
365
  constant: false
@@ -551,26 +584,14 @@ exports.LROStatus = async function({libraryId, objectId, offeringKey="default"})
551
584
  }
552
585
  }
553
586
 
554
- let error, result;
555
- const fabricURIs = this.fabricURIs;
556
- try {
557
- this.SetNodes({fabricURIs: [lroDraft.node, ...fabricURIs]});
558
-
559
- result = await this.ContentObjectMetadata({
560
- libraryId,
561
- objectId,
562
- writeToken: lroDraft.write_token,
563
- metadataSubtree: "lro_status"
564
- });
565
- } catch(err) {
566
- error = err;
567
- } finally {
568
- this.SetNodes({fabricURIs});
569
- }
587
+ this.HttpClient.RecordWriteToken(lroDraft.write_token, lroDraft.node);
570
588
 
571
- if(error) { throw error; }
572
-
573
- return result;
589
+ return await this.ContentObjectMetadata({
590
+ libraryId,
591
+ objectId,
592
+ writeToken: lroDraft.write_token,
593
+ metadataSubtree: "lro_status"
594
+ });
574
595
  };
575
596
 
576
597
  /**
@@ -582,10 +603,12 @@ exports.LROStatus = async function({libraryId, objectId, offeringKey="default"})
582
603
  * @param {string} objectId - ID of the mezzanine object
583
604
  * @param {string} writeToken - Write token for the mezzanine object
584
605
  * @param {string=} offeringKey=default - The offering to process
606
+ * @param {function=} preFinalizeFn - A function to call before finalizing changes, to allow further modifications to offering. The function will be invoked with {elvClient, nodeUrl, writeToken} to allow access to the draft and MUST NOT finalize the draft.
607
+ * @param {boolean=} preFinalizeThrow - If set to `true` then any error thrown by preFinalizeFn will not be caught. Otherwise, any exception will be appended to the `warnings` array returned after finalization.
585
608
  *
586
609
  * @return {Promise<Object>} - The finalize response for the mezzanine object, as well as any logs, warnings and errors from the finalization
587
610
  */
588
- exports.FinalizeABRMezzanine = async function({libraryId, objectId, offeringKey="default"}) {
611
+ exports.FinalizeABRMezzanine = async function({libraryId, objectId, offeringKey="default", preFinalizeFn, preFinalizeThrow}) {
589
612
  ValidateParameters({libraryId, objectId});
590
613
 
591
614
  const lroDraft = await this.ContentObjectMetadata({
@@ -632,6 +655,22 @@ exports.FinalizeABRMezzanine = async function({libraryId, objectId, offeringKey=
632
655
  constant: false
633
656
  });
634
657
 
658
+ let preFinalizeWarnings = [];
659
+ if(preFinalizeFn) {
660
+ const params = {
661
+ elvClient: this,
662
+ nodeUrl: lroDraft.node,
663
+ writeToken: lroDraft.write_token
664
+ };
665
+ if(preFinalizeThrow){
666
+ await preFinalizeFn(params);
667
+ } else try {
668
+ await preFinalizeFn(params);
669
+ } catch(e) {
670
+ preFinalizeWarnings = `Error trying to set video stream codec descriptors: ${e}`;
671
+ }
672
+ }
673
+
635
674
  const finalizeResponse = await this.FinalizeContentObject({
636
675
  libraryId,
637
676
  objectId: objectId,
@@ -643,7 +682,7 @@ exports.FinalizeABRMezzanine = async function({libraryId, objectId, offeringKey=
643
682
  result = {
644
683
  data,
645
684
  logs: logs || [],
646
- warnings: warnings || [],
685
+ warnings: (warnings || []).concat(preFinalizeWarnings),
647
686
  errors: errors || [],
648
687
  ...finalizeResponse
649
688
  };