@soliton-id/web-sdk 1.0.0 → 1.0.2

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +127 -40
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,37 @@ All notable changes to `@soliton-id/web-sdk`. The `soliton-v1` postMessage
4
4
  protocol is frozen: changes are additive only, so older SDK versions keep
5
5
  working against the hosted flow.
6
6
 
7
+ ## 1.0.2 — 2026-08-06
8
+
9
+ Documentation only. No runtime, API, or bundle changes; `soliton-v1` is
10
+ unchanged and `1.0.0`/`1.0.1` remain fully compatible.
11
+
12
+ - Reframed `sk_test_` as the **sandbox environment** rather than a
13
+ fixtures-only mode. A sandbox credential now runs real captures; the
14
+ deterministic `pass` / `fail` / `partial` fixtures remain available and
15
+ remain sandbox-only. `sk_live_` still cannot request a fixture.
16
+ - Documented that redirect domains, iframe origins, and webhook endpoints are
17
+ registered per environment, so a staging origin can embed sandbox links
18
+ without being able to embed production ones, and each environment's webhook
19
+ has its own signing secret.
20
+ - Documented the additive `environment` field on the create response, every
21
+ status read, and every webhook payload.
22
+
23
+ ## 1.0.1 — 2026-08-02
24
+
25
+ Documentation only. No runtime, API, or bundle changes; `soliton-v1` is
26
+ unchanged and `1.0.0` remains fully compatible. Published because npm's
27
+ `1.0.0` README is immutable and described test keys incorrectly.
28
+
29
+ - Rewrote the test-key section: `sk_test_` credentials now produce
30
+ deterministic synthetic fixtures (`pass` / `fail` / `partial`) that never
31
+ open the camera, rather than running the same real capture pipeline as
32
+ `sk_live_`. Documented the scenario/verdict mapping and the strict
33
+ live/test read isolation.
34
+ - Documented completion webhooks as a polling alternative, and corrected the
35
+ iframe-origin, CSP, and `Permissions-Policy` guidance to describe the
36
+ iframe's direct-parent origin and nested frame chains.
37
+
7
38
  ## 1.0.0 — 2026-08-01
8
39
 
9
40
  First public release.
package/README.md CHANGED
@@ -92,7 +92,7 @@ BACKEND with your API key:
92
92
  user, selected server-side from the capture under neutral lighting.
93
93
  Returns 404 until the verification is complete or when no acceptable
94
94
  portrait frame existed. Right after completion, `portrait_available` can
95
- briefly read `false` while extraction finishes; once status is `complete`
95
+ briefly read `false` while extraction finishes; once status is `completed`
96
96
  just fetch the portrait and treat a 404 after one short retry as final.
97
97
 
98
98
  Your page and the SDK never see the verdict or the portrait: callbacks and
@@ -120,29 +120,55 @@ creation and check it on every status read to make this auditable.
120
120
 
121
121
  Embedding is off by default and gated on BOTH layers:
122
122
 
123
- 1. Your API key must have the exact origins of the pages that will embed the
124
- flow registered (scheme + host + port, e.g. `https://app.example.com`).
125
- Ask us to register yours.
126
- 2. The same origins must be present in the soliton.id deploy-time frame
127
- ancestors allowlist (we handle this when we register your key).
128
-
129
- A verification link opened inside an iframe on any other origin refuses to
130
- start and reports `origin_not_allowed`.
123
+ 1. Your Soliton account must have the exact origin of each page that runs the
124
+ SDK and directly contains its Soliton iframe registered (scheme + host +
125
+ port, e.g. `https://app.example.com`), **for the environment that will open
126
+ the link**. This direct-parent page does not have to be the browser's
127
+ top-level page. A link is checked against the origins registered for the
128
+ environment of the key that created it, so `https://dev.example.com` can be
129
+ a sandbox embedder without becoming a production one.
130
+ 2. The direct-parent origin must also be present in the soliton.id deploy-time
131
+ `frame-ancestors` allowlist. If the SDK page is itself framed, every origin
132
+ above it in the frame chain must be present there too (we manage this
133
+ allowlist). This layer is one list for the whole deployment and is not per
134
+ environment; the per-environment precision comes from layer 1.
135
+
136
+ A verification link opened inside an iframe with any other direct-parent
137
+ origin refuses to start and reports `origin_not_allowed`.
131
138
 
132
139
  During the invite-only pilot, Soliton manually manages both layers. Send your
133
- Soliton contact every exact production, staging, and local origin before
134
- testing. Wildcards are not accepted, and adding or changing an origin can
140
+ Soliton contact every exact production and local direct-parent origin before
141
+ testing. Include a staging origin only when Soliton has supplied a working
142
+ staging flow URL. For a nested integration, also send every other ancestor
143
+ origin. Wildcards are not accepted, and adding or changing an origin can
135
144
  require a Soliton deployment.
