@returningai/widget-sdk 1.4.0 → 1.4.1

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,104 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@returningai/widget-sdk` are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ---
9
+
10
+ ## [Security Notice — 2026-05-11] Refresh-token TTL change for Access Key Embed
11
+
12
+ **This is a server-side change. No SDK code update is required. Customers do
13
+ not need to publish a new build of their host pages — the change applies
14
+ automatically the next time their users load the widget.**
15
+
16
+ ### What changed
17
+
18
+ The ReturningAI widget auth backend (`/auth/serverless`) now issues
19
+ **0-second-TTL refresh tokens** for Access Key Embed sessions (any auth
20
+ request that includes a signed `embedToken` in the body). The SDK persists
21
+ the refresh token with an already-expired `refreshTokenExpiry`, so on the
22
+ next page load `loadFromStorage` wipes it and the SDK re-calls
23
+ `/auth/serverless` for fresh `embedToken` validation.
24
+
25
+ Public Embed sessions (auth via `data-*` identifier attributes only, no
26
+ `embedToken`) keep the original 7-day refresh window — their identity
27
+ arrives from the host page on every load anyway, so caching the refresh
28
+ token doesn't change the security model.
29
+
30
+ In addition, refresh tokens **issued before this date are now rejected** by
31
+ `/auth/refresh`. Users with stored refresh tokens older than the cutoff
32
+ will see a one-time `/auth/serverless` re-auth on their next page load.
33
+ This is transparent provided their host page still supplies `embed-token`
34
+ (Access Key Embed) or `data-email` / configured identifier attrs (Public
35
+ Embed) — which is the normal embed state.
36
+
37
+ ### Why
38
+
39
+ In the previous behavior, a host page that:
40
+
41
+ 1. Initially loaded with `embed-token` + `data-email` (auth succeeded,
42
+ 7-day refresh token stored), and
43
+ 2. Later loaded without those attributes (e.g., the `embed-token` attribute
44
+ was removed or rotated)
45
+
46
+ ...would still authenticate as the original user via the cached refresh
47
+ token until that token's 7-day TTL expired. This conflicted with the
48
+ Access Key Embed promise that **every page load re-validates the embed
49
+ token**. A revoked or expired `embedToken` should immediately end the
50
+ session — not survive for up to a week in the user's browser.
51
+
52
+ ### Visible behavior changes
53
+
54
+ | Scenario | Before | After |
55
+ |---|---|---|
56
+ | First load with `embed-token` (valid claims) | 200, stores 7-day refresh token | 200, stores already-expired refresh token |
57
+ | Subsequent loads with `embed-token` still present | Used cached refresh token via `/auth/refresh` | Re-validates via `/auth/serverless` every load |
58
+ | Subsequent loads after `embed-token` is removed/changed | Continued working for up to 7 days (gap) | Re-auth required; fails closed if no identity is present |
59
+ | Public Embed loads (`data-email` only) | Unchanged | Unchanged |
60
+ | Users mid-session (in-memory access token) | Unchanged | Unchanged until access token expires (~5 min) |
61
+
62
+ ### Action required
63
+
64
+ **For most customers: none.** The change is backward-compatible with all
65
+ documented embed patterns. Your existing `<script>` / custom-element
66
+ embeds keep working with their pinned SDK version.
67
+
68
+ **Possible visible effect:** existing logged-in users may see a single
69
+ re-auth round-trip on their next page load (≈50–150 ms latency added).
70
+ After that, normal behavior resumes.
71
+
72
+ **If you're using Access Key Embed:** confirm your token-mint endpoint
73
+ calls `issueEmbedTokenService(accessId, accessKey, { /* identifiers */ })`
74
+ so the JWT carries `userIdentifiers` as a signed claim. With a correctly
75
+ signed token, no `data-*` attributes are needed on the embed tag and
76
+ re-auth on every load is transparent.
77
+
78
+ ---
79
+
80
+ ## [1.4.0] — 2026-05-02
81
+
82
+ ### Added
83
+ - Bundled lottie-web (light build) loader instead of runtime CDN fetch.
84
+ Eliminates dependency on `cdnjs.cloudflare.com` at runtime — works
85
+ offline and behind corporate proxies.
86
+ - `AnimationItem.destroy()` cleanup on `disconnectedCallback` to fix a
87
+ memory leak when widgets are repeatedly mounted/unmounted.
88
+ - `data-rai-widget-root` attribute on the mount container for easier
89
+ selection in tests and external CSS.
90
+
91
+ ### Changed
92
+ - Environment URLs (`api-url`, `widget-url`, `domain-key`, `v2-api-url`)
93
+ are now optional. The SDK resolves them from `domain-key` when present
94
+ and defaults to production otherwise. Existing embeds that explicitly
95
+ pass these attributes continue to work without modification.
96
+
97
+ ---
98
+
99
+ ## [1.3.0] — Server-signed identity (Access Key Embed) + security hardening
100
+
101
+ Introduced Access Key Embed mode — JWT `embedToken` carries signed
102
+ `userIdentifiers` claims. Server trusts token claims over body-level
103
+ identifiers. SDK clears storage on every load when `embed-token` is
104
+ present, forcing fresh `/auth/serverless` validation.
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Embed ReturningAI widgets on any website — React, Vue, Angular, or plain `<script>` tag. No external dependencies.
4
4
 
5
+ > 🛡️ **2026-05-11 security notice — refresh-token TTL for Access Key Embed.** The auth backend now issues 0-TTL refresh tokens for Access Key Embed sessions, and rejects refresh tokens issued before this date. **No SDK update required.** See [CHANGELOG.md](./CHANGELOG.md) for the full rationale and behavior changes.
6
+
5
7
  ---
6
8
 
7
9
  ## Quick Start
@@ -10,11 +12,11 @@ Your access credentials stay on your server. Your server exchanges them for a **
10
12
 
11
13
  **Step 1 — Create an access key pair** (one-time, from your dashboard):
12
14
 
13
- Go to **Community Settings > Integrations > SDK Access** and click **Create SDK Key**. Enter a name and optional allowed origins (required in production; localhost is auto-allowed in dev).
15
+ Go to **Community Settings > Integrations > SDK Access** and click **Create SDK Key**. Enter a name and the allowed origins for the sites that will embed the widget.
14
16
 
15
17
  The dashboard will display your `accessId` and `accessKey`. The `accessKey` is shown **once only** — save it securely.
16
18
 
17
- Store both values in your server environment variables.
19
+ Store both values securely on your server.
18
20
 
19
21
  > **Rotating or revoking keys:** The same dashboard page lists existing keys and lets you revoke or replace them. Revocation takes effect immediately for token issuance, and forces active sessions to re-auth on their next page load.
20
22
 
@@ -22,7 +24,7 @@ Store both values in your server environment variables.
22
24
 
23
25
  ```js
