@eluvio/elv-client-js 4.0.79 → 4.0.81

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.
@@ -1739,6 +1739,21 @@ var ElvWalletClient = /*#__PURE__*/function () {
1739
1739
  if (op === "nft-offer-redeem") {
1740
1740
  offerId = status.op.split(":")[3];
1741
1741
  }
1742
+ if (op === "nft-claim-entitlement") {
1743
+ var _status$op$split3 = status.op.split(":"),
1744
+ _status$op$split4 = _slicedToArray(_status$op$split3, 4),
1745
+ _op = _status$op$split4[0],
1746
+ marketplace = _status$op$split4[1],
1747
+ sku = _status$op$split4[2],
1748
+ purchaseId = _status$op$split4[3];
1749
+ confirmationId = purchaseId;
1750
+ if (status.extra && status.extra["0"]) {
1751
+ address = status.extra["0"].token_addr;
1752
+ tokenId = status.extra["0"].token_id;
1753
+ address = address.startsWith("0x") ? Utils.FormatAddress(address) : address;
1754
+ status.marketplaceId = marketplace;
1755
+ }
1756
+ }
1742
1757
  return _objectSpread(_objectSpread({}, status), {}, {
1743
1758
  timestamp: new Date(status.ts),
1744
1759
  state: status.state && _typeof(status.state) === "object" ? Object.values(status.state) : status.state,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-client-js",
3
- "version": "4.0.79",
3
+ "version": "4.0.81",
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
@@ -975,6 +975,71 @@ class ElvClient {
975
975
  ]))}`;
976
976
  }
977
977
 
978
+
979
+ /**
980
+ * Build a signed message (JSON) using the current signer.
981
+ * Signed messages have a similar format to signed access tokens and they include the message itself
982
+ * such that they can be both verified and decoded by the receiving entity.
983
+ *
984
+ * Messages can be encoded and signed using different methods, and the encoding and signature types
985
+ * are described in the header of the resulting signed message blob.
986
+ *
987
+ * Note this type of message can not be verified and decoded on chain.
988
+ *
989
+ * @methodGroup Authorization
990
+ * @namedParams
991
+ * @param {string} messasge - A JSON object representing the message to sign
992
+ */
993
+ async CreateSignedMessageJSON({
994
+ message
995
+ }) {
996
+
997
+ // Only one kind of signature supported currently
998
+ const type = "mje_" // JSON message, EIP192 signature
999
+
1000
+ const msg = JSON.stringify(message);
1001
+ const signature = await this.PersonalSign({message: msg, addEthereumPrefix: true});
1002
+ return `${type}${Utils.B58(
1003
+ Buffer.concat([
1004
+ Buffer.from(signature.replace(/^0x/, ""), "hex"),
1005
+ Buffer.from(msg)
1006
+ ])
1007
+ )}`;
1008
+ }
1009
+
1010
+ /**
1011
+ * Verify and decode a signed message (JSON).
1012
+ *
1013
+ * @methodGroup Authorization
1014
+ * @namedParams
1015
+ * @param {string} signedMessage - a signed message as created by CreateSignedMessageJSON
1016
+ * @returns {Promise<Object>} - The decoded message, signer address, signature and signature type
1017
+ */
1018
+ async DecodeSignedMessageJSON({
1019
+ signedMessage
1020
+ }) {
1021
+ const type = signedMessage.slice(0,4);
1022
+ switch(type) {
1023
+ case "mje_":
1024
+ const msgBytes = Utils.FromB58(signedMessage.slice(4));
1025
+ const signature = msgBytes.slice(0, 65);
1026
+ const msg = msgBytes.slice(65);
1027
+ const obj = JSON.parse(msg);
1028
+
1029
+ const prefixedMsgHash = Ethers.utils.keccak256(Buffer.from(`\x19Ethereum Signed Message:\n${msg.length}${msg}`, "utf-8"));
1030
+ const signerAddr = Ethers.utils.recoverAddress(prefixedMsgHash, signature);
1031
+
1032
+ return {
1033
+ type: type,
1034
+ message: obj,
1035
+ signerAddress: signerAddr,
1036
+ signature: "0x" + signature.toString("hex")
1037
+ };
1038
+ default:
1039
+ throw new Error(`Bad message type: ${type}`);
1040
+ }
1041
+ }
1042
+
978
1043
  /**
979
1044
  * Get the account address of the current signer
980
1045
  *
@@ -209,6 +209,17 @@ class LiveConf {
209
209
  return seg;
210
210
  }
211
211
 
212
+ /*
213
+ * Calculate output timebase from the encoder (codec) timebase. The videoTimeBase parameter
214
+ * represents the encoder timebase. The format muxer will change it so it is greater than 10000.
215
+ */
216
+ calcOutputTimebase(codecTimebase) {
217
+ let outputTimebase = codecTimebase;
218
+ while (outputTimebase < 10000)
219
+ outputTimebase = outputTimebase * 2;
220
+ return outputTimebase;
221
+ }
222
+
212
223
  calcSegDurationMpegts({sourceTimescale}) {
213
224
  let videoStream = this.getStreamDataForCodecType("video");
214
225
  let frameRate = videoStream.frame_rate;
@@ -270,7 +281,9 @@ class LiveConf {
270
281
 
271
282
  switch(frameRate) {
272
283
  case "24":
273
- seg.video = sourceTimescale * 30;
284
+ seg.videoTimeBase = 1536; // Output timebase: 12288
285
+ seg.videoFrameDurationTs = 512;
286
+ seg.video = this.calcOutputTimebase(seg.videoTimeBase) * 30;
274
287
  seg.keyint = 48;
275
288
  seg.duration = "30";
276
289
  break;
@@ -280,7 +293,9 @@ class LiveConf {
280
293
  seg.duration = "30";
281
294
  break;
282
295
  case "30":
283
- seg.video = sourceTimescale * 30;
296
+ seg.videoTimeBase = 960; // Output timebase: 15360
297
+ seg.videoFrameDurationTs = 512;
298
+ seg.video = this.calcOutputTimebase(seg.videoTimeBase) * 30;
284
299
  seg.keyint = 60;
285
300
  seg.duration = "30";
286
301
  break;
@@ -290,7 +305,9 @@ class LiveConf {
290
305
  seg.duration = "30.03";
291
306
  break;
292
307
  case "48":
293
- seg.video = sourceTimescale * 30;
308
+ seg.videoTimeBase = 1536; // Output timebase: 12288
309
+ seg.videoFrameDurationTs = 256;
310
+ seg.video = this.calcOutputTimebase(seg.videoTimeBase) * 30;
294
311
  seg.keyint = 96;
295
312
  seg.duration = "30";
296
313
  break;
@@ -300,7 +317,9 @@ class LiveConf {
300
317
  seg.duration = "30";
301
318
  break;
302
319
  case "60":
303
- seg.video = sourceTimescale * 30;
320
+ seg.videoTimeBase = 960; // Output timebase: 15360
321
+ seg.videoFrameDurationTs = 256;
322
+ seg.video = this.calcOutputTimebase(seg.videoTimeBase) * 30;
304
323
  seg.keyint = 120;
305
324
  seg.duration = "30";
306
325
  break;
@@ -397,7 +416,9 @@ class LiveConf {
397
416
  // Optional override output timebase and frame duration (ts)
398
417
  if(segDurations.videoTimeBase) {
399
418
  conf.live_recording.recording_config.recording_params.xc_params.video_time_base = segDurations.videoTimeBase;
400
- conf.live_recording.recording_config.recording_params.source_timescale = segDurations.videoTimeBase;
419
+
420
+ // Note 'source_timescale' needs to be set to the output timebase and is used by playout
421
+ conf.live_recording.recording_config.recording_params.source_timescale = this.calcOutputTimebase(segDurations.videoTimeBase);
401
422
  }
402
423
  if(segDurations.videoFrameDurationTs) {
403
424
  conf.live_recording.recording_config.recording_params.xc_params.video_frame_duration_ts = segDurations.videoFrameDurationTs;
@@ -1322,7 +1322,7 @@ exports.StreamConfig = async function({name, customSettings={}}) {
1322
1322
  const hostName = userConfig.url.replace("udp://", "").replace("rtmp://", "").replace("srt://", "").split(":")[0];
1323
1323
  const streamUrl = new URL(userConfig.url);
1324
1324
 
1325
- console.log("Retrieving nodes...");
1325
+ console.log("Retrieving nodes - matching", hostName);
1326
1326
  let nodes = await this.SpaceNodes({matchEndpoint: hostName});
1327
1327
  if(nodes.length < 1) {
1328
1328
  status.error = "No node matching stream URL " + streamUrl.href;
@@ -1371,6 +1371,54 @@ exports.GiftClaimStatus = async function({marketplaceParams, confirmationId, gif
1371
1371
  }
1372
1372
  };
1373
1373
 
1374
+ /**
1375
+ * Return status of the specified entitlement claim
1376
+ *
1377
+ * @methodGroup Status
1378
+ * @namedParams
1379
+ * @param {Object} marketplaceParams - Parameters of the marketplace
1380
+ * @param {string} purchaseId - The purchase ID of the entitlement, for confirmation of status
1381
+ *
1382
+ * @returns {Promise<Object>} - The mint status of the entitlement claim
1383
+ */
1384
+ exports.EntitlementClaimStatus = async function({marketplaceParams, purchaseId}) {
1385
+ try {
1386
+ const marketplaceInfo = await this.MarketplaceInfo({marketplaceParams});
1387
+ const statuses = await this.MintingStatus({tenantId: marketplaceInfo.tenantId});
1388
+
1389
+ const responses = statuses.filter(status => status.op === "nft-claim-entitlement"
1390
+ && (purchaseId && purchaseId == status.confirmationId)) || { status: "none" };
1391
+
1392
+ if(responses.length === 0) {
1393
+ return { status: "none" };
1394
+ } else {
1395
+ if(responses.find(response => response.status === "complete")) {
1396
+ return {
1397
+ status: "complete",
1398
+ op: "nft-claim-entitlement",
1399
+ items: [{
1400
+ token_addr: responses[0].address,
1401
+ token_id: responses[0].tokenId
1402
+ }]
1403
+ };
1404
+ } else if(responses.find(response => response.status === "error")) {
1405
+ return {
1406
+ status: "error",
1407
+ op: "nft-claim-entitlement",
1408
+ };
1409
+ } else {
1410
+ return {
1411
+ status: "pending",
1412
+ op: "nft-claim-entitlement",
1413
+ };
1414
+ }
1415
+ }
1416
+ } catch(error) {
1417
+ this.Log(error, true);
1418
+ return { status: "unknown" };
1419
+ }
1420
+ };
1421
+
1374
1422
  /**
1375
1423
  * Return status of the specified pack opening
1376
1424
  *
@@ -1326,6 +1326,18 @@ class ElvWalletClient {
1326
1326
  offerId = status.op.split(":")[3];
1327
1327
  }
1328
1328
 
1329
+ if(op === "nft-claim-entitlement") {
1330
+ let [op, marketplace, sku, purchaseId ] = status.op.split(":");
1331
+ confirmationId = purchaseId
1332
+ if(status.extra && status.extra["0"]) {
1333
+ address = status.extra["0"].token_addr;
1334
+ tokenId = status.extra["0"].token_id;
1335
+
1336
+ address = address.startsWith("0x") ? Utils.FormatAddress(address) : address;
1337
+ status.marketplaceId = marketplace;
1338
+ }
1339
+ }
1340
+
1329
1341
  return {
1330
1342
  ...status,
1331
1343
  timestamp: new Date(status.ts),
@@ -0,0 +1,51 @@
1
+ const { ElvClient } = require("../src/ElvClient");
2
+
3
+ const yargs = require("yargs");
4
+ const argv = yargs
5
+ .option("msg", {
6
+ description: "message to be signed and decoded",
7
+ type: "string"
8
+ })
9
+ .option("config-url", {
10
+ type: "string",
11
+ description: "URL pointing to the Fabric configuration. i.e. https://main.net955210.contentfabric.io/config"
12
+ })
13
+ .demandOption(
14
+ ["msg"],
15
+ "\nUsage: PRIVATE_KEY=<private-key> node CreateAndDecodeSignedMessage.js --msg <message>\n"
16
+ )
17
+ .strict().argv;
18
+ const ClientConfiguration = (!argv["config-url"]) ? (require("../TestConfiguration.json")) : {"config-url": argv["config-url"]};
19
+
20
+ const CreateAndDecodeSignedMessage = async ({msg}) => {
21
+ try {
22
+ const client = await ElvClient.FromConfigurationUrl({
23
+ configUrl: ClientConfiguration["config-url"],
24
+ });
25
+ const wallet = client.GenerateWallet();
26
+ const signer = wallet.AddAccount({
27
+ privateKey: process.env.PRIVATE_KEY
28
+ });
29
+
30
+ client.SetSigner({signer});
31
+
32
+ const signedMessage = await client.CreateSignedMessageJSON({
33
+ message:msg,
34
+ });
35
+
36
+ const decodedMessage = await client.DecodeSignedMessageJSON({
37
+ signedMessage,
38
+ });
39
+
40
+
41
+ console.log(signedMessage);
42
+ console.log(decodedMessage);
43
+ } catch(error) {
44
+ console.error(error);
45
+ console.error(JSON.stringify(error, null, 2));
46
+ }
47
+
48
+ process.exit(0);
49
+ };
50
+
51
+ CreateAndDecodeSignedMessage({msg: argv.msg});
@@ -11,7 +11,10 @@ const GenerateFabricToken = async () => {
11
11
 
12
12
  client.SetSigner({signer});
13
13
 
14
- console.log(await client.CreateFabricToken({duration: process.env.DURATION}));
14
+ console.log(await client.CreateFabricToken({
15
+ duration: parseInt(process.env.DURATION),
16
+ //context: {email:"xyz@eluv.io"}
17
+ }));
15
18
  } catch(error) {
16
19
  console.error(error);
17
20
  console.error(JSON.stringify(error, null, 2));