136
145
 
146
+ Register the direct-parent page's origin, not a URL path. For example,
147
+ `https://app.example.com` and `https://app.example.com:8443` are different
148
+ origins; `/verify`, a query string, and a trailing slash are not part of the
149
+ value you send us. Redirect-domain registration and iframe-origin registration
150
+ are separate: enabling one does not enable the other.
151
+
137
152
  ## Customer security headers
138
153
 
139
- If your embedding page sends restrictive response headers, merge these
140
- sources into its existing policies (do not replace the rest of your policy
141
- with this example):
154
+ Content Security Policy (CSP) is the browser response header that controls
155
+ which sources a page may load. If the page that runs the SDK sends restrictive
156
+ security headers, merge the Soliton sources into its existing policies; do not
157
+ replace the rest of your policy with these minimal examples.
158
+
159
+ When you bundle the npm package:
160
+
161
+ ```text
162
+ Content-Security-Policy: frame-src https://soliton.id
163
+ Permissions-Policy: camera=(self "https://soliton.id"), microphone=(self "https://soliton.id")
164
+ ```
165
+
166
+ When you load the classic CDN script or hosted ESM build, the remote script
167
+ also needs to be allowed:
142
168
 
143
169
  ```text
144
- Content-Security-Policy: frame-src https://soliton.id https://staging.soliton.id; script-src https://soliton.id https://staging.soliton.id
145
- Permissions-Policy: camera=(self "https://soliton.id" "https://staging.soliton.id"), microphone=(self "https://soliton.id" "https://staging.soliton.id")
170
+ Content-Security-Policy: frame-src https://soliton.id; script-src https://soliton.id
171
+ Permissions-Policy: camera=(self "https://soliton.id"), microphone=(self "https://soliton.id")
146
172
  ```
147
173
 
148
174
  - `frame-src` must include the Soliton origin you use because the capture flow
