@adobe/acc-js-sdk 1.1.58 → 1.1.59

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.
@@ -3,8 +3,15 @@ layout: page
3
3
  title: Change Log
4
4
  ---
5
5
 
6
+ <section class="changelog"><h1>Version 1.1.59</h1>
7
+ <h2>2025/08/22</h2>
8
+ <li>
9
+ In previous commit, computing the UUID was not working in a browser context
10
+ </li>
11
+ </section>
12
+
6
13
  <section class="changelog"><h1>Version 1.1.58</h1>
7
- <h2>2025/06/24</h2>
14
+ <h2>2025/08/20</h2>
8
15
  <li>
9
16
  Bumped dependencies version to fix vulnerabilities
10
17
  </li>
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@adobe/acc-js-sdk",
3
- "version": "1.1.58",
3
+ "version": "1.1.59",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@adobe/acc-js-sdk",
9
- "version": "1.1.58",
9
+ "version": "1.1.59",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
12
  "axios": "^1.7.8",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/acc-js-sdk",
3
- "version": "1.1.58",
3
+ "version": "1.1.59",
4
4
  "description": "ACC Javascript SDK",
5
5
  "main": "src/index.js",
6
6
  "homepage": "https://github.com/adobe/acc-js-sdk#readme",
package/src/client.js CHANGED
@@ -38,7 +38,7 @@ const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
38
38
  const { Util } = require('./util.js');
39
39
  const { XtkJobInterface } = require('./xtkJob.js');
40
40
  const qsStringify = require('qs-stringify');
