Compatibility Mode Changes

To upgrade to the latest compatibility mode, you must understand what changed between modes, so that you can make the corresponding changes to your code.

Your site uses one of the following compatibility modes: 10.4, 10.6, 13.6, 15.5, 16.1, 16.2,17.7, 18.2, 18.10, 19.10, 21.2, or 22.7.

The dw.system.System.getCompatibilityMode() method returns the compatibility mode of the custom code version that is currently active. The compatibility mode is returned as a number, for example, compatibility mode 15.5 is returned as 1505.

22.7

With compatibility mode 22.7, the B2C Commerce server-side JavaScript engine supports more elements from ECMAScript 6 (ES6) and later. You can access new and expanded features, including top-level built-in types and methods for existing classes.
  • Shorthand property names
  • New JavaScript primitive type bigint, replaces dw.util.BigInteger
  • Template literal support
  • String.raw
  • globalThis
  • Exponential operator
  • Ojbect.values / Object.entries / objectfromEntries / Number.EPSILON
  • dw.order.Order.getOrderExportXML() API v2 with strict argument validation and extended RSA algorithm support
    • The encryption parameter handling for encrypted and masked payment instrument data in dw.order.Order#getOrderExportXML API is revised.
    • Data Includes
      • Credit card number
      • Bank account number
      • Bank account driver's license number
    • Change Details
      • dw.order.Order.getOrderExportXML(encryptionAlgorithm, encryptionKey, encryptUsingEKID) was removed entirely. This method was deprecated because the encryptUsingEKID parameter was never used. To return encrypted payment instrument data with the given algorithm or key, use dw.order.Order.getOrderExportXML(encryptionAlgorithm, encryptionKey) instead. To return payment instrument data unmasked, use dw.order.Order.getOrderExportXML().
      • dw.order.Order.getOrderExportXML(encryptionAlgorithm, encryptionKey) no longer accepts an invalid encryption argument, which includes null, blank, or otherwise empty algorithms or keys.
      • dw.order.Order.getOrderExportXML(encryptionAlgorithm, encryptionKey) supports the current RSA/ECB/OAEPWithSHA-256AndMGF1Padding encryption algorithm. Previously, the encryptionAlgorithm argument was ignored and the (now deprecated) algorithm RSA/ECB/PKCS1Padding was always used when a non-blank key was provided.
      • dw.order.Order.getOrderExportXML(encryptionAlgorithm, encryptionKey) no longer accepts a null key, which was used as a β€œmagic” value for returning the payment instrument data as masked instead of encrypted. Only use dw.order.Order.getOrderExportXML() to return masked payment instrument data.

21.7

  • Any use of invalid characters in a cookie name, as described in RFC6265, which references RFC2068, now causes dw.web.Cookie to throw an exception.
The dw.catalog.ProductInventoryRecord class has the following updates
  • The already-deprecated method getOnHand() has been removed.
  • The allocation amount now requires an allocation reset date. For that reason, the setAllocation(allocationAmount, allocationResetDate) has replaced the setAllocation(allocationAmount) method, which has been removed.
  • Product Inventory Records are now read-only in a storefront context. Thus, you can no longer call the following methods within a storefront context:
    • setAllocation(allocationAmount, allocationResetDate)
    • setBackorderable(boolean)
    • setInStockDate(Date)
    • setPerpetual(boolean)
    • setPreorderable(boolean)
    • setPreorderBackorderAllocation(double)

21.2

  • The JavaScript server-side engine supports some ECMAScript 6 and later language elements.
  • B2C Commerce JavaScript is based on Rhino JavaScript. Compatibility modes earlier than 21.2 use the ECMAScript 5 (ES5) language version. With 21.2, some ECMAScript 6 (ES6) language elements, standardized as ECMAScript 2015 and later, are supported. Keep in mind that ES6 isn’t completely compatible with ES5. ES6 introduces the following new keywords that you can no longer use as identifiers.
    • In general: class, export, extends, import, super, await, enum
    • In strict mode only: implements, interface, package, private, protected, public, static
  • Compatibility mode 21.2 activates numerous B2C Commerce JavaScript changes, including many small fixes and changes to existing features. Some of the significant changes and new features are as follows:
    • More features for strict mode.
    • New JavaScript top-level built-in types, including Symbol, Map, Set, and typed arrays. The new types are designated as API Versioned, From version 21.2 in B2C Commerce Script documentation.
    • New methods for existing classes, for example String, Number, Array, Math, and Object. The new methods are designated as API Versioned, From version 21.2 in B2C Commerce Script documentation.
    • Support for Symbols.
    • for..of loops.
    • Arrow functions.
    • Generator functions (functions that use function * syntax.)
    • Shorthand method declarations. (Shorthand properties aren’t supported.)
    • Destructuring of objects.
    • More consistent timeout handling.

