@eluvio/elv-client-js 4.0.77 → 4.0.79

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.77",
3
+ "version": "4.0.79",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/index.js",
6
6
  "author": "Kevin Talmadge",
@@ -387,6 +387,7 @@ class FrameClient {
387
387
  "DeleteMetadata",
388
388
  "DeleteNTPInstance",
389
389
  "DeletePart",
390
+ "DeleteWriteToken",
390
391
  "DeployContract",
391
392
  "Download",
392
393
  "DownloadEncrypted",
@@ -478,6 +479,7 @@ class FrameClient {
478
479
  "StreamCreate",
479
480
  "StreamInitialize",
480
481
  "StreamInsertion",
482
+ "StreamListUrls",
481
483
  "StreamStatus",
482
484
  "StreamStartOrStopOrReset",
483
485
  "StreamStopSession",
package/src/HttpClient.js CHANGED
@@ -29,6 +29,12 @@ class HttpClient {
29
29
  this.draftURIs[writeToken] = new URI(nodeUrlStr);
30
30
  }
31
31
 
32
+ ClearWriteToken({writeToken}) {
33
+ if(Object.hasOwn(this.draftURIs, writeToken)) {
34
+ delete this.draftURIs[writeToken];
35
+ }
36
+ }
37
+
32
38
  RequestHeaders(bodyType, headers={}) {
33
39
  if(!headers.Accept) {
34
40
  headers["Accept"] = "application/json";
@@ -476,9 +476,11 @@ await client.userProfileClient.UserMetadata()
476
476
  */
477
477
  async TenantContractId() {
478
478
  if(!this.tenantContractId) {
479
- this.tenantContractId = await this.UserMetadata({metadataSubtree: "tenantContractId"});
479
+ const {objectId} = await this.UserWalletObjectInfo();
480
+ this.tenantContractId = await this.client.TenantContractId({
481
+ contractAddress: this.client.utils.HashToAddress(objectId)
482
+ });
480
483
  }
481
-
482
484
  return this.tenantContractId;
483
485
  }
484
486
 
@@ -489,44 +491,13 @@ await client.userProfileClient.UserMetadata()
489
491
  *
490
492
  * @namedParams
491
493
  * @param {string} tenantContractId - The tenant contract ID in hash format
492
- * @param {string} address - The group address to use in the hash if id is not provided
494
+ * @param {string} address - The tenant address to use in the hash if id is not provided
493
495
  */
494
- async SetTenantContractId({tenantContractId, address}) {
495
- if(tenantContractId && (!tenantContractId.startsWith("iten") || !Utils.ValidHash(tenantContractId))) {
496
- throw Error(`Invalid tenant ID: ${tenantContractId}`);
497
- }
498
-
499
- if(address) {
500
- if(!Utils.ValidAddress(address)) {
501
- throw Error(`Invalid address: ${address}`);
502
- }
503
-
504
- tenantContractId = `iten${Utils.AddressToHash(address)}`;
505
- }
496
+ async SetTenantContractId({tenantContractId}) {
497
+ const {objectId} = await this.UserWalletObjectInfo();
506
498
 
507
- try {
508
- const version = await this.client.AccessType({id: tenantContractId});
509
-
510
- if(version !== this.client.authClient.ACCESS_TYPES.TENANT) {
511
- throw Error("Invalid tenant ID: " + tenantContractId);
512
- }
513
- } catch(error) {
514
- throw Error("Invalid tenant ID: " + tenantContractId);
515
- }
516
-
517
- const tenantAdminGroupAddress = await this.client.CallContractMethod({
518
- contractAddress: address || Utils.HashToAddress(tenantContractId),
519
- methodName: "groupsMapping",
520
- methodArgs : ["tenant_admin", 0],
521
- formatArguments: true,
522
- });
523
-
524
- await this.MergeUserMetadata({
525
- metadata: {
526
- tenantContractId,
527
- tenantId: !tenantAdminGroupAddress ? undefined : `iten${Utils.AddressToHash(tenantAdminGroupAddress)}`
528
- }
529
- });
499
+ const tenantInfo = await this.client.SetTenantContractId({ objectId,tenantContractId });
500
+ this.tenantContractId = tenantInfo.tenantContractId;
530
501
  }
531
502
 
532
503
  /**
@@ -241,9 +241,8 @@ exports.CreateAccessGroup = async function({name, description, metadata={}, visi
241
241
  this.Log(`Creating access group: ${name || ""} ${description || ""}`);
242
242
  let { contractAddress } = await this.authClient.CreateAccessGroup();
243
243
  contractAddress = this.utils.FormatAddress(contractAddress);
244
-
245
244
  const objectId = this.utils.AddressToObjectId(contractAddress);
246
- const tenantId = await this.userProfileClient.TenantId();
245
+ const tenantContractId = await this.userProfileClient.TenantContractId();
247
246
 
248
247
  this.Log(`Access group: ${contractAddress} ${objectId}`);
249
248
 
@@ -262,27 +261,6 @@ exports.CreateAccessGroup = async function({name, description, metadata={}, visi
262
261
  ...metadata
263
262
  };
264
263
 
265
- if(tenantId) {
266
- let tenantAdminGroupAddress = this.utils.HashToAddress(tenantId);
267
-
268
- await this.AddContentObjectGroupPermission({
269
- objectId,
270
- groupAddress: tenantAdminGroupAddress,
271
- permission: "manage"
272
- });
273
-
274
- await this.ReplaceContractMetadata({
275
- contractAddress,
276
- metadataKey: "_tenantId",
277
- metadata: tenantId
278
- });
279
-
280
- groupMetadata["tenantId"] = tenantId;
281
- } else {
282
- // eslint-disable-next-line no-console
283
- console.warn("No tenant ID associated with current tenant.");
284
- }
285
-
286
264
  await this.ReplaceMetadata({
287
265
  libraryId: this.contentSpaceLibraryId,
288
266
  objectId,
@@ -303,6 +281,23 @@ exports.CreateAccessGroup = async function({name, description, metadata={}, visi
303
281
  commitMessage: "Create access group"
304
282
  });
305
283
 
284
+ if(tenantContractId){
285
+ const tenantInfo = await this.SetTenantContractId({contractAddress, tenantContractId});
286
+
287
+ if(tenantInfo.tenantId) {
288
+ let tenantAdminGroupAddress = this.utils.HashToAddress(tenantInfo.tenantId);
289
+
290
+ await this.AddContentObjectGroupPermission({
291
+ objectId,
292
+ groupAddress: tenantAdminGroupAddress,
293
+ permission: "manage"
294
+ });
295
+ } else {
296
+ // eslint-disable-next-line no-console
297
+ console.warn("No tenant ID associated with current tenant.");
298
+ }
299
+ }
300
+
306
301
  return contractAddress;
307
302
  };
308
303
 
@@ -946,4 +941,4 @@ exports.UnlinkAccessGroupFromOauth = async function({groupAddress}) {
946
941
  methodName: "setOAuthEnabled",
947
942
  methodArgs: [false]
948
943
  });
949
- };
944
+ };
@@ -1275,7 +1275,7 @@ exports.PlayoutPathResolution = async function({
1275
1275
  * Retrieve available playout offerings for the specified content
1276
1276
  *
1277
1277
  * @methodGroup Media
1278
- * @param {string=} objectId - Id of the content
1278
+ * @param {string=} objectId - ID of the content
1279
1279
  * @param {string=} versionHash - Version hash of the content
1280
1280
  * @param {string=} writeToken - Write token for the content
1281
1281
  * @param {string=} linkPath - If playing from a link, the path to the link
@@ -2176,6 +2176,11 @@ const EmbedMediaTypes = {
2176
2176
  - `showTitle` - Shows the video title, which is set from the title option (if set) or the metadata
2177
2177
  - `title` - Sets the page title
2178
2178
  - `viewRecordKey` - Contains record key
2179
+ - `useTicketCodes` - Use tickets authorization
2180
+ - `tenantId` - Tenant ID, required for tickets authorization
2181
+ - `ntpId` - NTP ID, required for tickets authorization
2182
+ - `ticketCode` - Ticket code, optional with tickets authorization
2183
+ - `ticketSubject` - Ticket subject, optional with tickets authorization
2179
2184
  *
2180
2185
  * @returns {Promise<string>} - Will return an embed URL
2181
2186
  */
@@ -2279,6 +2284,22 @@ exports.EmbedUrl = async function({
2279
2284
  case "viewRecordKey":
2280
2285
  embedUrl.searchParams.set("vrk", options.viewRecordKey);
2281
2286
  break;
2287
+ case "useTicketCodes":
2288
+ embedUrl.searchParams.set("ptk", "");
2289
+ if (options.tenantId) {
2290
+ embedUrl.searchParams.set("ten", options.tenantId);
2291
+ }
2292
+ if (options.ntpId) {
2293
+ embedUrl.searchParams.set("ntp", options.ntpId);
2294
+ }
2295
+ if (options.ticketCode) {
2296
+ embedUrl.searchParams.set("tk", Buffer.from(options.ticketCode).toString("base64"));
2297
+
2298
+ }
2299
+ if (options.ticketSubject) {
2300
+ embedUrl.searchParams.set("sbj", Buffer.from(options.ticketSubject).toString("base64"));
2301
+ }
2302
+ break;
2282
2303
  }
2283
2304
  }
2284
2305
 
@@ -221,6 +221,12 @@ exports.CreateContentType = async function({name, metadata={}, bitcode}) {
221
221
  commitMessage: "Create content type"
222
222
  });
223
223
 
224
+ const tenantContractId = await this.userProfileClient.TenantContractId();
225
+ if(tenantContractId){
226
+ await this.SetTenantContractId({contractAddress, tenantContractId});
227
+ this.Log(`tenant_contract_id set for ${objectId}`);
228
+ }
229
+
224
230
  return objectId;
225
231
  };
226
232
 
@@ -255,7 +261,7 @@ exports.CreateContentLibrary = async function({
255
261
  imageName,
256
262
  metadata={},
257
263
  kmsId,
258
- tenantId
264
+ tenantContractId
259
265
  }) {
260
266
  if(!kmsId) {
261
267
  kmsId = `ikms${this.utils.AddressToHash(await this.DefaultKMSAddress())}`;
@@ -266,27 +272,6 @@ exports.CreateContentLibrary = async function({
266
272
 
267
273
  const { contractAddress } = await this.authClient.CreateContentLibrary({kmsId});
268
274
 
269
-
270
- // Set tenant ID on the library if the user is associated with a tenant
271
- if(!tenantId) {
272
- tenantId = await this.userProfileClient.TenantId();
273
- }
274
-
275
- if(tenantId) {
276
- if(!this.utils.ValidHash(tenantId)) {
277
- throw Error(`Invalid tenant ID: ${tenantId}`);
278
- }
279
-
280
- await this.CallContractMethod({
281
- contractAddress,
282
- methodName: "putMeta",
283
- methodArgs: [
284
- "_tenantId",
285
- tenantId
286
- ]
287
- });
288
- }
289
-
290
275
  metadata = {
291
276
  ...metadata,
292
277
  name,
@@ -333,6 +318,16 @@ exports.CreateContentLibrary = async function({
333
318
  });
334
319
  }
335
320
 
321
+ // Set tenant contract ID on the library if the user is associated with a tenant
322
+ if(!tenantContractId) {
323
+ tenantContractId = await this.userProfileClient.TenantContractId();
324
+ }
325
+
326
+ if(tenantContractId){
327
+ await this.SetTenantContractId({contractAddress, tenantContractId});
328
+ this.Log(`tenant_contract_id set for ${contractAddress}`);
329
+ }
330
+
336
331
  this.Log(`Library ${libraryId} created`);
337
332
 
338
333
  return libraryId;
@@ -1530,3 +1525,30 @@ exports.SetAuthPolicy = async function({objectId, policyId}) {
1530
1525
  metadata: { "elv:delegation-id": policyId }
1531
1526
  });
1532
1527
  };
1528
+
1529
+ /**
1530
+ * Delete the specified write token
1531
+ *
1532
+ * @methodGroup Content Objects
1533
+ *
1534
+ * @namedParams
1535
+ * @param {string} writeToken - Write token to delete
1536
+ * @param {string} libraryId - ID of the library
1537
+ */
1538
+ exports.DeleteWriteToken = async function({writeToken, libraryId}) {
1539
+ ValidateWriteToken(writeToken);
1540
+ ValidateLibrary(libraryId);
1541
+
1542
+ let path = UrlJoin("qlibs", libraryId, "q", writeToken);
1543
+
1544
+ const authorizationHeader = await this.authClient.AuthorizationHeader({libraryId, update: true});
1545
+
1546
+ await this.HttpClient.Request({
1547
+ headers: authorizationHeader,
1548
+ method: "DELETE",
1549
+ path: path,
1550
+ allowFailover: false
1551
+ });
1552
+
1553
+ await this.HttpClient.ClearWriteToken({writeToken});
1554
+ };
@@ -10,8 +10,10 @@ const Ethers = require("ethers");
10
10
  const {
11
11
  ValidateAddress,
12
12
  ValidateParameters,
13
- ValidatePresence
13
+ ValidatePresence,
14
+ ValidateObject, ValidateVersion
14
15
  } = require("../Validation");
16
+ const Utils=require("../Utils");
15
17
 
16
18
  /**
17
19
  * Return the name of the contract, as specified in the contracts "version" string
@@ -323,12 +325,16 @@ exports.ReplaceContractMetadata = async function({contractAddress, metadataKey,
323
325
  ValidatePresence("contractAddress", contractAddress);
324
326
  ValidatePresence("metadataKey", metadataKey);
325
327
 
328
+ if(typeof metadata === "object") {
329
+ metadata = JSON.stringify(metadata);
330
+ }
331
+
326
332
  await this.CallContractMethodAndWait({
327
333
  contractAddress,
328
334
  methodName: "putMeta",
329
335
  methodArgs: [
330
336
  metadataKey,
331
- JSON.stringify(metadata)
337
+ metadata
332
338
  ]
333
339
  });
334
340
  };
@@ -572,3 +578,152 @@ exports.SendFunds = async function({recipient, ether}) {
572
578
 
573
579
  return await transaction.wait();
574
580
  };
581
+
582
+ /**
583
+ * Retrieve the ID of the tenant contract for the specified object
584
+ *
585
+ * @methodGroup Tenant
586
+ * @namedParams
587
+ * @param {string=} contractAddress - The address of the object
588
+ * @param {string=} objectId - The ID of the object
589
+ * @param {string=} versionHash - A version hash of the object
590
+ *
591
+ * @returns {Promise<string|undefined>}
592
+ */
593
+ exports.TenantContractId = async function({contractAddress, objectId, versionHash}) {
594
+
595
+ if(contractAddress){
596
+ ValidateAddress(contractAddress);
597
+ objectId = Utils.AddressToObjectId(contractAddress);
598
+ } else if(versionHash){
599
+ ValidateVersion(versionHash);
600
+ objectId = this.utils.DecodeVersionHash(versionHash).objectId;
601
+ contractAddress = Utils.HashToAddress(objectId);
602
+ } else if(objectId){
603
+ ValidateObject(objectId);
604
+ contractAddress=Utils.HashToAddress(objectId);
605
+ } else {
606
+ throw Error("contractAddress or objectId or versionHash not specified");
607
+ }
608
+
609
+ const hasGetMetaMethod = await this.authClient.ContractHasMethod({
610
+ contractAddress: contractAddress,
611
+ methodName: "getMeta"
612
+ });
613
+
614
+ if(hasGetMetaMethod) {
615
+ const tenantContractId = await this.ContractMetadata({
616
+ contractAddress:contractAddress,
617
+ metadataKey:"_ELV_TENANT_ID"
618
+ });
619
+ if(tenantContractId !== "") {
620
+ return tenantContractId;
621
+ }
622
+ }
623
+
624
+ const libraryId = await this.ContentObjectLibraryId({ objectId });
625
+
626
+ return await this.ContentObjectMetadata({
627
+ libraryId,
628
+ objectId,
629
+ metadataSubtree: "tenantContractId",
630
+ });
631
+ };
632
+
633
+ /**
634
+ * Set the tenant contract ID for the specified object
635
+ *
636
+ * @methodGroup Tenant
637
+ * @namedParams
638
+ * @param {string=} contractAddress - The address of the object
639
+ * @param {string=} objectId - The ID of the object
640
+ * @param {string=} versionHash - A version hash of the object
641
+ * @param {string} tenantContractId - The tenant contract ID to set
642
+ *
643
+ * @returns {Promise<{tenantId: (undefined|string), tenantContractId}>}
644
+ */
645
+ exports.SetTenantContractId = async function({contractAddress, objectId, versionHash, tenantContractId}) {
646
+
647
+ if(contractAddress){
648
+ ValidateAddress(contractAddress);
649
+ objectId = Utils.AddressToObjectId(contractAddress);
650
+ } else if(versionHash){
651
+ ValidateVersion(versionHash);
652
+ objectId = this.utils.DecodeVersionHash(versionHash).objectId;
653
+ contractAddress = Utils.HashToAddress(objectId);
654
+ } else if(objectId){
655
+ ValidateObject(objectId);
656
+ contractAddress=Utils.HashToAddress(objectId);
657
+ } else {
658
+ throw Error("contractAddress or objectId or versionHash not specified");
659
+ }
660
+ ValidateObject(tenantContractId);
661
+
662
+ if(tenantContractId && (!tenantContractId.startsWith("iten") || !Utils.ValidHash(tenantContractId))) {
663
+ throw Error(`Invalid tenant ID: ${tenantContractId}`);
664
+ }
665
+ const tenantAddress = Utils.HashToAddress(tenantContractId);
666
+
667
+ const version = await this.authClient.AccessType(tenantContractId);
668
+ if(version !== this.authClient.ACCESS_TYPES.TENANT) {
669
+ throw Error("Invalid tenant ID: " + tenantContractId);
670
+ }
671
+
672
+ // get tenant admin group
673
+ const tenantAdminGroupAddress = await this.CallContractMethod({
674
+ contractAddress: tenantAddress,
675
+ methodName: "groupsMapping",
676
+ methodArgs: ["tenant_admin", 0],
677
+ formatArguments: true,
678
+ });
679
+
680
+ const hasPutMetaMethod = await this.authClient.ContractHasMethod({
681
+ contractAddress: contractAddress,
682
+ methodName: "putMeta"
683
+ });
684
+
685
+ if(hasPutMetaMethod) {
686
+
687
+ await this.ReplaceContractMetadata({
688
+ contractAddress: contractAddress,
689
+ metadataKey: "_ELV_TENANT_ID",
690
+ metadata: tenantContractId
691
+ });
692
+
693
+ if(tenantAdminGroupAddress){
694
+ await this.ReplaceContractMetadata({
695
+ contractAddress: contractAddress,
696
+ metadataKey: "_tenantId",
697
+ metadata: `iten${Utils.AddressToHash(tenantAdminGroupAddress)}`
698
+ });
699
+ } else {
700
+ // eslint-disable-next-line no-console
701
+ console.warn("No tenant ID associated with current tenant.");
702
+ }
703
+ } else {
704
+ const libraryId = await this.ContentObjectLibraryId({ objectId });
705
+ const editRequest = await this.EditContentObject({libraryId, objectId});
706
+
707
+ await this.MergeMetadata({
708
+ libraryId,
709
+ objectId,
710
+ writeToken: editRequest.write_token,
711
+ metadata: {
712
+ tenantContractId,
713
+ tenantId: !tenantAdminGroupAddress ? undefined : `iten${Utils.AddressToHash(tenantAdminGroupAddress)}`
714
+ },
715
+ });
716
+
717
+ await this.FinalizeContentObject({
718
+ libraryId,
719
+ objectId,
720
+ writeToken: editRequest.write_token,
721
+ commitMessage: "set tenant_contract_id"
722
+ });
723
+ }
724
+
725
+ return {
726
+ tenantContractId: tenantContractId,
727
+ tenantId: !tenantAdminGroupAddress ? undefined : `iten${Utils.AddressToHash(tenantAdminGroupAddress)}`
728
+ };
729
+ };