41
- const crypto = require('crypto');
41
+
42
42
  /**
43
43
  * @namespace Campaign
44
44
  *
@@ -636,9 +636,16 @@ const fileUploader = (client) => {
636
636
  // If a prefix is provided, we use it with a UUID (i.e. 'customPrefix-123e4567-e89b-12d3-a456-426614174000')
637
637
  const oldBehaviorPrefix = 'RES';
638
638
  const prefix = Util.validateFileResPrefix(fileResPrefix, oldBehaviorPrefix);
639
-
639
+ const getUUIDOrFallback = async() => {
640
+ try {
641
+ return Util.getUUID();
642
+ } catch (error) {
643
+ // In case getUUID throws, fall back to increasing the counter
644
+ return await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' });
645
+ }
646
+ };
640
647
  const suffix = (prefix === oldBehaviorPrefix) ?
641
- await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' }) : crypto.randomUUID();
648
+ await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' }) : await getUUIDOrFallback();
642
649
 
643
650
  const internalName = (prefix === oldBehaviorPrefix) ? `${prefix}${suffix}` : `${prefix}_${suffix}`;
644
651
 
package/src/util.js CHANGED
@@ -143,7 +143,7 @@ class Util {
143
143
  return schemaId;
144
144
  }
145
145
 
146
- static validateFileResPrefix(prefix, defaultPrefix = "RES") {
146
+ static validateFileResPrefix(prefix, defaultPrefix = 'RES') {
147
147
  const regex = /^[A-Za-z_][A-Za-z0-9_]*$/;
148
148
 
149
149
  if (typeof prefix !== "string" || !regex.test(prefix)) {
@@ -153,6 +153,23 @@ class Util {
153
153
  return prefix;
154
154
  }
155
155
 
156
+ static getUUID() {
157
+ if (globalThis.crypto &&
158
+ globalThis.crypto.randomUUID &&
159
+ typeof globalThis.crypto.randomUUID === 'function') {
160
+ return globalThis.crypto.randomUUID(); // browser
161
+ }
162
+ const nodeCrypto = (() => {
163
+ return require("crypto");
164
+ })();
165
+ if (nodeCrypto && nodeCrypto.randomUUID) {
166
+ return nodeCrypto.randomUUID(); // Node
167
+ }
168
+
169
+ //Nothing worked
170
+ throw new Error('Unable to generate UUID');
171
+ }
172
+
156
173
  /**
157
174
  * Test if an object is a promise
158
175
  * @param {*} object the object to test
@@ -3604,7 +3604,7 @@ describe('ACC Client', function () {
3604
3604
  statusCode: 500,
3605
3605
  });
3606
3606
  });
3607
- });
3607
+ }); // "File uploader - on server"
3608
3608
 
3609
3609
  describe("File uploader - on browser", () => {
3610
3610
  beforeEach(() => {
@@ -4218,8 +4218,6 @@ describe('ACC Client', function () {
4218
4218
  statusCode: 400,
4219
4219
  });
4220
4220
  });
4221
- });
4222
-
4223
4221
  it("Test uploads by specifying a file prefix", async () => {
4224
4222
  // Create a mock client and logon
4225
4223
  const client = await Mock.makeClient();
@@ -4261,13 +4259,69 @@ describe('ACC Client', function () {
4261
4259
  ); // xtk:fileRes#GetURL
4262
4260
 
4263
4261
  // Call upload
4264
- const result = await client.fileUploader.upload({
4265
- type: "text/html",
4266
- size: 12345,
4267
- }, undefined, 'PREFIX');
4262
+ await client.fileUploader.upload({
4263
+ type: "text/html",
4264
+ size: 12345,
4265
+ }, undefined, 'PREFIX');
4268
4266
  expect(Util.validateFileResPrefix).toHaveBeenLastCalledWith('PREFIX', 'RES');
4269
4267
  });
4270
- });
4268
+
4269
+ it("Test uploads by with a file prefix but getUUID throws", async () => {
4270
+ // Create a mock client and logon
4271
+ const client = await Mock.makeClient();
4272
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
4273
+ await client.NLWS.xtkSession.logon();
4274
+
4275
+ // Mock the upload protocol
4276
+ // - the upload.jsp (which returns the content of an iframe and JS to eval)
4277
+ // - call to xtk:session#Write
4278
+ // - call to xtk:fileRes#PublishIfNeeded
4279
+ // - call to xtk:fileRes#GetURL
4280
+
4281
+ client._transport.mockReturnValueOnce(
4282
+ Promise.resolve(`Ok
4283
+ <html xmlns="http://www.w3.org/1999/xhtml">
4284
+ <head>
4285
+ <script type="text/javascript">if(window.parent&&window.parent.document.controller&&"function"==typeof window.parent.document.controller.uploadFileCallBack){var aFilesInfo=new Array;aFilesInfo.push({paramName:"file",fileName:"test.txt",newFileName:"d8e8fca2dc0f896fd7cb4cb0031ba249.txt",md5:"d8e8fca2dc0f896fd7cb4cb0031ba249"}),window.parent.document.controller.uploadFileCallBack(aFilesInfo)}</script>
4286
+ </head>
4287
+ <body></body>
4288
+ </html>`)
4289
+ ); // upload.jsp
4290
+
4291
+ client._transport.mockReturnValueOnce(
4292
+ Promise.resolve(Mock.GET_XTK_COUNTER_RESPONSE)
4293
+ ); // GetEntityIfMoreRecentResponse - counter
4294
+ client._transport.mockReturnValueOnce(
4295
+ Mock.INCREASE_VALUE_RESPONSE
4296
+ ); // xtk:counter#IncreaseValue
4297
+
4298
+ client._transport.mockReturnValueOnce(
4299
+ Mock.GET_XTK_SESSION_SCHEMA_RESPONSE
4300
+ ); // GetEntityIfMoreRecentResponse - session
4301
+
4302
+ client._transport.mockReturnValueOnce(Mock.FILE_RES_WRITE_RESPONSE); // xtk:session#Write
4303
+ jest.spyOn(Util, 'getUUID').mockImplementation(() => { throw new Error('UUID error'); });
4304
+
4305
+ client._transport.mockReturnValueOnce(
4306
+ Promise.resolve(Mock.GET_FILERES_QUERY_SCHEMA_RESPONSE)
4307
+ ); // GetEntityIfMoreRecentResponse - fileRes
4308
+ client._transport.mockReturnValueOnce(
4309
+ Promise.resolve(Mock.PUBLISH_IF_NEEDED_RESPONSE)
4310
+ ); // xtk:fileRes#PublishIfNeeded
4311
+
4312
+ client._transport.mockReturnValueOnce(
4313
+ Promise.resolve(Mock.GET_URL_RESPONSE)
4314
+ ); // xtk:fileRes#GetURL
4315
+
4316
+ // Call upload
4317
+ await client.fileUploader.upload({
4318
+ type: "text/html",
4319
+ size: 12345,
4320
+ }, undefined, 'PREFIX');
4321
+ expect(Util.getUUID).toHaveBeenCalledTimes(1);
4322
+ });
4323
+ }); // "File uploader - on browser"
4324
+ }); // 'upload'
4271
4325
 
4272
4326
  describe('uploadAemAsset', () => {
4273
4327
  // write unit test for client.fileUploader.uploadAemAsset method
package/test/util.test.js CHANGED
@@ -458,5 +458,104 @@ describe('Util', function() {
458
458
  expect(Util.validateFileResPrefix("132Invalid", "customDefault")).toBe("customDefault");
459
459
  });
460
460
  });
461
+
462
+ describe("GetUUID", () => {
463
+ describe("UUID - on server node", () => {
464
+ describe("node <= 16", () => {
465
+ describe('code coverage: getUUID', () => {
466
+ let originalCrypto;
467
+ // on old Node versions, crypto may not be available
468
+ // deleting globalThis.crypto to simulate the environment on newer Node
469
+ beforeEach(() => {
470
+ // Save the original crypto
471
+ originalCrypto = globalThis.crypto;
472
+ delete globalThis.crypto;
473
+ });
474
+
475
+ afterEach(() => {
476
+ // Restore it after the test
477
+ globalThis.crypto = originalCrypto;
478
+ });
479
+
480
+ it('should handle require("crypto") throwing', () => {
481
+ // Force require("crypto") to throw
482
+ jest.mock('crypto', () => {
483
+ throw new Error('mock require failure');
484
+ });
485
+
486
+ // Re-require the module AFTER mocking
487
+ const UUIDHelper = require('../src/util.js').Util;
488
+
489
+ let exceptionCaught = false;
490
+ try{
491
+ UUIDHelper.getUUID();
492
+ } catch (e) {
493
+ exceptionCaught = true;
494
+ }
495
+ expect(exceptionCaught).toBe(true);
496
+ });
497
+
498
+ it('should handle require("crypto") throwing', () => {
499
+ // Force require("crypto") to not have randomUUID
500
+ jest.mock('crypto', () => ({}));
501
+
502
+ // Re-require the module AFTER mocking
503
+ const UUIDHelper = require('../src/util.js').Util;
504
+
505
+ let exceptionCaught = false;
506
+ try{
507
+ UUIDHelper.getUUID();
508
+ } catch (e) {
509
+ exceptionCaught = e.message === 'Unable to generate UUID';
510
+ }
511
+ expect(exceptionCaught).toBe(true);
512
+ });
513
+
514
+ it('should fallback to node crypto when globalThis.crypto is not available', () => {
515
+ jest.unmock('crypto');
516
+ // Spy on require
517
+ const spy = jest.spyOn(require('crypto'), 'randomUUID').mockReturnValue('mock-uuid');
518
+
519
+ // Re-import the module if your getUUID function is from a module
520
+ const uuid = Util.getUUID(); // or just call getUUID() if it's in scope
521
+
522
+ expect(uuid).toBe('mock-uuid');
523
+ expect(spy).toHaveBeenCalled();
524
+ spy.mockRestore();
525
+ });
526
+ });
527
+ });
528
+ });
529
+ describe("node > 16", () => {
530
+ it('should return a correct UUID v4', () => {
531
+ // x is [0-9a-f], Y is 8, 9, a or b
532
+ // uuid format: xxxxxxxx-xxxx-4xxx-Yxxx-xxxxxxxxxxxx
533
+ const uuidV4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
534
+ expect(uuidV4Regex.test(Util.getUUID())).toBe(true);
535
+ });
536
+ });
537
+
538
+ describe("UUID - on browser", () => {
539
+ // code coverage test as we mock the browser return values
540
+ it('should return a correct UUID v4', () => {
541
+ if (!globalThis.crypto || !globalThis.crypto.randomUUID){
542
+ globalThis.crypto = {
543
+ ...globalThis.crypto,
544
+ randomUUID: jest.fn(),
545
+ };
546
+ }
547
+
548
+ // x is [0-9a-f], Y is 8, 9, a or b
549
+ // uuid v4 format: xxxxxxxx-xxxx-4xxx-Yxxx-xxxxxxxxxxxx
550
+ // Mocking crypto.randomUUID to return a specific valid v4 UUID
551
+ jest.spyOn(globalThis.crypto, 'randomUUID').mockReturnValue('123e4567-e89b-42d3-a456-426614174000');
552
+ const uuidV4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
553
+ expect(uuidV4Regex.test(Util.getUUID())).toBe(true);
554
+ // Mocking crypto.randomUUID to return a specific an invalid v4 UUID
555
+ jest.spyOn(globalThis.crypto, 'randomUUID').mockReturnValue('12345678-1234-0234-0567-426614174000');
556
+ expect(uuidV4Regex.test(Util.getUUID())).toBe(false);
557
+ });
558
+ });
559
+ });
461
560
  });
462
561