@helpai/elements 0.28.0 → 0.28.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/index.mjs CHANGED
@@ -1381,6 +1381,7 @@ function messageToWireParts(m) {
1381
1381
  var log4 = logger.scope("transport");
1382
1382
  var MAX_RESUME_ATTEMPTS = 3;
1383
1383
  var RESUME_BACKOFF_MS = 400;
1384
+ var CONTENT_CACHE_TTL_MS = 6e4;
1384
1385
  var MAX_REQUEST_RETRIES = 3;
1385
1386
  var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
1386
1387
  function backoffMs(attempt) {
@@ -1419,6 +1420,20 @@ var AgentTransport = class {
1419
1420
  // always sees the visitor's latest context as they navigate.
1420
1421
  __publicField(this, "userContext");
1421
1422
  __publicField(this, "pageContext");
1423
+ // ---- Data API (content / forms — module-help-ai-data-api) --------------
1424
+ //
1425
+ // The DATA surfaces live on `dataApiBaseUrl` (default `${baseUrl}/api/data`)
1426
+ // under the module's `/pai/*` group — same auth headers + envelope, same
1427
+ // retry behavior. One endpoint for every content surface (Home / Help /
1428
+ // News / docs); callers pass filters; a thrown StreamError (e.g. 404 on an
1429
+ // older backend) is treated as "no content" by the module and the tab
1430
+ // degrades gracefully.
1431
+ // Per-query content cache: published content barely changes mid-visit, but
1432
+ // every tab switch remounts its module and re-asks. Entries hold the
1433
+ // REQUEST PROMISE (concurrent identical queries share one network call)
1434
+ // and serve repeats for CONTENT_CACHE_TTL_MS; failures are evicted so the
1435
+ // next ask retries.
1436
+ __publicField(this, "contentCache", /* @__PURE__ */ new Map());
1422
1437
  }
1423
1438
  // ---- Public API -------------------------------------------------------
1424
1439
  /**
@@ -1575,16 +1590,22 @@ var AgentTransport = class {
1575
1590
  log4.debug("markRead failed (non-fatal)", { err });
1576
1591
  }
1577
1592
  }
1578
- // ---- Data API (content / forms module-help-ai-data-api) --------------
1579
- //
1580
- // The DATA surfaces live on `dataApiBaseUrl` (default `${baseUrl}/api/data`)
1581
- // with ROOT-level paths — same auth headers + envelope, same retry
1582
- // behavior. One endpoint for every content surface (Home / Help / News /
1583
- // docs); callers pass filters; a thrown StreamError (e.g. 404 on an older
1584
- // backend) is treated as "no content" by the module and the tab degrades
1585
- // gracefully.
1586
- /** Fetch content rows by filter. `GET /content` (data-API). */
1587
- async listContent(query = {}) {
1593
+ /** Fetch content rows by filter. `GET /pai/content` (data-API), TTL-cached. */
1594
+ listContent(query = {}) {
1595
+ const key = JSON.stringify(query, Object.keys(query).toSorted());
1596
+ const cached = this.contentCache.get(key);
1597
+ if (cached && Date.now() - cached.at < CONTENT_CACHE_TTL_MS) {
1598
+ log4.debug("listContent \u2192 cache", query);
1599
+ return cached.result;
1600
+ }
1601
+ const result = this.fetchContent(query).catch((err) => {
1602
+ this.contentCache.delete(key);
1603
+ throw err;
1604
+ });
1605
+ this.contentCache.set(key, { at: Date.now(), result });
1606
+ return result;
1607
+ }
1608
+ async fetchContent(query) {
1588
1609
  const url = new URL(this.dataUrl(DEFAULT_PATHS.content));
1589
1610
  for (const [key, value] of Object.entries(query)) {
1590
1611
  if (value === void 0) continue;
package/package.json CHANGED
@@ -80,5 +80,5 @@
80
80
  ],
81
81
  "type": "module",
82
82
  "types": "./index.d.ts",
83
- "version": "0.28.0"
83
+ "version": "0.28.1"
84
84
  }
package/web-component.mjs CHANGED
@@ -1436,6 +1436,7 @@ function messageToWireParts(m) {
1436
1436
  var log4 = logger.scope("transport");
1437
1437
  var MAX_RESUME_ATTEMPTS = 3;
1438
1438
  var RESUME_BACKOFF_MS = 400;
1439
+ var CONTENT_CACHE_TTL_MS = 6e4;
1439
1440
  var MAX_REQUEST_RETRIES = 3;
1440
1441
  var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
1441
1442
  function backoffMs(attempt) {
@@ -1474,6 +1475,20 @@ var AgentTransport = class {
1474
1475
  // always sees the visitor's latest context as they navigate.
1475
1476
  __publicField(this, "userContext");
1476
1477
  __publicField(this, "pageContext");
1478
+ // ---- Data API (content / forms — module-help-ai-data-api) --------------
1479
+ //
1480
+ // The DATA surfaces live on `dataApiBaseUrl` (default `${baseUrl}/api/data`)
1481
+ // under the module's `/pai/*` group — same auth headers + envelope, same
1482
+ // retry behavior. One endpoint for every content surface (Home / Help /
1483
+ // News / docs); callers pass filters; a thrown StreamError (e.g. 404 on an
1484
+ // older backend) is treated as "no content" by the module and the tab
1485
+ // degrades gracefully.
1486
+ // Per-query content cache: published content barely changes mid-visit, but
1487
+ // every tab switch remounts its module and re-asks. Entries hold the
1488
+ // REQUEST PROMISE (concurrent identical queries share one network call)
1489
+ // and serve repeats for CONTENT_CACHE_TTL_MS; failures are evicted so the
1490
+ // next ask retries.
1491
+ __publicField(this, "contentCache", /* @__PURE__ */ new Map());
1477
1492
  }
1478
1493
  // ---- Public API -------------------------------------------------------
1479
1494
  /**
@@ -1630,16 +1645,22 @@ var AgentTransport = class {
1630
1645
  log4.debug("markRead failed (non-fatal)", { err });
1631
1646
  }
1632
1647
  }
1633
- // ---- Data API (content / forms module-help-ai-data-api) --------------
1634
- //
1635
- // The DATA surfaces live on `dataApiBaseUrl` (default `${baseUrl}/api/data`)
1636
- // with ROOT-level paths — same auth headers + envelope, same retry
1637
- // behavior. One endpoint for every content surface (Home / Help / News /
1638
- // docs); callers pass filters; a thrown StreamError (e.g. 404 on an older
1639
- // backend) is treated as "no content" by the module and the tab degrades
1640
- // gracefully.
1641
- /** Fetch content rows by filter. `GET /content` (data-API). */
1642
- async listContent(query = {}) {
1648
+ /** Fetch content rows by filter. `GET /pai/content` (data-API), TTL-cached. */
1649
+ listContent(query = {}) {
1650
+ const key = JSON.stringify(query, Object.keys(query).toSorted());
1651
+ const cached = this.contentCache.get(key);
1652
+ if (cached && Date.now() - cached.at < CONTENT_CACHE_TTL_MS) {
1653
+ log4.debug("listContent \u2192 cache", query);
1654
+ return cached.result;
1655
+ }
1656
+ const result = this.fetchContent(query).catch((err) => {
1657
+ this.contentCache.delete(key);
1658
+ throw err;
1659
+ });
1660
+ this.contentCache.set(key, { at: Date.now(), result });
1661
+ return result;
1662
+ }
1663
+ async fetchContent(query) {
1643
1664
  const url = new URL(this.dataUrl(DEFAULT_PATHS.content));
1644
1665
  for (const [key, value] of Object.entries(query)) {
1645
1666
  if (value === void 0) continue;