@arsel.sa/web-sdk 1.0.0
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 +56 -0
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/arsel.js +600 -0
- package/dist/arsel.js.map +1 -0
- package/dist/arsel.umd.cjs +2 -0
- package/dist/arsel.umd.cjs.map +1 -0
- package/dist/events.d.ts +23 -0
- package/dist/index.d.ts +81 -0
- package/dist/push.d.ts +39 -0
- package/dist/session.d.ts +21 -0
- package/dist/store.d.ts +52 -0
- package/dist/transport.d.ts +22 -0
- package/dist/types.d.ts +68 -0
- package/dist/version.d.ts +5 -0
- package/package.json +60 -0
- package/sw/arsel-sw.js +278 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@arsel.sa/web-sdk`. Format follows [Keep a Changelog](https://keepachangelog.com/),
|
|
4
|
+
versioning follows [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
Breaking changes to the public surface wait for a major release, and are listed here explicitly.
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [1.0.0] — 2026-08-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Events channel.** `track(name, properties)` with a durable IndexedDB queue: events are persisted
|
|
15
|
+
before they are sent, drain oldest-first in batches of up to 50 per request, stop at the first
|
|
16
|
+
retryable failure so history is never reordered, and discard permanent failures rather than
|
|
17
|
+
wedging the queue behind them — logging the response body when a drop carried identifiers.
|
|
18
|
+
Retries dedupe via persisted per-event idempotency keys and an `Idempotency-Key` request header.
|
|
19
|
+
Drains also trigger on `online` and on the tab becoming visible. Event properties pass through as
|
|
20
|
+
arbitrary nested JSON (`Date` → ISO string, non-JSON values dropped, 64 KB cap). `track()` calls
|
|
21
|
+
made before `init()` are buffered (up to 100) and enqueued, in order, when `init()` runs.
|
|
22
|
+
- **Identity.** `identify({ externalId, email, phoneNumber })` and `reset()`. `reset()` rotates the
|
|
23
|
+
anonymous id so a shared computer does not hand the next person the previous one's history.
|
|
24
|
+
`phoneNumber` is validated as E.164 and `email` for shape at the door — invalid values are
|
|
25
|
+
rejected with a console error instead of stored, so one bad identifier cannot poison every
|
|
26
|
+
subsequent event.
|
|
27
|
+
- **`optOut()`** — durable, server-side, non-resurrectable push opt-out for this browser, distinct
|
|
28
|
+
from `reset()`, which never touches push.
|
|
29
|
+
- **Sessions.** `arsel.session_start` / `arsel.session_end` from visibility transitions, with the
|
|
30
|
+
industry-standard 30-minute background gap and no timers. The end event is emitted on the next
|
|
31
|
+
visit, backdated to when the page actually went away. Sessions only open for pages actually seen —
|
|
32
|
+
background tabs and prerendered pages wait for their first visible transition.
|
|
33
|
+
- **Web push.** `promptForPush()`, opt-in service-worker registration (`serviceWorkerPath`, or
|
|
34
|
+
`serviceWorker: 'external'` for PWAs whose own worker imports arsel-sw.js — the SDK never
|
|
35
|
+
clobbers an existing worker), subscription registration carrying the `anonymousId` that binds the
|
|
36
|
+
subscription to the contact, and engagements (`delivered`, `displayed`, `suppressed`,
|
|
37
|
+
`opened`, `clicked`, `dismissed`) — exactly one per tap, with the post-tap programmatic close
|
|
38
|
+
never double-reported as a dismissal, and the `delivered` engagement raced against a short budget so
|
|
39
|
+
it can never delay display. Worker readiness is verified with bounded, actionable failures before
|
|
40
|
+
the permission prompt, never via a `.ready` that can hang forever.
|
|
41
|
+
- **Silent VAPID reconciliation** on `init()`: a browser subscribed under a rotated keypair
|
|
42
|
+
re-subscribes without prompting, instead of going quietly unreachable.
|
|
43
|
+
- **`pushsubscriptionchange` handling** in the service worker, for browser-initiated endpoint
|
|
44
|
+
rotation.
|
|
45
|
+
- `diagnostics()` — a support-ticket-safe snapshot containing no keys and no device secret.
|
|
46
|
+
- `flushNow()`, `getAnonymousId()`, `debug` mode.
|
|
47
|
+
- Every request carries `X-Arsel-SDK: web/<version>`.
|
|
48
|
+
- `baseUrl` may be plain `http://` for `localhost`/`127.0.0.1`, for local backends.
|
|
49
|
+
- ESM + UMD builds. The UMD build exposes named exports on `window.Arsel`.
|
|
50
|
+
|
|
51
|
+
### Notes
|
|
52
|
+
|
|
53
|
+
- The events API never depends on push. `track()` and `identify()` work with notifications denied,
|
|
54
|
+
blocked, or never requested.
|
|
55
|
+
- The publishable `pub_…` client key is page-readable by design. Origin allowlisting bounds the
|
|
56
|
+
residual risk. A secret API key must never appear in page source.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BasicsEngage (Arsel)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Arsel Web SDK
|
|
2
|
+
|
|
3
|
+
Events, identity and web push for the browser. ~4 kB gzipped, no dependencies, ESM + UMD.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import Arsel from '@arsel.sa/web-sdk';
|
|
7
|
+
|
|
8
|
+
await Arsel.init({ clientKey: 'pub_…', baseUrl: 'https://api.arsel.sa' });
|
|
9
|
+
|
|
10
|
+
Arsel.track('product.viewed', { sku: 'A-1023', price: 149.99 });
|
|
11
|
+
Arsel.identify({ externalId: user.id });
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Two channels, and only one of them needs push.** `track()` and `identify()` work with notifications
|
|
15
|
+
denied, blocked, or never asked for — a visitor who declines still has a contact and a behavioural
|
|
16
|
+
history. Only delivery needs a subscription. Nothing in the events API waits on the push API.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Documentation
|
|
21
|
+
|
|
22
|
+
| | |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| **[Quickstart](docs/quickstart.md)** | Install, initialize, and verify in about ten minutes. |
|
|
25
|
+
| **[Identity](docs/identity.md)** | Anonymous → identified, the identifier ladder, merges, `reset()`. |
|
|
26
|
+
| **[Events](docs/events.md)** | Custom events, properties, limits, reserved events, sessions, durability. |
|
|
27
|
+
| **[Web push](docs/web-push.md)** | Service worker, VAPID, permission UX, browser support, engagements. |
|
|
28
|
+
| **[API reference](docs/api-reference.md)** | Every method: signature, arguments, returns, when to call it. |
|
|
29
|
+
| **[Troubleshooting](docs/troubleshooting.md)** | Symptom → cause → fix, and the things that only look like bugs. |
|
|
30
|
+
| **[Data collection](docs/data-collection.md)** | What the SDK stores and sends, and what it never does. GDPR/erasure. |
|
|
31
|
+
| **[Migrating from CleverTap](docs/migrating-from-clevertap.md)** | API mapping, identity mapping, and the traps. |
|
|
32
|
+
| **[Changelog](CHANGELOG.md)** | Release notes. |
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
| | |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| Browsers | Chrome/Edge 79+, Firefox 72+, Safari 16.4+, and their mobile equivalents |
|
|
39
|
+
| Transport | Your **page** must be served over HTTPS for push (`http://localhost` is the browser's one exemption). The **API `baseUrl`** must be HTTPS too, except `http://localhost` / `http://127.0.0.1` for a local backend. |
|
|
40
|
+
| Bundlers | Any, or none — the UMD build works from a script tag |
|
|
41
|
+
| Runtime deps | None |
|
|
42
|
+
|
|
43
|
+
Push has a narrower support surface than events; see the matrix in
|
|
44
|
+
[docs/web-push.md](docs/web-push.md#browser-support).
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install @arsel.sa/web-sdk
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or from a script tag, which exposes the same surface on `window.Arsel`. unpkg and jsDelivr serve the
|
|
53
|
+
UMD build straight from npm — **pin the version**, and add an
|
|
54
|
+
[SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) hash so a
|
|
55
|
+
compromised CDN cannot run arbitrary script on your pages:
|
|
56
|
+
|
|
57
|
+
```html
|
|
58
|
+
<script src="https://unpkg.com/@arsel.sa/web-sdk@1.0.0/dist/arsel.umd.cjs"
|
|
59
|
+
integrity="sha384-…" crossorigin="anonymous"></script>
|
|
60
|
+
<script>Arsel.init({ clientKey: 'pub_…', baseUrl: 'https://api.arsel.sa' })</script>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or skip the third party altogether: copy `node_modules/@arsel.sa/web-sdk/dist/arsel.umd.cjs` into your
|
|
64
|
+
static assets and serve it from your own origin.
|
|
65
|
+
|
|
66
|
+
For push, also add **one file** to your site — see
|
|
67
|
+
[the service worker](docs/quickstart.md#3-add-the-service-worker).
|
|
68
|
+
|
|
69
|
+
## `clientKey` is publishable, and that is the design
|
|
70
|
+
|
|
71
|
+
It authenticates the event and push channels and grants nothing else — no reads, no contact list, none
|
|
72
|
+
of what a secret API key can do. Every vendor in this category does the same: Klaviyo's site ID,
|
|
73
|
+
CleverTap's Account ID, Braze's SDK key, Mixpanel's project token.
|
|
74
|
+
|
|
75
|
+
**Never put a secret API key in page source.** The residual risk on a publishable key is data
|
|
76
|
+
*integrity*, not confidentiality: someone who lifts it could post junk events. Origin allowlisting on
|
|
77
|
+
your org is what bounds that — a browser cannot forge its `Origin` header.
|
|
78
|
+
|
|
79
|
+
## Contributing
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm install
|
|
83
|
+
npm run typecheck # tsc --noEmit — the gate; there is no lint step
|
|
84
|
+
npm test # Vitest
|
|
85
|
+
npm run build # dist/arsel.js (ESM) + dist/arsel.umd.cjs
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT.
|