npm package: @mabarri/hosted-fields-sdk
Description: ## Installation
Latest version: 2.3.1

# SDK

## Installation

### ESM (ES Modules)

```bash
npm i @mabarri/hosted-fields-sdk
```

### IIFE (Immediately Invoked Function Expression)

Include via CDN:

```html
<script src="https://unpkg.com/@mabarri/hosted-fields-sdk"></script>
```

or

```html
<script src="https://cdn.jsdelivr.net/npm/@mabarri/hosted-fields-sdk"></script>
```

### UMD (Universal Module Definition)

Include via CDN with latest version:

```html
<script src="https://unpkg.com/@mabarri/hosted-fields-sdk/dist/index.umd.js"></script>
```

or

```html
<script src="https://cdn.jsdelivr.net/npm/@mabarri/hosted-fields-sdk/dist/index.umd.js"></script>
```

For a specific version just specify the version in the link */@mabarri/**hosted-fields-sdk**/dist* -> */@mabarri/**hosted-fields-sdk@2.2.0**/dist*

## Usage

After installation, you can import and use the SDK:

```javascript
import LwHostedFields from '@mabarri/hosted-fields-sdk';

// Initialize and configure the SDK
const hostedFields = new LwHostedFields({
  // your configuration
});

// Mount the hosted fields
hostedFields.mount();
```

---

The SDK is a library, we cannot "run" a library. However this `sdk` project has 2 parts

- the library in [src](./src/) folder
- several small demo applications which use the sdk in [tests/e2e/pages](./tests/e2e/pages/) folder

When we run this SDK project, in fact we run these small demo applications.
When we build this project, only the SDK is built, these small demo applications won't be included in the bundle or deployed anywhere.

## Dev mode `pnpm dev`

This will run the vite DevServer which serve 2 things

- serve all the demo examples in the [tests/e2e/pages](./tests/e2e/pages/) folder. For eg: <http://localhost:5301/tests/e2e/pages/complete/>
- serve a complied version of the SDK in the `iife` format at <http://localhost:5301/dist/@lw/hosted-fields-sdk.iife.js>, so that the [Playground](../docs/playground/) can use the SDK from there.

The demo examples allow us to test the SDK each time we made changes. It can also be used for e2e tests. We use the playwright framework to play with them.

## Bundle `pnpm build`

- This command will bundle the SDK in 3 different formats: ESM, IIFE, UMD (checkout the [Cookbook](../docs/cookbook/public/articles/bundle.md) for more detail)
- Only the SDK is built, the Demo examples won't be included in the bundle.

## Dependencies

The SDK application requires to know the location of the iframe application. There are 2 ways to tell the SDK where the IFRAME is:

- In Build time: set the env. var. `VITE_IFRAME_URL` before building the SDK application.
- In Run time: consumer set the SDK configuration: `iframeUrl` which will override the value `VITE_IFRAME_URL` we gave to the SDK in Build time.
  - This configuration is not mentioned in the Cookbook because the partner would not need it.
  - The `iframeUrl` option exist to offer Lemonway the possibility to configure this dependency in Run time.
  - Today the SDK is smart and capable of auto-discover the `iframeUrl` (see below)

### Auto discovery (or dependencies auto-resolving)

If nobody tell the SDK where is the IFRAME application, it will try to figure out the IFRAME_URL by itself in run time.

In preview mode and production mode, the SDK application and the IFRAME application are deployed side by side as following:

```text
/root
  /sdk
    /@lw
      sdk.js   ==> the SDK got this location with `import.meta.url` or `document.currentScript.src`
  /iframe
    index.html ==> the SDK can infer this location with '../../iframe/index.html'
```

This "auto discovery" logic only works if the IFRAME_URL and the SDK_URL are relative to each other respecting the above structure.

One day, if Lemonway decides to split the IFRAME and the SDK to 2 different servers then the auto-discovery would break. In this case, Lemonway can use the `iframeUrl` option to configure this dependency in Run time.

## SDK Manifest file

