@eluvio/elv-client-js 4.2.16 → 4.2.18
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 +3 -2
- package/src/AuthorizationClient.js +1 -6
- package/src/FrameClient.js +23 -2
- package/src/abr_profiles/abr_profile_live_drm.js +0 -10
- package/src/client/ContentAccess.js +54 -64
- package/src/client/LiveConf.js +150 -65
- package/src/client/LiveStream.js +2613 -654
- package/src/client/NTP.js +71 -0
- package/src/live_recording_config_profiles/live_recording_config_default.js +54 -0
- package/src/live_recording_config_profiles/live_stream_profile_full.json +143 -0
- package/testScripts/StreamUpdateLinks.js +95 -0
- package/utilities/LiveOutputs.js +149 -0
- package/utilities/StreamCreate.js +53 -0
- package/utilities/lib/helpers.js +5 -1
- package/utilities/tests/mocks/ElvClient.mock.js +9 -1
- package/utilities/tests/unit/StreamCreate.test.js +39 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eluvio/elv-client-js",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.18",
|
|
4
4
|
"description": "Javascript client for the Eluvio Content Fabric",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "Kevin Talmadge",
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"lodash": "^4.17.19",
|
|
80
80
|
"lodash.isequal": "^4.5.0",
|
|
81
81
|
"mime-types": "^2.1.24",
|
|
82
|
+
"moment": "^2.27.0",
|
|
82
83
|
"multihashes": "^0.4.14",
|
|
83
84
|
"node-fetch": "^2.6.7",
|
|
84
85
|
"object-path": "^0.11.8",
|
|
@@ -112,7 +113,7 @@
|
|
|
112
113
|
"eslint": "^9.32.0",
|
|
113
114
|
"jsdoc": "^4.0.0",
|
|
114
115
|
"jsdom": "^26.1.0",
|
|
115
|
-
"
|
|
116
|
+
"mocha": "^11.7.5",
|
|
116
117
|
"raw-loader": "^0.5.1",
|
|
117
118
|
"shell-quote": "^1.7.2",
|
|
118
119
|
"showdown": "^1.9.1",
|
|
@@ -570,18 +570,13 @@ class AuthorizationClient {
|
|
|
570
570
|
const stateChannelApi = "elv_channelContentRequestContext";
|
|
571
571
|
const additionalParams = [JSON.stringify(audienceData)];
|
|
572
572
|
|
|
573
|
-
|
|
573
|
+
token = await this.MakeKMSCall({
|
|
574
574
|
objectId,
|
|
575
575
|
methodName: stateChannelApi,
|
|
576
576
|
paramTypes: ["address", "address", "uint", "uint"],
|
|
577
577
|
params: [this.client.signer.address, Utils.HashToAddress(objectId), value, Date.now()],
|
|
578
578
|
additionalParams
|
|
579
579
|
});
|
|
580
|
-
|
|
581
|
-
const signature = await this.Sign(Ethers.utils.keccak256(Ethers.utils.toUtf8Bytes(payload)));
|
|
582
|
-
const multiSig = Utils.FormatSignature(signature);
|
|
583
|
-
|
|
584
|
-
token = `${payload}.${Utils.B64(multiSig)}`;
|
|
585
580
|
}
|
|
586
581
|
|
|
587
582
|
if(!this.noCache) {
|
package/src/FrameClient.js
CHANGED
|
@@ -447,6 +447,15 @@ class FrameClient {
|
|
|
447
447
|
"Nodes",
|
|
448
448
|
"NTPInstance",
|
|
449
449
|
"ObjectCleanup",
|
|
450
|
+
"OutputsCreate",
|
|
451
|
+
"OutputsDelete",
|
|
452
|
+
"OutputsList",
|
|
453
|
+
"OutputsListItem",
|
|
454
|
+
"OutputsModify",
|
|
455
|
+
"OutputsModifyBatch",
|
|
456
|
+
"OutputsResolveSrtPullUrls",
|
|
457
|
+
"OutputsState",
|
|
458
|
+
"OutputsStop",
|
|
450
459
|
"Permission",
|
|
451
460
|
"PlayoutOptions",
|
|
452
461
|
"PlayoutPathResolution",
|
|
@@ -472,6 +481,7 @@ class FrameClient {
|
|
|
472
481
|
"RevokeShare",
|
|
473
482
|
"SendFunds",
|
|
474
483
|
"SetAccessCharge",
|
|
484
|
+
"StreamApplyProfile",
|
|
475
485
|
"SetAuth",
|
|
476
486
|
"SetAuthContext",
|
|
477
487
|
"SetAuthPolicy",
|
|
@@ -496,17 +506,28 @@ class FrameClient {
|
|
|
496
506
|
"SpaceNodes",
|
|
497
507
|
"StartABRMezzanineJobs",
|
|
498
508
|
"StreamAddWatermark",
|
|
509
|
+
"StreamApplyProfile",
|
|
510
|
+
"StreamAssignProfile",
|
|
499
511
|
"StreamConfig",
|
|
512
|
+
"StreamConfigProfile",
|
|
513
|
+
"StreamConfigProfiles",
|
|
500
514
|
"StreamCopyToVod",
|
|
501
515
|
"StreamCreate",
|
|
502
516
|
"StreamInitialize",
|
|
503
517
|
"StreamInsertion",
|
|
518
|
+
"StreamLinkToSite",
|
|
504
519
|
"StreamListUrls",
|
|
520
|
+
"StreamRemoveLinkToSite",
|
|
505
521
|
"StreamRemoveWatermark",
|
|
522
|
+
"StreamSaveConfigProfile",
|
|
506
523
|
"StreamSetOfferingAndDRM",
|
|
507
|
-
"
|
|
524
|
+
"StreamSiteSettings",
|
|
525
|
+
"StreamStartRecording",
|
|
508
526
|
"StreamStartOrStopOrReset",
|
|
509
|
-
"
|
|
527
|
+
"StreamStatus",
|
|
528
|
+
"StreamStopRecording",
|
|
529
|
+
"StreamUnassignProfile",
|
|
530
|
+
"StreamUpdateConfig",
|
|
510
531
|
"SuspendNTPInstance",
|
|
511
532
|
"TenantContractId",
|
|
512
533
|
"TenantId",
|
|
@@ -1863,16 +1863,6 @@ const AbrProfileLiveDrm = {
|
|
|
1863
1863
|
}
|
|
1864
1864
|
},
|
|
1865
1865
|
"playout_formats": {
|
|
1866
|
-
"dash-playready-cenc": {
|
|
1867
|
-
"drm": {
|
|
1868
|
-
"enc_scheme_name": "cenc",
|
|
1869
|
-
"type": "DrmPlayReady"
|
|
1870
|
-
},
|
|
1871
|
-
"protocol": {
|
|
1872
|
-
"min_buffer_length": 2,
|
|
1873
|
-
"type": "ProtoDash"
|
|
1874
|
-
}
|
|
1875
|
-
},
|
|
1876
1866
|
"dash-widevine": {
|
|
1877
1867
|
"drm": {
|
|
1878
1868
|
"content_id": "",
|
|
@@ -20,6 +20,8 @@ const {
|
|
|
20
20
|
} = require("../Validation");
|
|
21
21
|
|
|
22
22
|
const MergeWith = require("lodash/mergeWith");
|
|
23
|
+
const LodashSet = require("lodash/set");
|
|
24
|
+
const LodashGet = require("lodash/get");
|
|
23
25
|
|
|
24
26
|
// Note: Keep these ordered by most-restrictive to least-restrictive
|
|
25
27
|
exports.permissionLevels = {
|
|
@@ -583,7 +585,7 @@ exports.ContentObjects = async function({libraryId, filterOptions={}}) {
|
|
|
583
585
|
*
|
|
584
586
|
* @returns {Promise<Object>} - Description of content object
|
|
585
587
|
*/
|
|
586
|
-
exports.ContentObject = async function({objectId, versionHash, writeToken, noCache}) {
|
|
588
|
+
exports.ContentObject = async function({objectId, versionHash, writeToken, noCache, authorizationToken}) {
|
|
587
589
|
this.Log(`Retrieving content object: ${writeToken || versionHash || objectId}`);
|
|
588
590
|
|
|
589
591
|
if(writeToken) {
|
|
@@ -598,7 +600,9 @@ exports.ContentObject = async function({objectId, versionHash, writeToken, noCac
|
|
|
598
600
|
if(noCache || !this.objectInfo[id] || Date.now() - this.objectInfo[id].retrievedAt > 30000) {
|
|
599
601
|
let path = UrlJoin("q", id);
|
|
600
602
|
const info = await this.HttpClient.RequestJsonBody({
|
|
601
|
-
headers:
|
|
603
|
+
headers: {
|
|
604
|
+
Authorization: `Bearer ${authorizationToken || await this.authClient.AuthorizationToken({objectId, versionHash})}`,
|
|
605
|
+
},
|
|
602
606
|
method: "GET",
|
|
603
607
|
path: path,
|
|
604
608
|
queryParams: {
|
|
@@ -626,7 +630,7 @@ exports.ContentObject = async function({objectId, versionHash, writeToken, noCac
|
|
|
626
630
|
*
|
|
627
631
|
* @returns {Promise<string>} - The account address of the owner
|
|
628
632
|
*/
|
|
629
|
-
exports.ContentObjectOwner = async function({objectId, versionHash}) {
|
|
633
|
+
exports.ContentObjectOwner = async function({objectId, versionHash, authorizationToken}) {
|
|
630
634
|
versionHash ? ValidateVersion(versionHash) : ValidateObject(objectId);
|
|
631
635
|
|
|
632
636
|
if(versionHash) {
|
|
@@ -635,7 +639,7 @@ exports.ContentObjectOwner = async function({objectId, versionHash}) {
|
|
|
635
639
|
|
|
636
640
|
this.Log(`Retrieving content object owner: ${objectId}`);
|
|
637
641
|
|
|
638
|
-
return this.utils.HashToAddress((await this.ContentObject({objectId, versionHash})).content_profile.owner);
|
|
642
|
+
return this.utils.HashToAddress((await this.ContentObject({objectId, versionHash, authorizationToken})).content_profile.owner);
|
|
639
643
|
};
|
|
640
644
|
|
|
641
645
|
/**
|
|
@@ -649,7 +653,7 @@ exports.ContentObjectOwner = async function({objectId, versionHash}) {
|
|
|
649
653
|
*
|
|
650
654
|
* @returns {Promise<string>} - Tenant ID of the object
|
|
651
655
|
*/
|
|
652
|
-
exports.ContentObjectTenantId = async function({objectId, versionHash}) {
|
|
656
|
+
exports.ContentObjectTenantId = async function({objectId, versionHash, authorizationToken}) {
|
|
653
657
|
versionHash ? ValidateVersion(versionHash) : ValidateObject(objectId);
|
|
654
658
|
|
|
655
659
|
if(versionHash) {
|
|
@@ -659,7 +663,7 @@ exports.ContentObjectTenantId = async function({objectId, versionHash}) {
|
|
|
659
663
|
// Cache results because they will never change
|
|
660
664
|
if(!this.objectTenantIds[objectId]) {
|
|
661
665
|
try {
|
|
662
|
-
this.objectTenantIds[objectId] = (await this.ContentObject({objectId, versionHash})).content_profile.tenant_id;
|
|
666
|
+
this.objectTenantIds[objectId] = (await this.ContentObject({objectId, versionHash, authorizationToken})).content_profile.tenant_id;
|
|
663
667
|
} catch(error) {
|
|
664
668
|
error.message = `Unable to determine tenant ID for ${versionHash || objectId}`;
|
|
665
669
|
throw error;
|
|
@@ -680,7 +684,7 @@ exports.ContentObjectTenantId = async function({objectId, versionHash}) {
|
|
|
680
684
|
*
|
|
681
685
|
* @returns {Promise<string>} - Library ID of the object
|
|
682
686
|
*/
|
|
683
|
-
exports.ContentObjectLibraryId = async function({objectId, versionHash}) {
|
|
687
|
+
exports.ContentObjectLibraryId = async function({objectId, versionHash, authorizationToken}) {
|
|
684
688
|
versionHash ? ValidateVersion(versionHash) : ValidateObject(objectId);
|
|
685
689
|
|
|
686
690
|
if(versionHash) {
|
|
@@ -690,7 +694,7 @@ exports.ContentObjectLibraryId = async function({objectId, versionHash}) {
|
|
|
690
694
|
// Cache results because they will never change
|
|
691
695
|
if(!this.objectLibraryIds[objectId]) {
|
|
692
696
|
try {
|
|
693
|
-
this.objectLibraryIds[objectId] = (await this.ContentObject({objectId, versionHash})).qlib_id;
|
|
697
|
+
this.objectLibraryIds[objectId] = (await this.ContentObject({objectId, versionHash, authorizationToken})).qlib_id;
|
|
694
698
|
} catch(error) {
|
|
695
699
|
error.message = `Unable to determine library ID for ${versionHash || objectId}`;
|
|
696
700
|
throw error;
|
|
@@ -709,56 +713,43 @@ exports.ProduceMetadataLinks = async function({
|
|
|
709
713
|
authorizationToken,
|
|
710
714
|
noAuth
|
|
711
715
|
}) {
|
|
712
|
-
|
|
713
|
-
if(!metadata || typeof metadata !== "object") { return metadata; }
|
|
716
|
+
path = UrlJoin(path || "").replace(/^\//, "").replace(/\/$/, "");
|
|
714
717
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
return await this.utils.LimitedMap(
|
|
718
|
-
5,
|
|
719
|
-
metadata,
|
|
720
|
-
async (entry, i) => await this.ProduceMetadataLinks({
|
|
721
|
-
libraryId,
|
|
722
|
-
objectId,
|
|
723
|
-
versionHash,
|
|
724
|
-
path: UrlJoin(path, i.toString()),
|
|
725
|
-
metadata: entry,
|
|
726
|
-
authorizationToken,
|
|
727
|
-
noAuth
|
|
728
|
-
})
|
|
729
|
-
);
|
|
730
|
-
}
|
|
718
|
+
const Traverse = async (currentPath="") => {
|
|
719
|
+
const currentMetadata = !currentPath ? metadata : LodashGet(metadata, currentPath.split("/"));
|
|
731
720
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
{
|
|
737
|
-
// Is file or rep link - produce a url
|
|
738
|
-
return {
|
|
739
|
-
...metadata,
|
|
740
|
-
url: await this.LinkUrl({libraryId, objectId, versionHash, linkPath: path, authorizationToken, noAuth})
|
|
741
|
-
};
|
|
742
|
-
}
|
|
721
|
+
// Primitive
|
|
722
|
+
if(!currentMetadata || typeof currentMetadata !== "object") {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
743
725
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
result[key] = await this.ProduceMetadataLinks({
|
|
750
|
-
libraryId,
|
|
751
|
-
objectId,
|
|
752
|
-
versionHash,
|
|
753
|
-
path: UrlJoin(path, key),
|
|
754
|
-
metadata: metadata[key],
|
|
755
|
-
authorizationToken,
|
|
756
|
-
noAuth
|
|
757
|
-
});
|
|
726
|
+
// Array
|
|
727
|
+
if(Array.isArray(currentMetadata)) {
|
|
728
|
+
for(let i = 0; i < currentMetadata.length; i++) {
|
|
729
|
+
await Traverse(UrlJoin(currentPath, i.toString()));
|
|
730
|
+
}
|
|
758
731
|
}
|
|
759
|
-
);
|
|
760
732
|
|
|
761
|
-
|
|
733
|
+
// Object
|
|
734
|
+
if(currentMetadata["/"] &&
|
|
735
|
+
(currentMetadata["/"].match(/\.\/(rep|files)\/.+/) ||
|
|
736
|
+
currentMetadata["/"].match(/^\/?qfab\/([\w]+)\/?(rep|files)\/.+/))) {
|
|
737
|
+
// Is file or rep link - produce a url
|
|
738
|
+
LodashSet(
|
|
739
|
+
metadata,
|
|
740
|
+
UrlJoin(currentPath, "url").split("/"),
|
|
741
|
+
await this.LinkUrl({libraryId, objectId, versionHash, linkPath: UrlJoin(path, currentPath), authorizationToken, noAuth})
|
|
742
|
+
)
|
|
743
|
+
} else {
|
|
744
|
+
for(let key of Object.keys(currentMetadata)) {
|
|
745
|
+
await Traverse(UrlJoin(currentPath, key))
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
Traverse();
|
|
751
|
+
|
|
752
|
+
return metadata;
|
|
762
753
|
};
|
|
763
754
|
|
|
764
755
|
exports.MetadataAuth = async function({
|
|
@@ -1056,7 +1047,7 @@ exports.ContentObjectVersions = async function({libraryId, objectId}) {
|
|
|
1056
1047
|
return this.HttpClient.RequestJsonBody({
|
|
1057
1048
|
headers: await this.authClient.AuthorizationHeader({libraryId, objectId}),
|
|
1058
1049
|
method: "GET",
|
|
1059
|
-
path
|
|
1050
|
+
path
|
|
1060
1051
|
});
|
|
1061
1052
|
};
|
|
1062
1053
|
|
|
@@ -1070,13 +1061,13 @@ exports.ContentObjectVersions = async function({libraryId, objectId}) {
|
|
|
1070
1061
|
*
|
|
1071
1062
|
* @returns {Promise<string>} - The latest version hash of the object
|
|
1072
1063
|
*/
|
|
1073
|
-
exports.LatestVersionHash = async function({objectId, versionHash}) {
|
|
1064
|
+
exports.LatestVersionHash = async function({objectId, versionHash, authorizationToken}) {
|
|
1074
1065
|
if(versionHash) {
|
|
1075
1066
|
objectId = this.utils.DecodeVersionHash(versionHash).objectId;
|
|
1076
1067
|
}
|
|
1077
1068
|
|
|
1078
1069
|
try {
|
|
1079
|
-
return (await this.ContentObject({objectId, noCache: true})).hash;
|
|
1070
|
+
return (await this.ContentObject({objectId, noCache: true, authorizationToken})).hash;
|
|
1080
1071
|
} catch(error) {
|
|
1081
1072
|
error.message = `Unable to determine latest version hash for ${versionHash || objectId}`;
|
|
1082
1073
|
throw error;
|
|
@@ -1175,11 +1166,11 @@ exports.PlayoutPathResolution = async function({
|
|
|
1175
1166
|
authorizationToken
|
|
1176
1167
|
}) {
|
|
1177
1168
|
if(!libraryId) {
|
|
1178
|
-
libraryId = await this.ContentObjectLibraryId({objectId});
|
|
1169
|
+
libraryId = await this.ContentObjectLibraryId({objectId, authorizationToken});
|
|
1179
1170
|
}
|
|
1180
1171
|
|
|
1181
1172
|
if(!versionHash) {
|
|
1182
|
-
versionHash = await this.LatestVersionHash({objectId});
|
|
1173
|
+
versionHash = await this.LatestVersionHash({objectId, authorizationToken});
|
|
1183
1174
|
}
|
|
1184
1175
|
|
|
1185
1176
|
let path = UrlJoin("qlibs", libraryId, "q", writeToken || versionHash, "rep", handler, offering, "options.json");
|
|
@@ -1215,7 +1206,7 @@ exports.PlayoutPathResolution = async function({
|
|
|
1215
1206
|
authorizationToken
|
|
1216
1207
|
});
|
|
1217
1208
|
linkTargetId = this.utils.DecodeVersionHash(linkTargetHash).objectId;
|
|
1218
|
-
linkTargetLibraryId = await this.ContentObjectLibraryId({objectId: linkTargetId});
|
|
1209
|
+
linkTargetLibraryId = await this.ContentObjectLibraryId({objectId: linkTargetId, authorizationToken});
|
|
1219
1210
|
|
|
1220
1211
|
if(!multiOfferingLink && !offering) {
|
|
1221
1212
|
// If the offering is not specified, the intent is to get available offerings. For a single offering link, must
|
|
@@ -1272,7 +1263,7 @@ exports.AvailableOfferings = async function({
|
|
|
1272
1263
|
|
|
1273
1264
|
if(directLink) {
|
|
1274
1265
|
return await this.ContentObjectMetadata({
|
|
1275
|
-
libraryId: await this.ContentObjectLibraryId({objectId}),
|
|
1266
|
+
libraryId: await this.ContentObjectLibraryId({objectId, authorizationToken}),
|
|
1276
1267
|
objectId,
|
|
1277
1268
|
versionHash,
|
|
1278
1269
|
metadataSubtree: linkPath,
|
|
@@ -1383,10 +1374,10 @@ exports.PlayoutOptions = async function({
|
|
|
1383
1374
|
if(!objectId) {
|
|
1384
1375
|
objectId = this.utils.DecodeVersionHash(versionHash).objectId;
|
|
1385
1376
|
} else if(!versionHash) {
|
|
1386
|
-
versionHash = await this.LatestVersionHash({objectId});
|
|
1377
|
+
versionHash = await this.LatestVersionHash({objectId, authorizationToken});
|
|
1387
1378
|
}
|
|
1388
1379
|
|
|
1389
|
-
const libraryId = await this.ContentObjectLibraryId({objectId});
|
|
1380
|
+
const libraryId = await this.ContentObjectLibraryId({objectId, authorizationToken});
|
|
1390
1381
|
|
|
1391
1382
|
try {
|
|
1392
1383
|
// If public/asset_metadata/sources/<offering> exists, use that instead of directly calling on object
|
|
@@ -1804,7 +1795,6 @@ exports.GlobalUrl = async function({
|
|
|
1804
1795
|
}
|
|
1805
1796
|
}
|
|
1806
1797
|
|
|
1807
|
-
console.log("Updated")
|
|
1808
1798
|
let urlPath = UrlJoin("s", network);
|
|
1809
1799
|
if(versionHash) {
|
|
1810
1800
|
objectId = this.utils.DecodeVersionHash(versionHash).objectId;
|
|
@@ -2824,7 +2814,7 @@ exports.EncryptionConk = async function({libraryId, objectId, versionHash, write
|
|
|
2824
2814
|
const owner = await this.authClient.Owner({id: objectId});
|
|
2825
2815
|
|
|
2826
2816
|
const ownerCapKey = `eluv.caps.iusr${this.utils.AddressToHash(this.signer.address)}`;
|
|
2827
|
-
const ownerCap = await this.ContentObjectMetadata({libraryId, objectId, versionHash, metadataSubtree: ownerCapKey});
|
|
2817
|
+
const ownerCap = await this.ContentObjectMetadata({libraryId, objectId, versionHash, writeToken, metadataSubtree: ownerCapKey});
|
|
2828
2818
|
|
|
2829
2819
|
if(!this.utils.EqualAddress(owner, this.signer.address) && !ownerCap) {
|
|
2830
2820
|
if(download) {
|