19.10

19.10 includes the following changes:

  • Long running scripts now abort as expected after the timeout period. Previously, some scripts didn’t time out under some conditions.
  • The classes dw.svc.ServiceRegistry, dw.svc.ServiceDefinition, and the subclasses of dw.svc.ServiceDefinition have been removed from the script API. These classes had been previously deprecated and replaced with dw.svc.LocalServiceRegistry. You can’t register ServiceDefinitions using an init script in package.json. The init scripts are no longer executed.
  • Objects of unsupported types can no longer be stored at the session. Previously, if you used an unsupported type, you got a deprecation warning message. With 19.10, the session object refuses objects of unsupported types with an exception. If you implemented your storefront based on SiteGenesis, sometimes you have to adjust the code. In SiteGenesis, when a shopper logs in, the requested location is held in a session variable of type URL. In guard.js, change the type to string, as follows:

    Change this:

    session.custom.TargetLocation = browsing.lastUrl();

    To this:

    session.custom.TargetLocation = ''+browsing.lastUrl();

18.10

The dw.util.StringUtils#formatNumber(number,format,locale) API method now respects the regional settings of the locale for grouping and decimal characters.

Before Compatibility Mode 18.10, this method ignored the defined regional settings and used the format setting from Java for the specified locale.

18.2

Exceptions from JavaScript functions called by script API classes were wrapped as a SystemError. This situation led to issues if the exception was an APIException, because the additional properties weren’t accessible.

A method where this situation occurred is dw.util.Transaction.wrap():

try {
 dw.util.Transaction.wrap(function () {
   throw new Error("my error");
   });
 } catch (e)
 {
 return {message: e.message, name: e.name}; 
 }

Before Compatibility Mode 18.2, this example returned the unexpected result:

message: com.demandware.core.script.capi.ScriptingException: Error: test error (...) name: SystemError.

With 18.2 Compatibility Mode, the original exception object remains intact, which means the example returns the following message:

test error name: Error

17.7

APP-49849: Changed Argument Handling of ISML.RenderTemplate

The behavior of the dw.template.ISML.renderTemplate() method has changed slightly. The template execution is now scoped. All variables passed to the template are only placed in the dictionary temporarily. After the template finishes, the original pipeline dictionary is recovered. Previously, arguments passed into the template were placed in the global pipeline dictionary. Having the arguments in the global pipeline dictionary led to naming conflicts and changed values in the dictionary after the template returned.

Important: Because this change is a breaking change, a new API compatibility mode was added. The new behavior is only activate if API mode is set to 17.7 or later.

16.2

With Compatibility Mode 16.2 it, you can encrypt and decrypt a message with a salt of β€˜0’, using the Cipher class in the Salesforce B2C Commerce API. When using a previous compatibility mode, a system-defined salt was used if the developer passed a salt that consisted solely of bytes with value 0x00 or other characters that are represented by ASCII codes less than or equal to 0x20.

Compatibility Mode 16.1 used the following salt values:

  • salt 0x7d, 0x60, 0x43, 0x5f, 0x02, 0xe9, 0xe0, 0xae (Base64 encoded fWBDXwLp4K4=) as the default salt in the cases mentioned previously for PBE-based encryption.
  • salt 0x73, 0x2f, 0x2d, 0x33, 0xc8, 0x01, 0x73, 0x2b, 0x72, 0x06, 0x75, 0x6c, 0xbd, 0x44, 0xf9, 0xc1 (Base64 encoded cy8tM8gBcytyBnVsvUT5wQ==) as the default salt for AES-based encryptions.

If you must reproduce the behavior of compatibility modes before Release 16.2 on an instance that has 16.2 enabled, use these salts as the salt parameters to encrypt or decrypt.

16.1

APP-33920: ECMAScript 5 compliant behavior of global function parseInt(String) in code compatibility version 16.1

Starting with B2C Commerce Script API (code compatibility) version 16.1, the parseInt(String) function is ECMAScript 5 compliant. In older versions, the function was only compliant with ECMAScript 3. The difference is that with ECMAScript 5, octal number support was dropped. Numbers starting with leading zeros are now parsed to radix 10 instead of radix 8, as previously. If the dynamic radix determination isn't needed explicitly, the use of parseInt(String, Number) is still recommended.