Both `pnpm dev` and `pnpm build` will generate a `manifest.json` file. It contains the exact name of the compiled SDK and the Subresource integrity (SRI). If we know the location of this `manifest.json` we can fetch its content

- to know the SRI
- and to deduce the location of the compiled SDK.

Some applications (the Cookbook and Playground) do this eventually. They requires the location of this `manifest.json` file, fetch the content and deduce these 2 information.

### Known issue

Sometime the `manifest.json` is not well generated. It happens randomly in *Dev mode* only, you will have to manually fix the `manifest.json`. The reason is unknown, it might be a bug of vite or of VSCode, prettify, auto-save.. We won't have this problem in *Preview mode* or *Production mode*.

![manifest.json](https://user-images.githubusercontent.com/1638594/235326862-cded0f24-f641-4505-8598-88553fd1305e.png)

## How to watch a specific unit test

```sh
npx vitest -t "findParentForm case 1"
```

A VSCode extension will help you to do it as well

## Why Svelte?

The SDK needs to create several "iframe components" and mount them to the corresponding Container elements. An "iframe component" accepts a config object as props, and has several responsibilities:

- it coordinates the "focus-trap" inside and outside the iframe (there are some "div" inside and outside the iframe to trap the focus changes which needs to be coordinated cross-domain).
- it tracks the internal state of the iframe.
- it forwards cross-domain events from inside the iframe to the outside container.

We could certainly create this component in vanilla JS. However a component base framework will make the task easier.

[Svelte] is chosen because it is just a compiler, it won't increase the size of the final bundle, unlike other framework ([VueJS], [React]...). Currently, with [Svelte], **the SDK size is around 10kB** (minify+gzip). The JavaScript you would write shouldn't much different from (or even worst than) the JavaScript generated by the Svelte compiler. Note: it is what the Svelte team tried to sell, we might not trust them, although it is true that there is actually no trace of Svelte in the compiled version of the SDK.

If we used [VueJS], then a "Hello world" component (without any of our codes) would be **at least 16kB** (minify+gzip), this size will only increase as we would use more [VueJS] features. [Ref. Vue FAQ](https://vuejs.org/about/faq.html#is-vue-lightweight)

[SolidJS] is another compiler we had taken into consideration. Similar to [Svelte], it won't increase the bundle size. At the moment of test (Feb 2023), the [Svelte] compiler had appeared to produce smaller JavaScript codes than the [SolidJS] compiler; not by much, but still better for us, so [Svelte] was chosen.

Note:

1. Smaller bundle size doesn't mean more optimize or more performance.
2. The comparison tests is removed because it is obsolete now. Our SDK implementation was evolved, both the [Svelte], and [SolidJS] compiler are evolved as well.
3. The current choice ([Svelte]) has also some down sides:
    - it makes the project setup more complex.
    - one more framework to be learned by maintainers.
    - The SDK is caught in the crossfire of the "frontend frameworks war". Any justification, no matter how valid, may be met with resistance from anti-Svelte fans or die-hard fans of other frameworks like VueJS, who may refuse to evolve and learn other alternatives.
    - necessity of this useless section in the `README.md`

=> The choice to remove Svelte is completely a valid choice depends on the culture of the team.

### Update May 2025: Why not Svelte?

Svelte 5 is released, and it is not very suistable to our use case which only want to use the compiler part, not the full framework.
By consequence, the SDK will stay with Svelte 4 forever, many packages must not be updated to avoid breaking the Svelte 4 compatibility.

For the long run we should remove Svelte 4, replace it with **vanilla typescript**. In fact, our use case doesn't benefit much from Svelte, it is perfectly fine to remove it.

## Future direction to be considered

In the future, the Hosted Field SDK should be published as a Set of [WebComponents](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) such as `<CardNumber>`, `<CardHolderName>`... similar to the GooglePay or ApplePay button:

- No mounting
- Web Component are standard and can be integrated into any rendering framework on partner side (React, Vue, Solid, Astro...)

[Svelte]: https://svelte.dev/
[SolidJS]: https://www.solidjs.com/
[VueJS]: https://vuejs.org/
[React]: https://react.dev/