@@ -150,31 +176,92 @@ Permissions-Policy: camera=(self "https://soliton.id" "https://staging.soliton.i
150
176
  - `script-src` must include the Soliton origin you use only for the classic
151
177
  script or hosted ESM distribution. It is not needed when your application
152
178
  bundles the npm package.
153
- - If your top-level `Permissions-Policy` explicitly restricts camera or
154
- microphone, delegate both features to the production and/or staging Soliton
155
- origin you use. The SDK already sets the matching
156
- `allow="camera; microphone"` attribute on its iframe.
157
-
158
- For local development, add the exact localhost origin (including its port) to
159
- the corresponding directives as well.
160
-
161
- ## Pilot test keys
179
+ - If any document above the Soliton iframe explicitly restricts camera or
180
+ microphone with `Permissions-Policy`, every level in a nested frame chain
181
+ must allow and delegate both features through each intervening iframe; an
182
+ upstream denial cannot be overridden lower in the chain. The SDK already
183
+ sets the matching `allow="camera; microphone"` attribute on the iframe it
184
+ creates.
185
+
186
+ These examples use production. Add a staging origin to these directives only
187
+ when Soliton has supplied its exact, working staging URL; include both origins
188
+ only if the same page can open both environments.
189
+
190
+ For local customer-page testing, send us the exact origin, including its port
191
+ (for example `http://localhost:3000`), for registration. It does not belong in
192
+ `frame-src` or `script-src` while the iframe and hosted SDK still load from
193
+ soliton.id. Do not add Soliton to your page's `frame-ancestors`: that directive
194
+ controls who may frame your page, while `frame-src` controls what your page may
195
+ frame.
196
+
197
+ ## Sandbox
198
+
199
+ Your account has two environments and the API key prefix selects one:
200
+ `sk_live_` is **production**, `sk_test_` is **sandbox**. Each has its own
201
+ credentials, verifications, redirect domains, iframe origins, and webhook
202
+ endpoint with its own signing secret.
203
+
204
+ A sandbox verification opens in the overlay exactly like a production one and
205
+ runs the same real capture — but it is checked against the iframe origins
206
+ registered for **sandbox**, so your staging page can embed sandbox links
207
+ without being able to embed production ones. Register each origin for the
208
+ environment that will use it.
209
+
210
+ Sandbox is additionally the only place that can request a fixed outcome, which
211
+ is the practical way to exercise your `partial` branch:
212
+
213
+ ```jsonc
214
+ // POST /api/v1/verifications with an sk_test_ key
215
+ { "client_reference_id": "user-8412", "test_fixture_scenario": "partial" }
216
+ ```
162
217
 
163
- `sk_test_` identifies a pilot credential; it is not an isolated or simulated
164
- sandbox. Test keys use the same hosted capture, biometric processing, and data
165
- handling as live keys. The prefix does not create synthetic results or trigger
166
- automatic deletion. Use only informed, consenting pilot participants, give
167
- them your applicable privacy notice, and follow your Soliton pilot terms.
218
+ | `test_fixture_scenario` | `verified` | `partial_verification` |
219
+ | ----------------------- | ---------- | ---------------------- |
220
+ | `pass` | `true` | `false` |
221
+ | `partial` | `true` | `true` |
222
+ | `fail` | `false` | `false` |
223
+
224
+ A fixture's URL opens in the overlay and fires `onComplete` the same way, but
225
+ never requests camera permission and never records anything. The hosted page
226
+ marks itself as synthetic on screen.
227
+
228
+ Fixtures do not exercise liveness, anti-spoof, or anti-deepfake logic, and
229
+ simulate no errors or timeouts — only the three terminal verdicts. Real
230
+ sandbox captures do run the full pipeline; a production `sk_live_` key cannot
231
+ request fixtures at all.
232
+
233
+ The two environments are strictly isolated: neither credential can read the
234
+ other's verifications, even within one account. Every create response, status
235
+ read, and webhook carries `environment` (`sandbox` or `production`) and
236
+ `result_source` (`biometric` or `synthetic_test_fixture`) — assert both
237
+ anywhere a real production verdict matters.
238
+
239
+ ## Completion webhooks
240
+
241
+ Instead of polling, your server can receive a signed `verification.completed`
242
+ POST the moment a verification reaches its final verdict. Like `onComplete`, it
243
+ is a "check now" signal rather than the verdict itself — fetch the verification
244
+ server-to-server before acting on it. Verify the `X-Soliton-Signature` HMAC,
245
+ deduplicate on `X-Soliton-Event-Id`, and respond `2xx` within 5 seconds. Full
246
+ setup, the signature recipe, and retry semantics are in the
247
+ [integration guide](https://soliton.id/docs/integration).
248
+
249
+ Webhooks are configured per environment: one endpoint for sandbox and one for
250
+ production, each with its own signing secret. A sandbox completion is only ever
251
+ delivered to the sandbox endpoint, so a staging receiver cannot validate — or
252
+ forge — a production event. The payload's `environment` field tells you which
253
+ is which if you point both at one URL.
168
254
 
169
255
  ## How it works
170
256
 
171
- `open()` accepts hosted URLs only from `https://soliton.id` or
172
- `https://staging.soliton.id` (plus HTTP localhost/127.0.0.1 development URLs),
173
- requires a `/v/{token}` path, and preserves query parameters. It renders a
174
- full-viewport overlay with an iframe pointing at that validated origin and
175
- listens for the hosted page's lifecycle messages. Every message is checked
176
- three ways (origin, source window, protocol marker) before it reaches your
177
- callbacks, and unknown message types are ignored, so wrapper versions stay
178
- compatible as the hosted flow evolves. Redirect-style integration (no SDK,
179
- we redirect the user back to you) remains fully supported; the same
180
- verification URL works in both modes.
257
+ `open()` accepts hosted URLs from `https://soliton.id`. When Soliton has
258
+ supplied a working staging flow URL, it also accepts
259
+ `https://staging.soliton.id`; HTTP localhost/127.0.0.1 URLs are accepted for
260
+ development. Every URL must use a `/v/{token}` path; query parameters are
261
+ preserved. The SDK renders a full-viewport overlay with an iframe pointing at
262
+ that validated origin and listens for the hosted page's lifecycle messages.
263
+ Every message is checked three ways (origin, source window, protocol marker)
264
+ before it reaches your callbacks, and unknown message types are ignored, so
265
+ wrapper versions stay compatible as the hosted flow evolves. Redirect-style
266
+ integration (no SDK, we redirect the user back to you) remains fully
267
+ supported; the same verification URL works in both modes.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "Publishable manifest for the npm Web SDK. No devDependencies and no own node_modules by design: every build runs from the next-app root with its existing toolchain (npm run build:sdk), so the lockfile never grows for packaging. dist/ is rebuilt automatically by the prepack hook and is not committed.",
3
3
  "name": "@soliton-id/web-sdk",
4
- "version": "1.0.0",
4
+ "version": "1.0.2",
5
5
  "description": "Soliton identity verification for the browser: opens the hosted verification flow in a full-viewport overlay iframe on your page and reports lifecycle events. Verdicts and portraits are fetched by your backend, never exposed in the browser.",
6
6
  "license": "MIT",
7
7
  "author": "Soliton",