24
26
  // Runs on YOUR SERVER — never in the browser
25
- const response = await fetch('https://YOUR_API_URL/v2/api/widget-access-keys/token', {
27
+ const response = await fetch('https://api-v2.returning.ai/v2/api/widget-access-keys/token', {
26
28
  method: 'POST',
27
29
  headers: { 'Content-Type': 'application/json' },
28
30
  body: JSON.stringify({
@@ -56,7 +58,7 @@ const { data } = await response.json()
56
58
  ></script>
57
59
  ```
58
60
 
59
- `api-url` is optional. The SDK resolves the widget server from `domain-key` when provided and uses production by default; pass `api-url` only if you need to override the widget auth server.
61
+ The SDK uses ReturningAI endpoints by default. `api-url` is optional and only needed when you want to override the widget auth server.
60
62
 
61
63
  The server validates the token and extracts identity from its signed claims. If the token is expired, invalid, or its identifiers don't satisfy the widget's configured User Identifier Fields, the widget shows an error screen. Tokens expire after 15 minutes — regenerate on each page render.
62
64
 
@@ -87,7 +89,6 @@ Set the `data-widget-type` attribute to choose which widget to display. The Widg
87
89
  | `store` | Store / rewards widget |
88
90
  | `channel` | Channel widget |
89
91
  | `milestone` | Milestone widget |
90
- | `social` | Social widget |
91
92
  | `currency-view` | Currency widget |
92
93
  | `referral-conditions` | Referral widget |
93
94
  | `custom` | Custom widget |
@@ -122,19 +123,6 @@ All examples below use **Access Key Embed** (recommended) — identity is signed
122
123
 
123
124
  > **Note:** `YOUR_WIDGET_ID` for channel widgets is the base64-encoded channel ID — find it under **Community Settings > Channels** in your dashboard. Alternatively, use the [custom element approach](#framework-usage-custom-elements) with separate `community-id` and `channel-id` attributes.
124
125
 
125
- ### Social widget
126
-
127
- ```html
128
- <div id="returning-ai-widget-YOUR_WIDGET_ID" style="width:100%;height:600px"></div>
129
- <script src="https://unpkg.com/@returningai/widget-sdk/dist/rai-widget.iife.js"
130
- data-widget-id="YOUR_WIDGET_ID"
131
- data-widget-type="social"
132
- data-theme="dark"
133
- data-embed-token="eyJ..."
134
- widget-url="YOUR_WIDGET_URL"
135
- ></script>
136
- ```
137
-
138
126
  ### Milestone widget
139
127
 
140
128
  ```html
@@ -180,10 +168,9 @@ All attributes can be provided with or without the `data-` prefix — both work.
180
168
  |-----------|----------|---------|-------------|
181
169
  | `data-widget-id` | **Yes** | — | Your widget ID (from dashboard) |
182
170
  | `data-widget-type` | **Yes** | `store` | Widget type (see table above) |
183
- | `api-url` | No | Production widget server | Optional widget auth server override. Defaults from `domain-key` when provided |
171
+ | `api-url` | No | ReturningAI widget auth server | Optional widget auth server override |
184
172
  | `widget-url` | **Yes**\* | — | Widget URL (from dashboard). \*Not required when using `data-bundle-url` |
185
173
  | `data-bundle-url` | No | — | URL to the widget IIFE bundle — triggers [bundle mode](#bundle-mode) (non-iframe) |
186
- | `data-domain-key` | No | `PROD` | Environment key: `SGTR`, `STG`, or `PROD`. Used to resolve default environment URLs when overrides are omitted |
187
174
  | `data-theme` | No | `light` | `light` or `dark` |
188
175
  | `data-email` | Public Embed only | — | User's email for identification. **Access Key Embed:** omit — identity is signed into `data-embed-token` |
189
176
  | `data-embed-token` | Access Key Embed only | — | Short-lived JWT from your server. Carries signed user identifiers — no `data-*` identifier attributes needed |
@@ -193,7 +180,7 @@ All attributes can be provided with or without the `data-` prefix — both work.
193
180
  | `data-debug` | No | `false` | Verbose console logging |
194
181
  | `data-custom-data` | No | — | JSON object forwarded to the widget |
195
182
  | `data-retry-label` | No | `Retry` | Label text for the retry button on the error screen |
196
- | `data-v2-api-url` | No | Domain-key default | Optional V2 API override for bundle mode. Safe to omit for standard environments |
183
+ | `data-v2-api-url` | No | ReturningAI V2 API | Optional V2 API override for bundle mode |
197
184
 
198
185
  ### Custom element attributes
199
186
 
@@ -201,10 +188,9 @@ All attributes can be provided with or without the `data-` prefix — both work.
201
188
  |-----------|----------|---------|-------------|
202
189
  | `community-id` | **Yes**\* | — | Your community ID (raw ObjectId from dashboard). \*Custom widgets use `widget-id` instead |
203
190
  | `channel-id` | **Channel only** | — | Channel ID (raw ObjectId) — required for `<rai-channel-widget>` |
204
- | `api-url` | No | Production widget server | Optional widget auth server override. Defaults from `domain-key` when provided |
191
+ | `api-url` | No | ReturningAI widget auth server | Optional widget auth server override |
205
192
  | `widget-url` | **Yes**\* | — | Widget URL (from dashboard). \*Not required when using `bundle-url` |
206
193
  | `bundle-url` | No | — | URL to the widget IIFE bundle — triggers [bundle mode](#bundle-mode) (non-iframe) |
207
- | `domain-key` | No | `PROD` | Environment key: `SGTR`, `STG`, or `PROD`. Used to resolve default environment URLs when overrides are omitted |
208
194
  | `theme` | No | `light` | `light` or `dark` |
209
195
  | `data-email` | Public Embed only | — | User's email for identification. **Access Key Embed:** omit — identity is signed into `embed-token` |
210
196
  | `embed-token` | Access Key Embed only | — | Short-lived JWT from your server. Carries signed user identifiers — no `data-*` identifier attributes needed |
@@ -216,7 +202,7 @@ All attributes can be provided with or without the `data-` prefix — both work.
216
202
  | `debug` | No | `false` | Verbose console logging |
217
203
  | `custom-data` | No | — | JSON object forwarded to the widget |
218
204
  | `retry-label` | No | `Retry` | Label text for the retry button on the error screen |
219
- | `v2-api-url` | No | Domain-key default | Optional V2 API override for bundle mode. Safe to omit for standard environments |
205
+ | `v2-api-url` | No | ReturningAI V2 API | Optional V2 API override for bundle mode |
220
206
 
221
207
  > **`widget-id` vs `community-id`:** The script-tag method uses `data-widget-id` which is a pre-encoded identifier (base64). The custom element method uses raw ObjectIds — `community-id` for most widget types, plus `channel-id` for channel widgets. The SDK handles the encoding internally.
222
208
 
@@ -243,7 +229,7 @@ Custom elements don't need a container div — they size themselves using `width
243
229
  data-widget-type="store"
244
230
  data-email="user@example.com"
245
231
  data-user-id="12345"
246
- data-account-id="abc"
232
+ data-member-id="abc"
247
233
  widget-url="YOUR_WIDGET_URL"
248
234
  ></script>
249
235
  ```
@@ -252,16 +238,28 @@ In Public Embed mode, any `data-*` attribute not reserved by the SDK is forwarde
252
238
 
253
239
  ---
254
240
 
241
+ ## Endpoint URL Overrides
242
+
243
+ The SDK uses ReturningAI endpoints by default.
244
+
245
+ These fields are optional. Set them only when you need to override the default endpoints:
246
+
247
+ - `api-url` / `data-api-url` — overrides the widget auth server used for SDK auth, refresh, logout, and error settings.
248
+ - `v2-api-url` / `data-v2-api-url` — overrides the V2 API base URL used by bundle mode.
249
+
250
+ These endpoint overrides do not replace `widget-url` or `bundle-url`; use the widget and bundle URLs from your dashboard.
251
+
252
+ ---
253
+
255
254
  ## Bundle Mode
256
255
 
257
256
  When you set the `bundle-url` attribute, the widget renders directly in the page DOM instead of inside an iframe. This gives full CSS cascade — `html[data-theme]` and Tailwind classes apply to the widget content naturally.
258
257
 
259
258
  - `widget-url` is **not** needed in bundle mode (the widget is loaded directly from `bundle-url`).
260
- - `api-url` is optional. The SDK resolves the widget auth server from `domain-key` when provided, or defaults to production.
261
- - `domain-key` is optional. When omitted, the SDK defaults to production (`PROD`).
262
- - Environment URL variables such as `window.api_url` are optional overrides. Standard `SGTR`, `STG`, and `PROD` environments resolve from `domain-key`.
259
+ - ReturningAI endpoints are used by default.
260
+ - `api-url` and `v2-api-url` are optional endpoint URL overrides.
263
261
 
264
- Both examples below use Access Key Embed and target staging. Omit `domain-key` for production.
262
+ Both examples below use Access Key Embed and the default endpoints.
265
263
 
266
264
  ```html
267
265
  <!-- Script-tag approach -->
@@ -272,7 +270,6 @@ Both examples below use Access Key Embed and target staging. Omit `domain-key` f
272
270
  data-theme="dark"
273
271
  data-embed-token="eyJ..."
274
272
  data-bundle-url="YOUR_BUNDLE_URL"
275
- data-domain-key="STG"
276
273
  data-eager
277
274
  ></script>
278
275
 
@@ -280,7 +277,6 @@ Both examples below use Access Key Embed and target staging. Omit `domain-key` f
280
277
  <rai-store-widget
281
278
  community-id="YOUR_COMMUNITY_ID"
282
279
  bundle-url="YOUR_BUNDLE_URL"
283
- domain-key="STG"
284
280
  embed-token="eyJ..."
285
281
  theme="dark"
286
282
  width="100%"
@@ -295,7 +291,6 @@ Each widget type has its own IIFE bundle and global name:
295
291
  |-------------|--------------|-------------------|
296
292
  | `store` | `RaiStoreWidget` | `<rai-store-widget>` |
297
293
  | `channel` | `RaiChannelWidget` | `<rai-channel-widget>` |
298
- | `social` | `RaiSocialWidget` | `<rai-social-widget>` |
299
294
  | `milestone` | `RaiMilestoneWidget` | `<rai-milestone-widget>` |
300
295
  | `currency-view` | `RaiCurrencyWidget` | `<rai-currency-widget>` |
301
296
  | `referral-conditions` | `RaiReferralWidget` | `<rai-referral-widget>` |
@@ -429,7 +424,6 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
429
424
  | `<rai-store-widget>` | `community-id` | Store |
430
425
  | `<rai-channel-widget>` | `community-id` + `channel-id` | Channel |
431
426
  | `<rai-milestone-widget>` | `community-id` | Milestone |
432
- | `<rai-social-widget>` | `community-id` | Social |
433
427
  | `<rai-currency-widget>` | `community-id` | Currency |
434
428
  | `<rai-referral-widget>` | `community-id` | Referral |
435
429
  | `<rai-custom-widget>` | `widget-id` (not `community-id`) | Custom |