@recapi/client 0.5.0 → 0.5.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/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.0/index.js';
19
+ import { createClient } from 'https://api.example.com/sdk/0.5.1/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
@@ -245,6 +245,31 @@ does when its consent API fails to load. It declares compatibility with
245
245
  WooCommerce's order tables (HPOS) and checkout blocks when installed as a
246
246
  plugin, and registers with the WP Consent API.
247
247
 
248
+ With a secret key pasted on WooCommerce → recapi (stored as the
249
+ `recapi_secret_key` option, not autoloaded, and never printed back), the
250
+ plugin describes the shop's products itself. Each product changed in a
251
+ request (`woocommerce_new_product`, `woocommerce_update_product`, a stock
252
+ status change, a variation's change as its parent's, a status change such as
253
+ trashing or a scheduled product going live, a deletion) is read again at
254
+ the end of the request and sent once the page is out, as one
255
+ `PUT /v1/items/{item_id}` or one `POST /v1/items:batch`: one try of at most
256
+ 2 s through WordPress's HTTP API, a failure logged to WooCommerce → Status →
257
+ Logs (source `recapi`), so a recapi outage never fails a save. A WP-Cron
258
+ event (`recapi_sync`, daily, first run when the key is saved) sends the
259
+ whole catalog, 200 products read and 1,000 sent at a time, oldest first,
260
+ with three tries per batch against an outage; the page shows when it last
261
+ ran, how many products it sent and why any were refused. Every item is
262
+ complete: `active` only while the product is published, not hidden from the
263
+ catalog, purchasable and in stock (the Store API cards' rule), its category
264
+ names as `tags` (not "Uncategorized"), its creation date as `published_at`,
265
+ and `name`, `url`, `picture` (the `woocommerce_thumbnail` size) and `price`
266
+ (as the shop displays it, in its currency) as `metadata`, shrunk below
267
+ 2,048 bytes as the Magento module does (picture first, then the name). The
268
+ row then draws every card from it, with no Store API call. Only items that
269
+ changed are billed. The plugin uses WordPress's HTTP API rather than the PHP
270
+ library so it stays one file (a snippet holds it) and follows the site's
271
+ proxy settings.
272
+
248
273
  Have past orders? Download them from WooCommerce → recapi and upload the
249
274
  file on Import data. The plugin writes the last 90 days of processing and
250
275
  completed orders as the dashboard's `user_id,item_id,level,timestamp` CSV,
@@ -516,7 +541,9 @@ so a batch already in flight when the user navigates away still arrives.
516
541
  from `GET /v1/users/{id}/history`. Merging adds up the decayed scores
517
542
  item by item. Use it only when the snapshot does not already contain
518
543
  this device's events, typically right after login. Otherwise those
519
- events count twice.
544
+ 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.
520
547
  - Merge rule for the recent lists: take the union of both lists and order
521
548
  it by interaction time, oldest first. An item in both lists takes its
522
549
  latest time. Then keep the last 20.
@@ -613,6 +640,10 @@ minifier, to keep zero dev dependencies.
613
640
 
614
641
  ## Changes
615
642
 
643
+ - 2026-11-01: version 0.5.1. Without consent, and under Do Not Track, the
644
+ SDK no longer touches `localStorage` at all: before, it wrote and removed a
645
+ probe key when the client was created, to check that storage works. Now
646
+ that check waits for the first read or write, which only consent allows.
616
647
  - 2026-11-01: version 0.5.0. Do Not Track and Global Privacy Control are
617
648
  respected by default: the SDK then stores nothing and sends no events or
618
649
  visitor ids, and still asks for recommendations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recapi/client",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
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
@@ -121,8 +121,16 @@ export function createClient(options) {
121
121
  }
122
122
  };
123
123
  const transport = createTransport({ baseUrl, apiKey, fetch: fetchImpl, timeoutMs });
124
+ // The default adapter probes localStorage with a write, so it is picked at
125
+ // the first storage access: never before consent, nor under Do Not Track.
126
+ let adapter = options.storage;
127
+ const storage = () => (adapter ??= defaultStorage(report));
124
128
  const store = createStore(
125
- options.storage ?? defaultStorage(report),
129
+ {
130
+ getItem: (key) => storage().getItem(key),
131
+ setItem: (key, value) => storage().setItem(key, value),
132
+ removeItem: (key) => storage().removeItem(key)
133
+ },
126
134
  storageKey(options.project ?? apiKey.slice(0, 16)),
127
135
  decodePersisted,
128
136
  report