@eluvio/elv-client-js 4.0.128 → 4.0.130

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.128",
3
+ "version": "4.0.130",
4
4
  "description": "Javascript client for the Eluvio Content Fabric",
5
5
  "main": "src/index.js",
6
6
  "author": "Kevin Talmadge",
package/src/ElvClient.js CHANGED
@@ -953,6 +953,8 @@ class ElvClient {
953
953
  * @param {boolean} allowDecryption=false - If specified, the re-encryption key will be included in the token,
954
954
  * enabling the user of this token to download encrypted content from the specified object
955
955
  * @param {Object=} context - Additional JSON context
956
+ * @param {number=} issueTime - Issue Time in milliseconds
957
+ * @param {number=} expirationTime - Expiration Time in milliseconds
956
958
  */
957
959
  async CreateSignedToken({
958
960
  libraryId,
@@ -963,7 +965,9 @@ class ElvClient {
963
965
  grantType="read",
964
966
  allowDecryption=false,
965
967
  duration,
966
- context={}
968
+ context={},
969
+ issueTime,
970
+ expirationTime
967
971
  }) {
968
972
  if(!subject) {
969
973
  subject = `iusr${this.utils.AddressToHash(await this.CurrentAccountAddress())}`;
@@ -973,12 +977,14 @@ class ElvClient {
973
977
  context["elv:delegation-id"] = policyId;
974
978
  }
975
979
 
980
+ const issueDateTime = issueTime || Date.now();
981
+
976
982
  let token = {
977
983
  adr: Buffer.from(await this.CurrentAccountAddress().replace(/^0x/, ""), "hex").toString("base64"),
978
984
  sub: subject,
979
985
  spc: await this.ContentSpaceId(),
980
- iat: Date.now(),
981
- exp: Date.now() + duration,
986
+ iat: issueDateTime,
987
+ exp: expirationTime || (issueDateTime + duration),
982
988
  gra: grantType,
983
989
  ctx: context
984
990
  };
package/src/HttpClient.js CHANGED
@@ -114,10 +114,10 @@ class HttpClient {
114
114
  } catch(error) {
115
115
  response = {
116
116
  ok: false,
117
- status: 500,
117
+ status: (error && error.status) || 500,
118
118
  statusText: "ElvClient Error: " + error.message,
119
119
  url: uri.toString(),
120
- stack: error.stack
120
+ error
121
121
  };
122
122
  }
123
123
 
@@ -167,7 +167,8 @@ class HttpClient {
167
167
  message: response.statusText,
168
168
  url: uri.toString(),
169
169
  body: errorBody,
170
- requestParams: fetchParameters
170
+ requestParams: fetchParameters,
171
+ response
171
172
  };
172
173
 
173
174
  if(this.debug) this.Log(
@@ -934,8 +934,8 @@ exports.ContentObjectMetadata = async function({
934
934
  // For a 404 error, check if error was due to write token not found
935
935
  const errQwtoken = objectPath.get(error.body, "errors.0.cause.cause.cause.qwtoken");
936
936
  if(errQwtoken) {
937
- // if so, re-throw rather than suppress error
938
- throw error;
937
+ // if so, throw more specific/informative error rather than the generic 'Not found' error
938
+ throw new Error(`Write token ${errQwtoken} not found`);
939
939
  } else {
940
940
  // For all other 404 errors (not just 'subtree not found'), suppress error and
941
941
  // return an empty value. (there are function call chains that depend on this behavior,
@@ -251,11 +251,11 @@ exports.CreateContentType = async function({name, metadata={}, bitcode}) {
251
251
  * @param {string} name - Library name
252
252
  * @param {string=} description - Library description
253
253
  * @param {blob=} image - Image associated with the library
254
- * @param {string=} - imageName - Name of the image associated with the library (required if image specified)
254
+ * @param {string=} imageName - Name of the image associated with the library (required if image specified)
255
255
  * @param {Object=} metadata - Metadata of library object
256
256
  * @param {string=} kmsId - ID of the KMS to use for content in this library. If not specified,
257
257
  * the default KMS will be used.
258
- * @param {string=} tenantId - ID of the tenant to use for this library
258
+ * @param {string=} tenantContractId - ID of the tenant to use for this library
259
259
  *
260
260
  * @returns {Promise<string>} - Library ID of created library
261
261
  */
@@ -420,26 +420,25 @@ exports.SetContentObjectImage = async function({libraryId, objectId, writeToken,
420
420
  * @param {string} libraryId - ID of the library to delete
421
421
  */
422
422
  exports.DeleteContentLibrary = async function({libraryId}) {
423
- throw Error("Not supported");
424
-
425
- // eslint-disable-next-line no-unreachable
426
- ValidateLibrary(libraryId);
427
-
428
- let path = UrlJoin("qlibs", libraryId);
429
-
430
- const authorizationHeader = await this.authClient.AuthorizationHeader({libraryId, update: true});
431
-
432
- await this.CallContractMethodAndWait({
433
- contractAddress: this.utils.HashToAddress(libraryId),
434
- methodName: "kill",
435
- methodArgs: []
436
- });
437
-
438
- await this.HttpClient.Request({
439
- headers: authorizationHeader,
440
- method: "DELETE",
441
- path: path
442
- });
423
+ throw Error(`Delete library not supported. (${libraryId})`);
424
+
425
+ // ValidateLibrary(libraryId);
426
+ //
427
+ // let path = UrlJoin("qlibs", libraryId);
428
+ //
429
+ // const authorizationHeader = await this.authClient.AuthorizationHeader({libraryId, update: true});
430
+ //
431
+ // await this.CallContractMethodAndWait({
432
+ // contractAddress: this.utils.HashToAddress(libraryId),
433
+ // methodName: "kill",
434
+ // methodArgs: []
435
+ // });
436
+ //
437
+ // await this.HttpClient.Request({
438
+ // headers: authorizationHeader,
439
+ // method: "DELETE",
440
+ // path: path
441
+ // });
443
442
  };
444
443
 
445
444
  /* Library Content Type Management */
@@ -542,7 +541,11 @@ exports.RemoveLibraryContentType = async function({libraryId, typeId, typeName,
542
541
  *
543
542
  * meta: Metadata to use for the new object
544
543
  *
545
- * @returns {Promise<Object>} - Response containing the object ID and write token of the draft
544
+ * noEncryptionConk: Set to true to prevent creation of an encryption conk for the object
545
+ *
546
+ * createKMSConk: Set to true to create a KMS conk for object (usually for sharing a playable object) (incompatible with noEncryptionConk: true)
547
+ *
548
+ * @returns {Promise<Object>} - Response containing the object ID and write token of the draft, as well as the url of the node that created the write token.
546
549
  */
547
550
  exports.CreateContentObject = async function({libraryId, objectId, options={}}) {
548
551
  ValidateLibrary(libraryId);
@@ -550,6 +553,8 @@ exports.CreateContentObject = async function({libraryId, objectId, options={}})
550
553
 
551
554
  this.Log(`Creating content object: ${libraryId} ${objectId || ""}`);
552
555
 
556
+ if(options.noEncryptionConk && options.createKMSConk) throw new Error("Incompatible options: noEncryptionConk and createKMSConk both set to true");
557
+
553
558
  // Look up content type, if specified
554
559
  let typeId;
555
560
  if(options.type) {
@@ -605,10 +610,15 @@ exports.CreateContentObject = async function({libraryId, objectId, options={}})
605
610
  headers: await this.authClient.AuthorizationHeader({libraryId, objectId, update: true}),
606
611
  method: "POST",
607
612
  path: path,
608
- body: options
613
+ body: { // filter out options not recognized by server (noEncryptionConk, createKMSConk)
614
+ type: options.type,
615
+ meta: options.meta
616
+ }
609
617
  });
618
+
610
619
  // extract the url for the node that handled the request
611
- // TODO: remove/simplify after we start using /nodes API call to get node URLs for write tokens
620
+ // (not strictly needed now that we can quickly look up node URL for a write token,
621
+ // but still convenient)
612
622
  const nodeUrl = (new URL(rawCreateResponse.url)).origin;
613
623
  const createResponse = await this.utils.ResponseToJson(
614
624
  rawCreateResponse,
@@ -616,6 +626,16 @@ exports.CreateContentObject = async function({libraryId, objectId, options={}})
616
626
  this.HttpClient.Log.bind(this.HttpClient)
617
627
  );
618
628
 
629
+ // create EncryptionConk and possibly KMSConk depending on options
630
+ if(!options.noEncryptionConk) await this.CreateEncryptionConk(
631
+ {
632
+ libraryId,
633
+ objectId,
634
+ writeToken: createResponse.write_token,
635
+ createKMSConk: options.createKMSConk
636
+ }
637
+ );
638
+
619
639
  // Record the node used in creating this write token
620
640
  this.RecordWriteToken({writeToken: createResponse.write_token, fabricNodeUrl: nodeUrl});
621
641
 
@@ -1449,14 +1469,14 @@ exports.CreateLinks = async function({
1449
1469
  10,
1450
1470
  links,
1451
1471
  async info => {
1452
- const path = info.path.replace(/^(\/|\.)+/, "");
1472
+ const path = info.path.replace(/^([/.])+/, "");
1453
1473
 
1454
1474
  let type = (info.type || "file") === "file" ? "files" : info.type;
1455
1475
  if(type === "metadata") { type = "meta"; }
1456
1476
 
1457
1477
  let target;
1458
1478
  let authTarget;
1459
- target = authTarget = info.target.replace(/^(\/|\.)+/, "");
1479
+ target = authTarget = info.target.replace(/^([/.])+/, "");
1460
1480
  if(info.targetHash) {
1461
1481
  target = `/qfab/${info.targetHash}/${type}/${target}`;
1462
1482
  } else {
@@ -443,6 +443,10 @@ class LiveConf {
443
443
  conf.live_recording.recording_config.recording_params.part_ttl = customSettings.part_ttl;
444
444
  }
445
445
 
446
+ if(Object.hasOwn(customSettings, "persistent")) {
447
+ conf.live_recording.recording_config.recording_params.persistent = customSettings.persistent;
448
+ }
449
+
446
450
  if(customSettings.connection_timeout) {
447
451
  conf.live_recording.recording_config.recording_params.xc_params.connection_timeout = customSettings.connection_timeout;
448
452
  }
@@ -451,6 +455,10 @@ class LiveConf {
451
455
  conf.live_recording.recording_config.recording_params.reconnect_timeout = customSettings.reconnect_timeout;
452
456
  }
453
457
 
458
+ if(Object.hasOwn(customSettings, "copy_mpegts")) {
459
+ conf.live_recording.recording_config.recording_params.xc_params.copy_mpegts = customSettings.copy_mpegts;
460
+ }
461
+
454
462
  // Fill in specifics for protocol
455
463
  switch(this.probeKind()) {
456
464
  case "udp":