@eluvio/elv-client-js 4.0.135 → 4.0.136

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.
Files changed (51) hide show
  1. package/dist/ElvClient-min.js +15 -14
  2. package/dist/ElvClient-node-min.js +14 -13
  3. package/dist/ElvFrameClient-min.js +10 -10
  4. package/dist/ElvPermissionsClient-min.js +9 -9
  5. package/dist/ElvWalletClient-min.js +15 -14
  6. package/dist/ElvWalletClient-node-min.js +14 -13
  7. package/dist/src/AuthorizationClient.js +9 -12
  8. package/dist/src/ContentObjectAudit.js +3 -3
  9. package/dist/src/ContentObjectVerification.js +3 -3
  10. package/dist/src/Crypto.js +2 -2
  11. package/dist/src/ElvClient.js +522 -397
  12. package/dist/src/ElvWallet.js +7 -5
  13. package/dist/src/EthClient.js +8 -9
  14. package/dist/src/FrameClient.js +9 -10
  15. package/dist/src/HttpClient.js +5 -5
  16. package/dist/src/Id.js +1 -2
  17. package/dist/src/PermissionsClient.js +31 -19
  18. package/dist/src/RemoteSigner.js +10 -11
  19. package/dist/src/UserProfileClient.js +35 -20
  20. package/dist/src/Utils.js +2 -3
  21. package/dist/src/client/ABRPublishing.js +342 -196
  22. package/dist/src/client/AccessGroups.js +2 -2
  23. package/dist/src/client/ContentAccess.js +8 -12
  24. package/dist/src/client/ContentManagement.js +99 -83
  25. package/dist/src/client/Contracts.js +2 -2
  26. package/dist/src/client/Files.js +2 -2
  27. package/dist/src/client/LiveConf.js +43 -26
  28. package/dist/src/client/LiveStream.js +65 -63
  29. package/dist/src/client/NFT.js +2 -2
  30. package/dist/src/client/Shares.js +47 -24
  31. package/dist/src/walletClient/ClientMethods.js +2 -2
  32. package/dist/src/walletClient/Profile.js +2 -2
  33. package/dist/src/walletClient/Utils.js +2 -2
  34. package/dist/src/walletClient/index.js +65 -50
  35. package/package.json +2 -2
  36. package/src/ElvClient.js +67 -3
  37. package/src/FrameClient.js +2 -1
  38. package/src/client/ABRPublishing.js +215 -83
  39. package/src/client/ContentManagement.js +7 -6
  40. package/src/client/LiveConf.js +13 -9
  41. package/src/client/LiveStream.js +8 -3
  42. package/utilities/FrontEndSimpleIngest.js +198 -0
  43. package/utilities/ProductionMasterCreate.js +9 -2
  44. package/utilities/SampleIngest.js +225 -0
  45. package/utilities/SampleIngestWithMaster.js +226 -0
  46. package/utilities/lib/concerns/ArgLibraryId.js +1 -1
  47. package/utilities/lib/concerns/ArgTenant.js +23 -0
  48. package/utilities/lib/concerns/ContentType.js +1 -1
  49. package/utilities/lib/concerns/Finalize.js +12 -7
  50. package/utilities/lib/concerns/LRO.js +3 -3
  51. package/utilities/lib/concerns/Tenant.js +47 -0
@@ -12,7 +12,8 @@ const UrlJoin = require("url-join");
12
12
  const {
13
13
  ValidateLibrary,
14
14
  ValidateVersion,
15
- ValidateParameters
15
+ ValidateParameters,
16
+ ValidateWriteToken
16
17
  } = require("../Validation");
17
18
 
18
19
  // When `/abr_mezzanine/offerings` contains more than one entry, only 1 is the 'real' offering, the others are
