npm package: @prelude.so/js-sdk
Description: Prelude Web SDK
Author: Prelude
Latest version: 0.7.1

# @prelude.so/js-sdk

Prelude's web SDK.

## Installation

```bash
npm install @prelude.so/js-sdk
```

This package contains several entrypoints (from the `package.json` file's `exports` field):

```JSON
".": {
  "types": "./dist/types/index.d.ts",
  "default": "./dist/inline/index.js"
},
"./slim": {
  "types": "./dist/types/index.d.ts",
  "default": "./dist/slim/index.js"
},
"./signals": {
  "types": "./dist/types/signals/index.d.ts",
  "default": "./dist/inline/signals.js"
},
"./signals/slim": {
  "types": "./dist/types/signals/index.d.ts",
  "default": "./dist/slim/signals.js"
},
"./session": {
  "types": "./dist/types/session/index.d.ts",
  "default": "./dist/inline/session.js"
},
"./session/slim": {
  "types": "./dist/types/session/index.d.ts",
  "default": "./dist/slim/session.js"
}
```

You can either import from the default `@prelude.so/js-sdk` entrypoint, or use the following:
- `@prelude.so/js-sdk/session`: the session SDK client. Useful to use Prelude's session core API to authenticate your apps.
- `@prelude.so/js-sdk/signals`: minimum library to dispatch browser signals to Prelude's platform while using our SDKs.

**This package contains **wasm** code**
In the default entrypoints, the **wasm** is inlined in the javascript file as a base64 data url.
If you want to optimize your bundle size, you can use the **slim** version of the entrypoints (check previous code block) instead of the inline ones.
This require further configuration, please refer to specific comments in the next section.

## Configuration

`@prelude.so/js-sdk` contains a web worker and `.wasm` code. This means if you are developping a bundled web app, you'll need some setup steps to make it work. This section explains those steps for different bundlers.

### Vite & Vitest

Here's an example config with comments to explain the configuration:

```javascript
{
  // If you're using a `/slim` entrypoint,
  // then you'll have to copy the `.wasm` core as a static asset in your bundle.
  assetsInclude: ["./node_modules/@prelude.so/**/*.wasm"],
  // Vite dev server config
  optimizeDeps: {
    // @prelude.so/js-sdk uses a web worker. Vite dev server does not handle optimization of web worker files.
    exclude: ["@prelude.so/js-sdk"],
    // As per Vite's docs, a commonJS sub dependency of a dependency should be optimized.
    include: ["@prelude.so/js-sdk > browser-tabs-lock"],
  },
  // Vitest config
  test: {
    // @prelude.so/js-sdk should only be used in browser like environments.
    environment: "jsdom",
    // If you're using a slim @prelude.so/js-sdk entrypoint,
    // in vitest it's better to resolve the inline one to avoid any issue with the `.wasm` asset.
    // This example config is aliasing all 3 entrypoints, but you can keep only the ones you need.
    alias: {
      "@prelude.so/js-sdk/slim": "@prelude.so/js-sdk",
      "@prelude.so/js-sdk/session/slim": "@prelude.so/js-sdk/session",
      "@prelude.so/js-sdk/signals/slim": "@prelude.so/js-sdk/signals",
    },
  },
}
```

### esbuild

To include the web worker in your bundle, you can use [@chialab/esbuild-plugin-meta-url](npmjs.com/package/@chialab/esbuild-plugin-meta-url):

```javascript
import metaUrlPlugin from "@chialab/esbuild-plugin-meta-url";
import * as esbuild from "esbuild";

await esbuild.build({
  // your config
  loader: {
    // your loaders
    //
    // If you're using a `/slim` entrypoint,
    // then you'll have to copy the `.wasm` core as a static asset in your bundle.
    ".wasm": "file",
  },
  plugins: [
    // This will recognize the worker file in @prelude.so/js-sdk as an entrypoint and bundle it
    metaUrlPlugin(),
    // your plugins
  ],
  // your config
})
```

### webpack

Here's how to configure webpack to copy the `.wasm` asset in your bundle:

```javascript
module.exports = {
  // your config
  module: {
    rules: [
      // your rules
      // If you're using a `/slim` entrypoint, then you'll have to copy the `.wasm` core as a static asset in your bundle.
      {
        test: /\.wasm$/,
        include: [path.resolve(__dirname, "node_modules/@prelude.so/core")],
        type: "asset/resource",
      },
      //  your rules
    ],
  },
  // your config
}
```

### Next.js

> Make sure to use the `"use client";` directive in the components using the Prelude JS SDK.

Turbopack does not offer enough WASM loading capabilities to use the /slim entrypoint yet, so if you're using Turbopack to build, you should use the default entrypoint, without anything to configure.

If you're building your next app with webpack, here's how to configure your next config to use the slim entrypoint:

```javascript
import type { NextConfig } from "next";
import path from "node:path";

const nextConfig: NextConfig = {
  webpack: (config) => {
    config.module.rules.push(
      // If you're using a `/slim` entrypoint, then you'll have to copy the `.wasm` core as a static asset in your bundle.
      {
        test: /\.wasm$/,
        include: [path.resolve(__dirname, "node_modules/@prelude.so/core")],
        type: "asset/resource",
      },
    );

    return config;
  },
};

export default nextConfig;
```

## How to use

### Session client initialization

```javascript
import { PrldSessionClient } from "@prelude.so/js-sdk/session";

const client = new PrldSessionClient({
  appId: "<your-prelude-session-app-id>",
  sdkKey: "<your-sdk-key>" // To automatically dispatch device signals upon login
});
```

### Signals dispatch

> Note: if you're using the session client with your SDK key configured you don't need to call this.

```javascript
import { dispatchSignals } from "@prelude.so/js-sdk/signals";

await const dispatchId = dispatchSignals(<your-prelude-sdk-key>);
```

### Silent verification

The Silent Verification feature allows you to verify a phone number without requiring the user to enter a verification code. It is available for certain carriers and requires a server-side service to handle the verification process.

The SDK provides a simple API to initiate the verification process and handle the response.

We assume here that you have a server-side service that exposes the 2 endpoints, one to start the verification process (`/verify`) and another to check the final code (`/verification_check`).

With this set up, the process would be as follows:

- Call the `dispatchSignals` SDK function indicating that you want to enable the Silent Verification feature if available:

```
// Add the client side imports according to the version of the SDK and framework that you are using
import { performSilentVerification } from "@prelude.so/js-sdk";
import { dispatchSignals, Features } from "@prelude.so/js-sdk/signals";
...
const dispatchId = await dispatchSignals("YOUR_SDK_KEY", { implementedFeatures: [Features.SilentVerification] });
...
```

This will collect the browser signals and report them to Prelude from the user's browser.

- Call your `/verify` endpoint from the Javascript code passing the `dispatchId` received in the previous call and the user's phone number. The `/verify` endpoint should use Prelude's backend SDK for your platform and the response should be forwarded to the client browser. If Silent Verification is enabled and supported for the phone number you may receive a `"method": "silent"`, with a `request_url` parameters in the response.

```
...
// This '/verify' endpoint is part of your own backend API. Adapt it to your needs.
verificationResponse = await fetch(
  '/verify',
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      to: phoneNumber,
      dispatch_id: dispatchId
    })
  }
);

const responseContent = await verificationResponse.json();

if (responseContent["method"] === "silent") {
  // The Silent Verification process can continue
  ...
} else {
  // The user will receive a code (SMS, ...) and will need to enter the code manually
  ...
}

```

- If the `silent` method is available you now need to pass the received URL to the SDK to continue:

```
...
if (responseContent["method"] === "silent") {
  const request_url = responseContent["request_url"]
  const verificationCode = await performSilentVerification(request_url);
  ...
```

- The final step is to check the verification code, either because it was received via the Silent Verification method or because the user typed it from the SMS received.

```
// As before, the '/verification_check' endpoint is part of your backend API. Adjust it accordingly.
const checkResponse = await fetch(
  "/verification_check,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      to: phoneNumber,
      code: verificationCode
    })
  }
);
```

- Your backend then will check with Prelude to verify that the code is correct or not and you can continue the onboarding accordingly.

You can read more about the Silent Verification feature at https://docs.prelude.so/verify/silent/overview