@recapi/client 0.5.1 → 0.6.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/README.md CHANGED
@@ -16,7 +16,7 @@ are, gzipped, and browsers cache them for a year:
16
16
 
17
17
  ```html
18
18
  <script type="module">
19
- import { createClient } from 'https://api.example.com/sdk/0.5.1/index.js';
19
+ import { createClient } from 'https://api.example.com/sdk/0.6.0/index.js';
20
20
 
21
21
  const recapi = createClient({ apiKey: 'rk_pub_…', baseUrl: 'https://api.example.com' });
22
22
  recapi.track('item-42', 'view'); // and the calls of the quick start below
@@ -327,7 +327,7 @@ come):
327
327
  ```js
328
328
  const LABELS = {
329
329
  for_you: 'Picked for you', similar: 'Similar items', next: 'Up next',
330
- trending: 'Trending now', popular: 'Popular', new: 'New',
330
+ bought_together: 'Often bought together', trending: 'Trending now', popular: 'Popular', new: 'New',
331
331
  };
332
332
  for (const item of items) {
333
333
  const label = LABELS[item.why]; // undefined for explore, more and future codes: no label
@@ -398,6 +398,9 @@ for (const item of items) {
398
398
  - **`getHistory()`** returns `{ history, recent, rejected }` exactly as the
399
399
  next request would send it (`rejected` goes into `exclude`). Use it for
400
400
  debugging.
401
+ - **`getAnonId()`** returns this device's anonymous id, the `anon_id` its
402
+ events carry, or `null` without consent and under Do Not Track. See
403
+ [Login and logout](#login-and-logout).
401
404
  - **`destroy()`** removes listeners and timers, then flushes.
402
405
 
403
406
  ### Errors
@@ -542,8 +545,18 @@ so a batch already in flight when the user navigates away still arrives.
542
545
  item by item. Use it only when the snapshot does not already contain
543
546
  this device's events, typically right after login. Otherwise those
544
547
  events count twice. The snapshot also holds the anonymous browsing of
545
- the devices the user logged in on before: on such a device, what was
546
- browsed there since would count twice.
548
+ the devices the user logged in on before, this one included when it was
549
+ not `reset()` at logout. Send `getAnonId()` with the login request and
550
+ have your backend ask for `GET /v1/users/{id}/history?anon_id=…`: the
551
+ snapshot then leaves out this device's own browsing.
552
+
553
+ ```js
554
+ // Browser, at login:
555
+ const res = await fetch('/login', { method: 'POST', body: JSON.stringify({ ...form, anonId: recapi.getAnonId() }) });
556
+ recapi.identify(userId, { history: (await res.json()).recapiHistory });
557
+ // Backend, with the secret key:
558
+ // GET /v1/users/{userId}/history?anon_id={anonId} (leave anon_id out when it is null)
559
+ ```
547
560
  - Merge rule for the recent lists: take the union of both lists and order
548
561
  it by interaction time, oldest first. An item in both lists takes its
549
562
  latest time. Then keep the last 20.
@@ -640,6 +653,10 @@ minifier, to keep zero dev dependencies.
640
653
 
641
654
  ## Changes
642
655
 
656
+ - 2026-11-01: version 0.6.0. `getAnonId()` returns the device's anonymous
657
+ id, for the backend to fetch the login snapshot without this device's own
658
+ browsing (`?anon_id=`), which would otherwise count twice on a device not
659
+ reset at logout.
643
660
  - 2026-11-01: version 0.5.1. Without consent, and under Do Not Track, the
644
661
  SDK no longer touches `localStorage` at all: before, it wrote and removed a
645
662
  probe key when the client was created, to check that storage works. Now
package/index.d.ts CHANGED
@@ -104,7 +104,8 @@ export interface RecommendParams {
104
104
 
105
105
  /** An item's reason code: map the ones you want to your own label, show none for an unknown one. */
106
106
  export type ReasonCode =
107
- | 'for_you' | 'similar' | 'next' | 'trending' | 'popular' | 'new' | 'explore' | 'more' | (string & {});
107
+ | 'for_you' | 'similar' | 'next' | 'bought_together' | 'trending' | 'popular' | 'new' | 'explore' | 'more'
108
+ | (string & {});
108
109
 
109
110
  /** The object stored with the item (`PUT /v1/items`, `metadata`): name, picture, link, price... */
110
111
  export type ItemMetadata = Record<string, unknown>;
@@ -159,6 +160,8 @@ export interface RecapiClient {
159
160
  /** Never rejects; failures go to `onError`. */
160
161
  flush(): Promise<void>;
161
162
  getHistory(): WireHistory;
163
+ /** This device's anonymous id; null without consent or under Do Not Track. */
164
+ getAnonId(): string | null;
162
165
  destroy(): Promise<void>;
163
166
  }
164
167
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recapi/client",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Browser and Node client for the recapi recommendation API: local decayed history, event batching, attribution.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/client.js CHANGED
@@ -508,7 +508,8 @@ export function createClient(options) {
508
508
  * `options.history` takes a server snapshot (from
509
509
  * `GET /v1/users/{id}/history`, fetched by your backend with the secret
510
510
  * key) and merges it into the local history. Only pass a snapshot that
511
- * does not already contain this device's events, or they count twice.
511
+ * does not already contain this device's events, or they count twice:
512
+ * fetch it with this device's `getAnonId()`.
512
513
  * Does nothing under Do Not Track: requests name nobody.
513
514
  *
514
515
  * @param {string} id
@@ -588,6 +589,20 @@ export function createClient(options) {
588
589
  return toWire(history, now(), config);
589
590
  },
590
591
 
592
+ /**
593
+ * This device's anonymous id, the `anon_id` its events carry: null
594
+ * without consent or under Do Not Track. Send it with the login request,
595
+ * so your backend asks `GET /v1/users/{id}/history?anon_id=…` for the
596
+ * snapshot it passes to `identify()`: that snapshot then leaves out this
597
+ * device's browsing, which the local history holds already.
598
+ *
599
+ * @returns {string | null}
600
+ */
601
+ getAnonId() {
602
+ if (consent) reload();
603
+ return anonId;
604
+ },
605
+
591
606
  /**
592
607
  * Removes listeners and timers, then flushes what is queued.
593
608
  *