APP-34144: Map.Values() Returns a View to the Map in Code Compatibility Version 16.1

Starting with B2C Commerce Script API (code compatibility) version 16.1, the Map.values() method now returns a view to a map the same way the Map.keySet() and Map.entrySet() methods did in earlier versions. Previously, the Map.values() method returned an independent collection where modification didn’t change the map.

15.5

APP-32403: SiteGenesis Release 15.3 and 15.4 Developers Must Modify Their Code If Using the Release 15.5 B2C Commerce Script API

A recent change in the way the 15.5 B2C Commerce Script API handles global variables means that customers who have adopted SiteGenesis Releases 15.3 or 15.4 must explicitly declare the paths of global functions such as dw.system.Logger and dw.web.URLUtils.

Who Does This Affect?

This change affects only customers using SiteGenesis Releases 15.3 and 15.4, and who have set the B2C Commerce Script API Compatibility Mode to 15.5. This change doesn't affect customers using B2C Commerce Script API Version 13.6 or using SiteGenesis 15.2 or earlier or SiteGenesis 15.5 or later.

How Does the Problem Appear?

If you’re using SiteGenesis Release 15.3 or 15.4 and you’re using B2C Commerce Script API 15.5, you can't access the Cart page in SiteGenesis. You get an error in your log file as follows:

org.mozilla.javascript.EcmaError: ReferenceError:
 "Logger" isn't defined.
 (app_storefront_core/cartridge/scripts/cart/calculate.js#271)
 in line 271

What Should I Do If This Happens to Me?

  1. If possible, merge SiteGenesis Release 15.5 into your code, or
  2. Use the SiteGenesis 15.5 version of calculate.js, or
  3. In calculate.js, replace all calls to Logger() to the fully qualified version, as follows: dw.system.Logger() .
  4. Only if you have no opportunity to fix the code to comply with the updated JavaScript standard set the compatibility mode to 13.6.
Note: This change is a temporary fix until you can make the required code changes.

APP-23919: Global Scope of Caller Not Accessible by Called Modules with Compatibility Version 15.5

The require() script now works properly within pipelines (Assign Node). Previously, global variables were shared between modules, which limited isolation and reusability. Global variables defined in a module script didn’t work, while they worked properly when requiring the module in another script.

See the following example:

TopLevelScript.ds


importPackage( dw.system );
 var globalVariable = PIPELET_ERROR;
 function execute( args : PipelineDictionary ) :
 Number
 {
 return require("myModule");
 }

MyModule.ds

var globalVariable;
 module.exports = globalVariable || PIPELET_NEXT;

With compatibility version 15.5, the PIPELET_NEXT is returned, while previous compatibility versions returned a PIPELET_ERROR.

Activate the new behavior by selecting compatibility version 15.5.

Customer impact: Review your code for use of the require() script that relies on the leakage of variables from the caller scope into the module.

APP-30008: Cipher Methods Expect a Base64-Encoded Salt with Compatibility Version 15.5

Starting with API Version 15.5, all dw.crypto.Cipher methods expect the salt argument to be base64-encoded.

Note: Passing undefined as salt is no longer possible, because it was previously used for some algorithms. With the new API version, you encounter an EncryptionException with the message base64 decoding of salt failed.

APP-30138: Module Lifetime Is Entire Request with Compatibility Version 15.5

With code compatibility version 15.5, modules are now loaded and instantiated only once per request. If within script code a require() call requests the module a second time, then the same instance as the first call is returned. This return of the same instance happens regardless of the location of the require call (pipeline, script files, or ISML files).

Previously, the module cache that was held within the implementation of require() wasn’t global per request, but belonged to the JavaScript context. For every new context, a new cache was created. Modules that were resolved in a script were therefore not visible to script sections contained in templates (for example, isscript) because scripts had their scope, and templates had another scope.

APP-30693: Log notification for changed methods in older API Versions

If a method behavior changes, but the method signature stays the same, and the method is still used with an old B2C Commerce Script API version active (also referred to as Compatibility Mode), B2C Commerce now writes notifications to the API log.

For example, if a fictitious class method apiClass.setMethod(String one) existed in the old B2C Commerce Script API Version 13.6 (which is the last active Compatibility Mode in 15.4) and the behavior changed with the new B2C Commerce Script API (a new Compatibility Mode) in Release 15.5, the usage of apiClass.setMethod in Release 15.5 executed on the old B2C Commerce Script API version 13.6 will log a message such as the following to the API log file:

API Method apiClass.setMethod(String) has been changed in a newer API Version.
Consider updating."

The same invocation on the newer B2C Commerce Script API (Compatibility Mode 15.5 after you activated this new API) will no longer log this type of message.

APP-31925: Strict JSON parsing enforced with code compatibility version 15.5

Starting with B2C Commerce Script API (code compatibility) version 15.5, strict parsing is enforced. Previously, versions of the JSON parsers in B2C Commerce accepted invalid JSON that contained extraneous commas before closing brackets.

APP-32088: ECMAScript compliance issue in B2C Commerce script parser fixed with compatibility version 15.5

When compatibility version 15.5 is selected, an error is thrown when code accesses undeclared properties, which is proper ECMAScript behavior. For compatibility reasons, this behavior is still allowed if you select a compatibility version earlier than 15.5.

13.6

APP-18307: SeekableIterator in Pipeline Dictionary

In B2C Commerce script files, you can call API methods that return a dw.util.SeekableIterator instance. A SeekableIterator enables you to iterate over its elements a single time. However, if you put this iterator into the Pipeline Dictionary and your API compatibility mode is earlier than 13.6, you can use the iterator multiple times. Depending on the number of elements the iterator represents, this approach can cause memory usage issues.

As of API compatibility mode 13.6, the elements in the SeekableIterator can only be accessed one time. If you’re using an API compatibility mode that pre-dates 13.6, there are entries in the API log indicating that the SeekableIterator is being placed into the Pipeline Dictionary. These log entries enable you to identify uses of SeekableIterator where moving to 13.6 compatibility mode can cause a change in your Pipeline behavior.

The log entries take the following form:

PipelineDictionary usage violation:
 WARN: dw.util.SeekableIterator put in dictionary.
 KEY: key_name, SCRIPT: script_name

where key_name is the pipeline dictionary key, and script_name is the name of the script that is putting the SeekableIterator into the dictionary.

10.6

APP-46080: SeekableIterator.close() now ensures that the iterator is closed

As of Release 17.2, SeekableIterator.close() now ensures that the iterator is closed. Previously in some situations, it was possible to read elements from a dw.util.SeekableIterator even after close was explicitly called.

Customer impact: for compatibility modes 10.6 and greater, the iterator must always be empty after a call to close().

APP-15882: API Behavior Change When Accessing SeekableIteratot via the Pipeline Dictionary

Instances of SeekableIterator are returned in the API whenever a method returns mass data. Starting with API version 10.6, these iterators can only be iterated one time to avoid possible memory problems for large iterators. Putting them into the pipeline dictionary and trying to loop them multiple times is no longer possible because this approach would require buffering the iterated elements internally.

Previously, and for all customers still running API version 10.4 (compatibility mode), SeekableIterator instances stored in the pipeline dictionary could be iterated multiple times (for example, by several loop nodes).

Customer Impact: Check your code for instances of SeekableIterator and adjust as required.

Product Attributes Set At Site Level (No Release Note)

With Compatibility Mode 10.6, the product attributes onlineFlag, searchableFlag, searchPlacement, and searchRank are set at the site level. Previously they were set at global level.

APP-15381: Improved ProductAttributeModel Methods GetValue() and GetDisplayValue()

The getValue() and getDisplayValue() ProductAttributeModel methods now return a MediaFile instance if there’s a custom image attribute, or a MarkupText instance if there’s a custom HTML attribute. Previously, both methods returned the image path or the HTML source as a simple String.

Note: Compatibility mode 10.6 must be activated for your code version to take advantage of this functionality.

APP-12148: Inventory levels are now adjusted on order cancellation and order Replacement

For instances configured (via API versioning) to use the B2C Commerce API version 10.6 or later, inventory levels are now adjusted to reflect items from canceled or replaced orders. Previously, when an order was canceled or replaced, no change was made to inventory levels.

Example 1: If an order has 5 units of product X, when the order is canceled, the availability of product X increases by five units.

Example 2: Assume the following:

  • Order A has two units of X and three units of Y.
  • Order B has three units of X, one unit of Y, and five units of Z.

If order A is replaced by order B, then the number of units available changes: -1 units of X, +2 units of Y, and -5 units of Z

When replacing order A with order B, the inventory levels now reflect that the items in order A are available.

10.4

This behavior is the original behavior. You have this version or greater.