@@ -41,6 +42,7 @@ const MezJobMainOfferingKey = function(abrMezOfferings) {
41
42
  * @param {string} name - Name of the content
42
43
  * @param {string=} description - Description of the content
43
44
  * @param {string} contentTypeName - Name of the content type to use
45
+ * @param {string=} writeToken - Write token of the draft. If specified, the object will not be finalized.
44
46
  * @param {Object=} metadata - Additional metadata for the content object
45
47
  * @param {Array<Object>=} fileInfo - Files to upload (See UploadFiles/UploadFilesFromS3 method)
46
48
  * @param {boolean=} encrypt=true - (Local or copied files only) - Unless `false` is passed in explicitly, any uploaded/copied files will be stored encrypted
@@ -83,6 +85,7 @@ const MezJobMainOfferingKey = function(abrMezOfferings) {
83
85
  exports.CreateProductionMaster = async function({
84
86
  libraryId,
85
87
  type,
88
+ writeToken,
86
89
  name,
87
90
  description,
88
91
  metadata={},
@@ -95,11 +98,17 @@ exports.CreateProductionMaster = async function({
95
98
  structLogLevel="none"
96
99
  }) {
97
100
  ValidateLibrary(libraryId);
101
+ let id;
102
+ const finalize = !writeToken;
98
103
 
99
- const {id, write_token} = await this.CreateContentObject({
100
- libraryId,
101
- options: type ? { type } : {}
102
- });
104
+ if(writeToken) {
105
+ id = this.utils.DecodeWriteToken(writeToken).objectId;
106
+ } else {
107
+ ({id, writeToken} = await this.CreateContentObject({
108
+ libraryId,
109
+ options: type ? { type } : {}
110
+ }));
111
+ }
103
112
 
104
113
  // any files specified?
105
114
  if(fileInfo) {
@@ -158,7 +167,7 @@ exports.CreateProductionMaster = async function({
158
167
  await this.UploadFilesFromS3({
159
168
  libraryId,
160
169
  objectId: id,
161
- writeToken: write_token,
170
+ writeToken,
162
171
  fileInfo: credentialSet.matched,
163
172
  region,
164
173
  bucket,
@@ -175,7 +184,7 @@ exports.CreateProductionMaster = async function({
175
184
  await this.UploadFiles({
176
185
  libraryId,
177
186
  objectId: id,
178
- writeToken: write_token,
187
+ writeToken,
179
188
  fileInfo,
180
189
  callback,
181
190
  encryption: encrypt ? "cgck" : "none"
@@ -183,12 +192,12 @@ exports.CreateProductionMaster = async function({
183
192
  }
184
193
  }
185
194
 
186
- await this.CreateEncryptionConk({libraryId, objectId: id, writeToken: write_token, createKMSConk: true});
195
+ await this.CreateEncryptionConk({libraryId, objectId: id, writeToken, createKMSConk: true});
187
196
 
188
197
  const { logs, errors, warnings } = await this.CallBitcodeMethod({
189
198
  libraryId,
190
199
  objectId: id,
191
- writeToken: write_token,
200
+ writeToken,
192
201
  method: UrlJoin("media", "production_master", "init"),
193
202
  queryParams: {
194
203
  response_log_level: respLogLevel,
@@ -203,7 +212,7 @@ exports.CreateProductionMaster = async function({
203
212
  await this.MergeMetadata({
204
213
  libraryId,
205
214
  objectId: id,
206
- writeToken: write_token,
215
+ writeToken,
207
216
  metadata: {
208
217
  ...(metadata || {}),
209
218
  name,
@@ -218,13 +227,24 @@ exports.CreateProductionMaster = async function({
218
227
  }
219
228
  });
220
229
 
221
- const finalizeResponse = await this.FinalizeContentObject({
222
- libraryId,
223
- objectId: id,
224
- writeToken: write_token,
225
- commitMessage: "Create master",
226
- awaitCommitConfirmation: false
227
- });
230
+ let finalizeResponse;
231
+
232
+ if(finalize) {
233
+ finalizeResponse = await this.FinalizeContentObject({
234
+ libraryId,
235
+ objectId: id,
236
+ writeToken,
237
+ commitMessage: "Create master",
238
+ awaitCommitConfirmation: false
239
+ });
240
+ } else {
241
+ finalizeResponse = {
242
+ write_token: writeToken,
243
+ type,
244
+ qlib_id: libraryId,
245
+ id
246
+ };
247
+ }
228
248
 
229
249
  return {
230
250
  errors: errors || [],
@@ -235,7 +255,7 @@ exports.CreateProductionMaster = async function({
235
255
  };
236
256
 
237
257
  /**
238
- * Create (or edit) a mezzanine offering based on the a given master content object version and variant key
258
+ * Create (or edit) a mezzanine offering based on a given master content object version and variant key
239
259
  *
240
260
  * @methodGroup ABR Publishing
241
261
  * @namedParams
@@ -245,6 +265,8 @@ exports.CreateProductionMaster = async function({
245
265
  * @param {boolean=} keepOtherStreams=false - If objectId is specified, whether to preserve existing streams with keys other than the ones specified in production master
246
266
  * @param {string} libraryId - ID of the mezzanine library
247
267
  * @param {string} masterVersionHash - The version hash of the production master content object
268
+ * @param {string=} masterWriteToken - The write token of the production master content object draft. If provided, the object will not be finalized
269
+ * @param {string=} writeToken - The write token of the mezzanine object draft. If specified, the object will not be finalized
248
270
  * @param {Object=} metadata - Additional metadata for mezzanine content object
249
271
  * @param {string} name - Name for mezzanine content object
250
272
  * @param {string=} objectId - ID of existing object (if not specified, new object will be created)
@@ -265,6 +287,8 @@ exports.CreateABRMezzanine = async function({
265
287
  description,
266
288
  metadata,
267
289
  masterVersionHash,
290
+ masterWriteToken,
291
+ writeToken,
268
292
  abrProfile,
269
293
  addlOfferingSpecs,
270
294
  variant="default",
@@ -275,10 +299,26 @@ exports.CreateABRMezzanine = async function({
275
299
  streamKeys
276
300
  }) {
277
301
  ValidateLibrary(libraryId);
278
- ValidateVersion(masterVersionHash);
279
302
 
280
- if(!masterVersionHash) {
281
- throw Error("Master version hash not specified");
303
+ let masterObjectId;
304
+ if(masterVersionHash) {
305
+ ValidateVersion(masterVersionHash);
306
+ } else if(masterWriteToken) {
307
+ ValidateWriteToken(masterWriteToken);
308
+
309
+ masterObjectId = this.utils.DecodeWriteToken(masterWriteToken).objectId;
310
+ }
311
+
312
+ if(writeToken) {
313
+ ValidateWriteToken(writeToken);
314
+
315
+ if(!objectId) {
316
+ objectId = this.utils.DecodeWriteToken(writeToken).objectId;
317
+ }
318
+ }
319
+
320
+ if(!masterVersionHash && !masterWriteToken) {
321
+ throw Error("Master version hash and master write token not specified. One must be provided");
282
322
  }
283
323
 
284
324
  if(!objectId && (keepOtherStreams)) {
@@ -293,17 +333,20 @@ exports.CreateABRMezzanine = async function({
293
333
 
294
334
  let options = type ? { type } : {};
295
335
 
296
- let id, write_token;
336
+ let id;
337
+ const finalize = !writeToken;
338
+
297
339
  if(existingMez) {
298
340
  // Edit existing
299
- const editResponse = await this.EditContentObject({
300
- libraryId,
301
- objectId,
302
- options
303
- });
304
-
305
- id = editResponse.id;
306
- write_token = editResponse.write_token;
341
+ if(writeToken) {
342
+ id = objectId;
343
+ } else {
344
+ ({writeToken, id} = await this.EditContentObject({
345
+ libraryId,
346
+ objectId,
347
+ options
348
+ }));
349
+ }
307
350
  } else {
308
351
  // Create new
309
352
  const createResponse = await this.CreateContentObject({
@@ -312,13 +355,27 @@ exports.CreateABRMezzanine = async function({
312
355
  });
313
356
 
314
357
  id = createResponse.id;
315
- write_token = createResponse.write_token;
358
+ writeToken = createResponse.write_token;
316
359
  }
317
360
 
318
- await this.CreateEncryptionConk({libraryId, objectId: id, writeToken: write_token, createKMSConk: true});
361
+ await this.CreateEncryptionConk({libraryId, objectId: id, writeToken, createKMSConk: true});
362
+
363
+
364
+ let nameMetaPayload;
365
+ if(masterWriteToken) {
366
+ nameMetaPayload = {
367
+ libraryId,
368
+ objectId: masterObjectId,
369
+ writeToken: masterWriteToken
370
+ };
371
+ } else if(masterVersionHash) {
372
+ nameMetaPayload = {
373
+ versionHash: masterVersionHash
374
+ };
375
+ }
319
376
 
320
377
  const masterName = await this.ContentObjectMetadata({
321
- versionHash: masterVersionHash,
378
+ ...nameMetaPayload,
322
379
  metadataSubtree: "public/name"
323
380
  });
324
381
 
@@ -326,7 +383,7 @@ exports.CreateABRMezzanine = async function({
326
383
  let authorizationTokens = [];
327
384
  authorizationTokens.push(await this.authClient.AuthorizationToken({libraryId, objectId: id, update: true}));
328
385
  authorizationTokens.push(await this.authClient.AuthorizationToken({libraryId}));
329
- authorizationTokens.push(await this.authClient.AuthorizationToken({versionHash: masterVersionHash}));
386
+ authorizationTokens.push(await this.authClient.AuthorizationToken({versionHash: masterVersionHash, objectId: masterObjectId}));
330
387
 
331
388
  const headers = {
332
389
  Authorization: authorizationTokens.map(token => `Bearer ${token}`).join(",")
@@ -336,7 +393,7 @@ exports.CreateABRMezzanine = async function({
336
393
  additional_offering_specs: addlOfferingSpecs,
337
394
  offering_key: offeringKey,
338
395
  keep_other_streams: keepOtherStreams,
339
- prod_master_hash: masterVersionHash,
396
+ prod_master_hash: masterWriteToken || masterVersionHash,
340
397
  stream_keys: streamKeys,
341
398
  variant_key: variant
342
399
  };
@@ -359,14 +416,14 @@ exports.CreateABRMezzanine = async function({
359
416
  await this.EncryptionConk({
360
417
  libraryId,
361
418
  objectId: id,
362
- writeToken: write_token
419
+ writeToken
363
420
  });
364
421
  }
365
422
 
366
423
  const {logs, errors, warnings} = await this.CallBitcodeMethod({
367
424
  libraryId,
368
425
  objectId: id,
369
- writeToken: write_token,
426
+ writeToken,
370
427
  method: UrlJoin("media", "abr_mezzanine", "init"),
371
428
  queryParams: {
372
429
  response_log_level: respLogLevel,
@@ -381,9 +438,16 @@ exports.CreateABRMezzanine = async function({
381
438
  if(!metadata.public) { metadata.public = {}; }
382
439
  if(!metadata.public.asset_metadata) { metadata.public.asset_metadata = {}; }
383
440
 
441
+ let masterId;
442
+ if(masterWriteToken) {
443
+ masterId = this.utils.DecodeWriteToken(masterWriteToken).objectId;
444
+ } else if(masterVersionHash) {
445
+ masterId = this.utils.DecodeVersionHash(masterVersionHash).objectId;
446
+ }
447
+
384
448
  metadata.master = {
385
449
  name: masterName,
386
- id: this.utils.DecodeVersionHash(masterVersionHash).objectId,
450
+ id: masterId,
387
451
  hash: masterVersionHash,
388
452
  variant
389
453
  };
@@ -415,7 +479,7 @@ exports.CreateABRMezzanine = async function({
415
479
  const existingMetadata = await this.ContentObjectMetadata({
416
480
  libraryId,
417
481
  objectId: id,
418
- writeToken: write_token,
482
+ writeToken,
419
483
  });
420
484
  // newer metadata values replace existing metadata, unless both new and old values are objects,
421
485
  // in which case their keys are merged recursively
@@ -430,16 +494,26 @@ exports.CreateABRMezzanine = async function({
430
494
  await this.ReplaceMetadata({
431
495
  libraryId,
432
496
  objectId: id,
433
- writeToken: write_token,
497
+ writeToken,
434
498
  metadata
435
499
  });
436
500
 
437
- const finalizeResponse = await this.FinalizeContentObject({
438
- libraryId,
439
- objectId: id,
440
- writeToken: write_token,
441
- commitMessage: "Create ABR mezzanine"
442
- });
501
+ let finalizeResponse;
502
+ if(finalize) {
503
+ finalizeResponse = await this.FinalizeContentObject({
504
+ libraryId,
505
+ objectId: id,
506
+ writeToken,
507
+ commitMessage: "Create ABR mezzanine"
508
+ });
509
+ } else {
510
+ finalizeResponse = {
511
+ write_token: writeToken,
512
+ type,
513
+ qlib_id: libraryId,
514
+ id
515
+ };
516
+ }
443
517
 
444
518
  return {
445
519
  logs: logs || [],
@@ -456,6 +530,7 @@ exports.CreateABRMezzanine = async function({
456
530
  * @namedParams
457
531
  * @param {string} libraryId - ID of the mezzanine library
458
532
  * @param {string} objectId - ID of the mezzanine object
533
+ * @param {string=} writeToken - Write token of the mezzanine object draft. If provided, the object will not be finalized
459
534
  * @param {Array<Object>=} access - Array of S3 credentials, along with path matching regexes - Required if any files in the masters are S3 references (See CreateProductionMaster method)
460
535
  * - Format: {region, bucket, accessKey, secret}
461
536
  * @param {number[]} jobIndexes - Array of LRO job indexes to start. LROs are listed in a map under metadata key /abr_mezzanine/offerings/(offeringKey)/mez_prep_specs/, and job indexes start with 0, corresponding to map keys in alphabetical order
@@ -465,14 +540,24 @@ exports.CreateABRMezzanine = async function({
465
540
  exports.StartABRMezzanineJobs = async function({
466
541
  libraryId,
467
542
  objectId,
543
+ writeToken,
468
544
  access=[],
469
545
  jobIndexes = null
470
546
  }) {
471
547
  ValidateParameters({libraryId, objectId});
472
548
 
549
+ if(writeToken) {
550
+ ValidateWriteToken(writeToken);
551
+
552
+ if(!objectId) {
553
+ objectId = this.utils.DecodeWriteToken(writeToken).objectId;
554
+ }
555
+ }
556
+
473
557
  const lastJobOfferingsInfo = await this.ContentObjectMetadata({
474
558
  libraryId,
475
559
  objectId,
560
+ writeToken,
476
561
  metadataSubtree: UrlJoin("abr_mezzanine", "offerings")
477
562
  });
478
563
  const offeringKey = MezJobMainOfferingKey(lastJobOfferingsInfo);
@@ -493,7 +578,16 @@ exports.StartABRMezzanineJobs = async function({
493
578
  // Retrieve authorization tokens for all masters and the mezzanine
494
579
 
495
580
  let authorizationTokens = await Promise.all(
496
- masterVersionHashes.map(async versionHash => await this.authClient.AuthorizationToken({versionHash}))
581
+ masterVersionHashes.map(async versionHash => {
582
+ let payload = {};
583
+ // Hash may be a write token since media/abr_mezzanine/init doesn't support write token, only prod_master_hash
584
+ if(versionHash.startsWith("tqw__")) {
585
+ payload["objectId"] = this.utils.DecodeWriteToken(versionHash).objectId;
586
+ } else {
587
+ payload["versionHash"] = versionHash;
588
+ }
589
+ return await this.authClient.AuthorizationToken({...payload});
590
+ })
497
591
  );
498
592
 
499
593
  authorizationTokens = [
@@ -505,7 +599,17 @@ exports.StartABRMezzanineJobs = async function({
505
599
  Authorization: authorizationTokens.map(token => `Bearer ${token}`).join(",")
506
600
  };
507
601
 
508
- const processingDraft = await this.EditContentObject({libraryId, objectId});
602
+ let processingDraft;
603
+ if(writeToken) {
604
+ const nodeUrl = await this.WriteTokenNodeUrlNetwork({writeToken});
605
+
606
+ processingDraft = {
607
+ write_token: writeToken,
608
+ nodeUrl
609
+ };
610
+ } else {
611
+ processingDraft = await this.EditContentObject({libraryId, objectId});
612
+ }
509
613
 
510
614
  const lroInfo = {
511
615
  write_token: processingDraft.write_token,
@@ -514,21 +618,32 @@ exports.StartABRMezzanineJobs = async function({
514
618
  };
515
619
 
516
620
  // Update metadata with LRO version write token
517
- const statusDraft = await this.EditContentObject({libraryId, objectId});
518
- await this.ReplaceMetadata({
519
- libraryId,
520
- objectId,
521
- writeToken: statusDraft.write_token,
522
- metadataSubtree: "lro_draft",
523
- metadata: lroInfo
524
- });
621
+ let finalizeResponse;
622
+ if(writeToken) {
623
+ await this.ReplaceMetadata({
624
+ libraryId,
625
+ objectId,
626
+ writeToken,
627
+ metadataSubtree: "lro_draft",
628
+ metadata: lroInfo
629
+ });
630
+ } else {
631
+ const statusDraft = await this.EditContentObject({libraryId, objectId});
632
+ await this.ReplaceMetadata({
633
+ libraryId,
634
+ objectId,
635
+ writeToken: statusDraft.write_token,
636
+ metadataSubtree: "lro_draft",
637
+ metadata: lroInfo
638
+ });
525
639
 
526
- const finalizeResponse = await this.FinalizeContentObject({
527
- libraryId,
528
- objectId,
529
- writeToken: statusDraft.write_token,
530
- commitMessage: "Mezzanine LRO status"
531
- });
640
+ finalizeResponse = await this.FinalizeContentObject({
641
+ libraryId,
642
+ objectId,
643
+ writeToken: statusDraft.write_token,
644
+ commitMessage: "Mezzanine LRO status"
645
+ });
646
+ }
532
647
 
533
648
  const {data, errors, warnings, logs} = await this.CallBitcodeMethod({
534
649
  libraryId,
@@ -545,7 +660,7 @@ exports.StartABRMezzanineJobs = async function({
545
660
  });
546
661
 
547
662
  return {
548
- hash: finalizeResponse.hash,
663
+ hash: finalizeResponse ? finalizeResponse.hash : "",
549
664
  lro_draft: lroInfo,
550
665
  writeToken: processingDraft.write_token,
551
666
  nodeUrl: processingDraft.nodeUrl,
@@ -567,10 +682,11 @@ exports.StartABRMezzanineJobs = async function({
567
682
  *
568
683
  * @return {Promise<Object>} - LRO status
569
684
  */
570
- exports.LRODraftInfo = async function({libraryId, objectId}) {
685
+ exports.LRODraftInfo = async function({libraryId, objectId, writeToken}) {
571
686
  const standardPathContents = await this.ContentObjectMetadata({
572
687
  libraryId,
573
688
  objectId,
689
+ writeToken,
574
690
  metadataSubtree: "lro_draft"
575
691
  });
576
692
 
@@ -580,6 +696,7 @@ exports.LRODraftInfo = async function({libraryId, objectId}) {
580
696
  const lastJobOfferingsInfo = await this.ContentObjectMetadata({
581
697
  libraryId,
582
698
  objectId,
699
+ writeToken,
583
700
  metadataSubtree: UrlJoin("abr_mezzanine", "offerings")
584
701
  });
585
702
 
@@ -595,6 +712,7 @@ exports.LRODraftInfo = async function({libraryId, objectId}) {
595
712
  const oldPathContents = await this.ContentObjectMetadata({
596
713
  libraryId,
597
714
  objectId,
715
+ writeToken,
598
716
  metadataSubtree: `lro_draft_${mainOfferingKey}`
599
717
  });
600
718
  if(oldPathContents) {
@@ -618,17 +736,17 @@ exports.LRODraftInfo = async function({libraryId, objectId}) {
618
736
  *
619
737
  * @return {Promise<Object>} - LRO status
620
738
  */
621
- exports.LROStatus = async function({libraryId, objectId}) {
739
+ exports.LROStatus = async function({libraryId, objectId, writeToken}) {
622
740
  ValidateParameters({libraryId, objectId});
623
741
 
624
- const lroDraft = await this.LRODraftInfo({libraryId, objectId});
742
+ const lroDraft = await this.LRODraftInfo({libraryId, objectId, writeToken});
625
743
 
626
744
  this.RecordWriteToken({writeToken: lroDraft.write_token, fabricNodeUrl: lroDraft.node});
627
745
 
628
746
  return await this.ContentObjectMetadata({
629
747
  libraryId,
630
748
  objectId,
631
- writeToken: lroDraft.write_token,
749
+ writeToken,
632
750
  metadataSubtree: "lro_status"
633
751
  });
634
752
  };
@@ -640,34 +758,45 @@ exports.LROStatus = async function({libraryId, objectId}) {
640
758
  * @namedParams
641
759
  * @param {string} libraryId - ID of the mezzanine library
642
760
  * @param {string} objectId - ID of the mezzanine object
643
- * @param {string} writeToken - Write token for the mezzanine object
761
+ * @param {string} writeToken - Write token for the mezzanine object. If specified, the object will not be finalized.
644
762
  * @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.
645
763
  * @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.
646
764
  *
647
765
  * @return {Promise<Object>} - The finalize response for the mezzanine object, as well as any logs, warnings and errors from the finalization
648
766
  */
649
- exports.FinalizeABRMezzanine = async function({libraryId, objectId, preFinalizeFn, preFinalizeThrow}) {
767
+ exports.FinalizeABRMezzanine = async function({libraryId, objectId, preFinalizeFn, preFinalizeThrow, writeToken}) {
650
768
  ValidateParameters({libraryId, objectId});
651
769
 
652
- const lroDraft = await this.LRODraftInfo({libraryId, objectId});
770
+ if(writeToken) {
771
+ ValidateWriteToken(writeToken);
772
+ }
773
+
774
+ const nodeUrl = await this.WriteTokenNodeUrlNetwork({writeToken});
653
775
 
654
776
  // tell http client what node to contact for this write token
655
- this.RecordWriteToken({writeToken: lroDraft.write_token, fabricNodeUrl: lroDraft.node});
777
+ this.RecordWriteToken({writeToken: writeToken, fabricNodeUrl: nodeUrl});
656
778
 
657
779
  const lastJobOfferingsInfo = await this.ContentObjectMetadata({
658
780
  libraryId,
659
781
  objectId,
660
- writeToken: lroDraft.write_token,
782
+ writeToken,
661
783
  metadataSubtree: UrlJoin("abr_mezzanine", "offerings")
662
784
  });
663
785
 
664
786
  const offeringKey = MezJobMainOfferingKey(lastJobOfferingsInfo);
665
787
  const masterHash = lastJobOfferingsInfo[offeringKey].prod_master_hash;
666
788
 
789
+ let authPayload = {};
790
+ if(masterHash.startsWith("tqw__")) {
791
+ authPayload["objectId"] = this.utils.DecodeWriteToken(masterHash).objectId;
792
+ } else {
793
+ authPayload["versionHash"] = masterHash;
794
+ }
795
+
667
796
  // Authorization token for mezzanine and master
668
797
  let authorizationTokens = [
669
798
  await this.authClient.AuthorizationToken({libraryId, objectId, update: true}),
670
- await this.authClient.AuthorizationToken({versionHash: masterHash})
799
+ await this.authClient.AuthorizationToken({...authPayload})
671
800
  ];
672
801
 
673
802
  const headers = {
@@ -677,7 +806,7 @@ exports.FinalizeABRMezzanine = async function({libraryId, objectId, preFinalizeF
677
806
  const {data, errors, warnings, logs} = await this.CallBitcodeMethod({
678
807
  objectId,
679
808
  libraryId,
680
- writeToken: lroDraft.write_token,
809
+ writeToken,
681
810
  method: UrlJoin("media", "abr_mezzanine", "offerings", offeringKey, "finalize"),
682
811
  headers,
683
812
  constant: false
@@ -686,9 +815,9 @@ exports.FinalizeABRMezzanine = async function({libraryId, objectId, preFinalizeF
686
815
  let preFinalizeWarnings = [];
687
816
  if(preFinalizeFn) {
688
817
  const params = {
689
- nodeUrl: lroDraft.node,
818
+ nodeUrl,
690
819
  offeringKey,
691
- writeToken: lroDraft.write_token
820
+ writeToken
692
821
  };
693
822
  try {
694
823
  await preFinalizeFn(params);
@@ -702,13 +831,16 @@ exports.FinalizeABRMezzanine = async function({libraryId, objectId, preFinalizeF
702
831
  }
703
832
  }
704
833
 
705
- const finalizeResponse = await this.FinalizeContentObject({
706
- libraryId,
707
- objectId: objectId,
708
- writeToken: lroDraft.write_token,
709
- commitMessage: "Finalize ABR mezzanine",
710
- awaitCommitConfirmation: false
711
- });
834
+ const finalizeResponse = {};
835
+ if (!writeToken) {
836
+ finalizeResponse = await this.FinalizeContentObject({
837
+ libraryId,
838
+ objectId: objectId,
839
+ writeToken,
840
+ commitMessage: "Finalize ABR mezzanine",
841
+ awaitCommitConfirmation: false
842
+ });
843
+ }
712
844
 
713
845
  return {
714
846
  data,
@@ -612,7 +612,8 @@ exports.CreateContentObject = async function({libraryId, objectId, options={}})
612
612
  path: path,
613
613
  body: { // filter out options not recognized by server (noEncryptionConk, createKMSConk)
614
614
  type: options.type,
615
- meta: options.meta
615
+ meta: options.meta,
616
+ copy_from: options.copy_from
616
617
  }
617
618
  });
618
619
 
@@ -1601,15 +1602,15 @@ exports.SetAuthPolicy = async function({objectId, policyId}) {
1601
1602
  *
1602
1603
  * @namedParams
1603
1604
  * @param {string} writeToken - Write token to delete
1604
- * @param {string} libraryId - ID of the library
1605
1605
  */
1606
- exports.DeleteWriteToken = async function({writeToken, libraryId}) {
1606
+ exports.DeleteWriteToken = async function({writeToken}) {
1607
1607
  ValidateWriteToken(writeToken);
1608
- ValidateLibrary(libraryId);
1609
1608
 
1610
- let path = UrlJoin("qlibs", libraryId, "q", writeToken);
1609
+ const objectId = this.utils.DecodeWriteToken(writeToken).objectId;
1610
+ const libraryId = await this.ContentObjectLibraryId({objectId});
1611
+ const path = UrlJoin("qlibs", libraryId, "q", writeToken);
1611
1612
 
1612
- const authorizationHeader = await this.authClient.AuthorizationHeader({libraryId, update: true});
1613
+ const authorizationHeader = await this.authClient.AuthorizationHeader({objectId, update: true});
1613
1614
 
1614
1615
  await this.HttpClient.Request({
1615
1616
  headers: authorizationHeader,
@@ -141,15 +141,19 @@ class LiveConf {
141
141
  // Used by generateAudioStreamsConfig()
142
142
  getAudioStreamsFromProbe() {
143
143
  let audioStreams = {};
144
- for(let index = 0; index < this.probeData.streams.length; index++) {
145
- if(this.probeData.streams[index].codec_type == "audio") {
146
- audioStreams[index] = {
147
- recordingBitrate: Math.max(this.probeData.streams[index].bit_rate, 128000),
148
- recordingChannels: this.probeData.streams[index].channels,
149
- playoutLabel: `Audio ${index}`
150
- };
151
- }
144
+ const audioStreamData = this.probeData.streams.filter((value) => value.codec_type === "audio");
145
+
146
+ for(let index = 0; index < audioStreamData.length; index++) {
147
+ const currentStreamIndex = audioStreamData[index].stream_index;
148
+ const currentStreamData = audioStreamData[index];
149
+
150
+ audioStreams[currentStreamIndex] = {
151
+ recordingBitrate: Math.max(currentStreamData.bit_rate, 128000),
152
+ recordingChannels: currentStreamData.channels,
153
+ playoutLabel: `Audio ${index + 1}`
154
+ };
152
155
  }
156
+
153
157
  return audioStreams;
154
158
  }
155
159
 
@@ -386,7 +390,7 @@ class LiveConf {
386
390
  recordingChannels: audio.recording_channels || 2,
387
391
  };
388
392
  if(audio.playout) {
389
- audioStreams[audioIdx].playoutLabel = audio.playout_label || `Audio ${audioIdx}`;
393
+ audioStreams[audioIdx].playoutLabel = audio.playout_label || `Audio ${i + 1}`;
390
394
  }
391
395
  }
392
396
  }
@@ -428,8 +428,14 @@ exports.StreamStatus = async function({name, stopLro=false, showParams=false}) {
428
428
  ]
429
429
  });
430
430
  } catch(error) {
431
- console.error("Unable to read edge write token metadata. Has token been deleted?", error);
432
- status.state = "inactive";
431
+ if(error.message && error.message.includes("ERR_TOO_MANY_REDIRECTS")) {
432
+ console.error("Redirect loop detected when trying to read metadata.");
433
+ status.state = "unavailable";
434
+ } else {
435
+ console.error("Unable to read edge write token metadata. Has token been deleted?", error);
436
+ status.state = "inactive";
437
+ }
438
+
433
439
  return status;
434
440
  }
435
441
 
@@ -879,7 +885,6 @@ exports.StreamStopSession = async function({name}) {
879
885
  }
880
886
 
881
887
  await this.DeleteWriteToken({
882
- libraryId,
883
888
  writeToken: metaEdgeWriteToken
884
889
  });
885
890
  } catch(error) {