# esales-api

> [Read the section below][to-v3] for info on upgrading from v2 to v3.

> This version of the library will only work with Elevate 4 Storefront API v3.
> Support for Elevate API v2 is limited to `v1.x.x` of this package. For
> information about upgrading to the `v2` version, see [the upgrade section][to-v2]

A helper library for making requests to the [Elevate Storefront API v3][s-api-3].
It includes type definitions for all HTTPS responses and the library API.


## Requirements

Install the package from npm:

```
npm install @apptus/esales-api
```

* Supports Browsers, Deno and Node v18+ by using `globalThis.fetch()`
  to send requests cross-platform
* Ships code bundled into in ESM and CJS format
* Ships with modern ES2022 code - tooling like `esbuild` can be used
  to support older platforms/environments ([see tooling](#tooling))
* [See polyfills](#polyfills) for required global API's


## Usage

The full API and all options/return-values are described by the Typescript
definitions (`dist/mod.d.ts`) that is bundled with this library.

```ts
import { elevate } from '@apptus/esales-api';


const api = elevate({
  market: 'GB',
  locale: 'en-GB',
  clusterId: '<ID>',
  touchpoint: 'desktop',
  session: () => ({ customerKey: '<UUID>', sessionKey: '<UUID>' })
});

async function main() {
  const result = await api.query.searchPage({ q: 'jeans', limit: 60 });
  // Use the search result
}

main().catch(err => console.warn(err));
```

A `CHANGELOG.md` is included in the package, but npm can't show
individual files from a package online. The changelog can be read
on e.g. [esm.sh][esm.sh] or [unpkg.com][unpkg], or any other npm mirror.


## Upgrading

### From v2 to v3

The `CHANGELOG.md` includes the full list of changes. For integrators
using this package, the changes listed below are required when upgrading
to version `3.0.0` of the package:

- A new property `session` is now required when initializing the API.
  Prior to v3, session information was automatically handled via
  `LocalStorage`. The same behavior as before can be achieved via the
  method `localStorageBackedSession()`.
  ```ts
  // Before
  import { esales } from '@apptus/esales-api';

  const api = esales({
    clusterId: 'wABCD1234',
    market: 'UK',
    locale: 'en-GB',
    touchpoint: 'desktop'
  });

  // After
  import { esales, localStorageBackedSession } from '@apptus/esales-api';

  const api = esales({
    clusterId: 'wABCD1234',
    market: 'UK',
    locale: 'en-GB',
    touchpoint: 'desktop',
    session: localStorageBackedSession()
  });
  ```
- The `session` property on the configured API object has been
  removed. Functionality related to reading/updating session metadata
  to `LocalStorage` can be found on the object returned by
  `localStorageBackedSession()`.

  ```ts
  // Before
  const api = esales({ ... });
  api.session.sessionKey;
  api.session.customerKey;
  api.session.customerKey = user.id;
  api.session.reset();

  // After
  const session = localStorageBackedSession();
  const { customerKey, sessionKey } = session();
  session.updateCustomerKey(user.id);
  session.reset();
  ```
- All `esales().notify.*` methods are now returning promises, and should
  thus be handled to avoid uncaught promises. Previously, these POST messages
  were sent via `Navigator.sendBeacon()`. This has been replaced with `fetch()`
  with the `keepalive` flag, to make the library supported cross platform.
  ```ts
  // Before
  try {
    api.notify.click();
  } catch {
    // failed to queue POST request with notification
  }

  // After
  await api.notify.click().catch(() => {});
  // to ignore errors, or:
  try {
    await api.notify.click();
  } catch {
    // Network error or a non-OK HTTP status code
  }
  ```


### From v1 to v2

The `CHANGELOG.md` includes the full list of changes. For integrators
using this package, the changes listed below are required when upgrading
to version `2.0.0` of the package:

- A new property `locale`, must be added to the API initialization.
  This field should be one of the locales that is used together with
  `market` when importing products with the Admin API.
  ```ts
  // Before
  const api = esales({ ..., market: 'SE' });

  // After
  const api = esales({ ..., market: 'SE', locale: 'sv-SE' });
  ```
- Rename the paramater `pageId` to `pageReference`, for the `query.landingPage()`
  request.
  ```ts
  const api = esales(options);

  // Before
  api.query.landingPage({ ...params, pageId: id });

  // After
  api.query.landingPage({ ...params, pageReference: id });
  ```
- Change `webApiId` to `clusterId` for initialization configuration.
  ```ts
  // Before
  const api = esales({ ..., webApiId: 'w00000000' });

  // After
  const api = esales({ ..., clusterId: 'w00000000' });
  ```

We've also cleaned up the public API surface of the package slightly,
by removing some internal/private features. There should not be any
reason for using them, and thus should not affect upgrades:

- Removed `@apptus/esales-api/mock` submodule. It exposed some helper functions
  for creating mocked objects of API responses.
- Removed `api.query.settings()` method, which used a private/undocumented
  API endpoint
- Removed `webApiUrl`. It's possible to provide a URL to `clusterId`
  if necessary. Any Integrators should prefer using an ID over URL for `clusterId`. When providing a URL to `clusterId` there should not be
  a `/api/v2/` suffix, but instead simply end the path with `'/'` or `''`.


## Future work

This library is in active development. Highest on the agenda:

* Open source the repository on Github
* Make `CHANGELOG.md` more accessible (currently included in NPM package)


## Tooling

This library is packaged as an ES Module with zero dependencies.
This requires the use of a pre-processor step since bare-imports are not natively
supported in browsers ([without import maps](https://github.com/WICG/import-maps)),
but most build tools should handle this.

Additionally, in order to ship smallest possible bundle, the code is using a
modern `ES2022` syntax. This may not work with the desired browser support
out of the box, and will likely [require transpiling before use](#transpilation).


### Transpilation

An example of how to transpile this library when building with Webpack is shown
below. Something similar can be done with Rollup by using the `include` property with
[`@rollup/babel-plugin`](https://github.com/rollup/plugins/tree/master/packages/babel).

```js
// webpack.config.js
const { resolve } = require('path');

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        type: 'javascript/auto',
        include: [resolve(__dirname, 'node_modules/@apptus/esales-api')],
        use: ['babel-loader']
      }
    ]
  }
};
```


### Polyfills

Depending on the level of required browser support, polyfills may need to be
included before using this library. It is assumed that the following API's are available:

* All `ES2015` API's
* `globalThis.fetch`
* `globalThis.URL`
* `globalThis.crypto.randomUUID()` (only when `localStorageBackedSession()` is used)
* `Object.entries`
* `Object.values`


## License 

MIT


[esm.sh]: https://esm.sh/@apptus/esales-api/CHANGELOG.md
[unpkg]: https://unpkg.com/browse/@apptus/esales-api/CHANGELOG.md
[s-api-3]: https://docs.elevate.voyado.cloud/elevate/4/integration/api/specifications/storefront/v3/
[to-v2]: #from-v1-to-v2
[to-v3]: #from-v2-to-v3
