@bicharts/chart-host 0.6.15 → 0.6.17

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.
@@ -1582,9 +1582,9 @@ var wt = new RegExp([String.raw`\bisMeasure\b`, String.raw`\bdataType\b`, String
1582
1582
 
1583
1583
  // ../shape-core/dist/index.mjs
1584
1584
  /*! @bicharts/shape-core — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; US Census/TIGER (public domain). Full text: NOTICE in this package. */
1585
- var z3 = 2;
1585
+ var K3 = 2;
1586
1586
  var Y3 = 400;
1587
- function B3(n) {
1587
+ function V3(n) {
1588
1588
  return !!E(n);
1589
1589
  }
1590
1590
  function T3(n) {
@@ -1598,8 +1598,8 @@ function T3(n) {
1598
1598
  }
1599
1599
  function M(n) {
1600
1600
  let e = T3(n);
1601
- if (e.length === 0 || W2(n) < 95) return false;
1602
- let t = e.filter((c2) => B3(c2) && !Y(c2)).length, i = e.filter((c2) => !B3(c2) && !!Y(c2)).length;
1601
+ if (e.length === 0 || B3(n) < 95) return false;
1602
+ let t = e.filter((c2) => V3(c2) && !Y(c2)).length, i = e.filter((c2) => !V3(c2) && !!Y(c2)).length;
1603
1603
  return t >= 1 && t >= i;
1604
1604
  }
1605
1605
  function X3(n, e) {
@@ -1607,11 +1607,11 @@ function X3(n, e) {
1607
1607
  let t = E(n);
1608
1608
  return t ? e === "world" ? true : s3.has(t) : false;
1609
1609
  }
1610
- function W2(n) {
1610
+ function B3(n) {
1611
1611
  let e = T3(n);
1612
1612
  if (e.length === 0) return 0;
1613
1613
  let t = 0;
1614
- for (let i of e) B3(i) && t++;
1614
+ for (let i of e) V3(i) && t++;
1615
1615
  return Math.round(t / e.length * 1e3) / 10;
1616
1616
  }
1617
1617
  function E4(n) {
@@ -1630,7 +1630,7 @@ function $2(n) {
1630
1630
  }
1631
1631
  return Array.from(e);
1632
1632
  }
1633
- function K3(n) {
1633
+ function W2(n) {
1634
1634
  let e = $2(n);
1635
1635
  if (e.length === 0) return 0;
1636
1636
  let t = 0;
@@ -1647,7 +1647,7 @@ function et2(n, e) {
1647
1647
  for (let c2 of t) p3(c2, e) && i++;
1648
1648
  return Math.round(i / t.length * 1e3) / 10;
1649
1649
  }
1650
- function V3(n, e) {
1650
+ function z3(n, e) {
1651
1651
  let t = 0;
1652
1652
  for (let i of T3(n)) e(i) && t++;
1653
1653
  return t;
@@ -1670,7 +1670,7 @@ function tt2(n, e, t, i, c2) {
1670
1670
  }
1671
1671
  let h3 = t?.zip;
1672
1672
  if (h3 && x2.has(h3)) {
1673
- let r = d2(h3), u2 = K3(r);
1673
+ let r = d2(h3), u2 = W2(r);
1674
1674
  u2 < 95 ? s.push(`zip=${h3} (only ${u2}% of values read as ZIPs)`) : Z3(r, h3) ? o.zip = h3 : s.push(`zip=${h3} (all values are 3-4 digits with nothing to say they are postal)`);
1675
1675
  }
1676
1676
  let g3 = t?.state;
@@ -1678,23 +1678,23 @@ function tt2(n, e, t, i, c2) {
1678
1678
  let r = d2(g3), u2 = T3(r);
1679
1679
  u2.length > 0 && u2.every((m) => X3(m, i)) ? s.push(`state=${g3} (every value is "CA", which is both Canada and California)`) : M(r) ? (s.push(`state=${g3} (every value is a country, not a state)`), o.country || (o.country = g3)) : E4(r) < 95 ? s.push(`state=${g3} (only ${E4(r)}% of values are states/provinces)`) : o.state = g3;
1680
1680
  }
1681
- let S = new Set(Object.values(o).filter(Boolean)), w3 = n.filter((r) => !S.has(r) && !r.startsWith("__"));
1681
+ let S = new Set(Object.values(o).filter(Boolean)), N3 = n.filter((r) => !S.has(r) && !r.startsWith("__"));
1682
1682
  if (!o.state) {
1683
1683
  let r = null;
1684
- for (let u2 of w3) {
1684
+ for (let u2 of N3) {
1685
1685
  let m = d2(u2);
1686
1686
  if (M(m)) continue;
1687
1687
  let p2 = E4(m);
1688
1688
  if (p2 < 95) continue;
1689
- let D3 = V3(m, (N3) => !!Y(N3)), se = V3(m, (N3) => !!Y(N3) && !X3(N3, i));
1690
- D3 < z3 && se < 1 || (!r || p2 > r.pct) && (r = { name: u2, pct: p2 });
1689
+ let D3 = z3(m, (w3) => !!Y(w3)), se = z3(m, (w3) => !!Y(w3) && !X3(w3, i));
1690
+ D3 < K3 && se < 1 || (!r || p2 > r.pct) && (r = { name: u2, pct: p2 });
1691
1691
  }
1692
1692
  r && (o.state = r.name, S.add(r.name), a4.push(`state=${r.name} (${r.pct}% states/provinces)`));
1693
1693
  }
1694
- if (!o.zip) for (let r of w3) {
1694
+ if (!o.zip) for (let r of N3) {
1695
1695
  if (S.has(r)) continue;
1696
- let u2 = d2(r), m = K3(u2);
1697
- if (!(m < 95) && Z3(u2, r) && !(nt2(u2, (p2) => Z(p2).length > 0) < z3)) {
1696
+ let u2 = d2(r), m = W2(u2);
1697
+ if (!(m < 95) && Z3(u2, r) && !(nt2(u2, (p2) => Z(p2).length > 0) < K3)) {
1698
1698
  o.zip = r, S.add(r), a4.push(`zip=${r} (${m}% ZIP codes)`);
1699
1699
  break;
1700
1700
  }
@@ -1702,27 +1702,27 @@ function tt2(n, e, t, i, c2) {
1702
1702
  let b4 = o.country;
1703
1703
  if (!b4 || !M(d2(b4))) {
1704
1704
  let r = null;
1705
- for (let u2 of w3) {
1705
+ for (let u2 of N3) {
1706
1706
  if (S.has(u2) || !M(d2(u2))) continue;
1707
- let m = W2(d2(u2));
1707
+ let m = B3(d2(u2));
1708
1708
  (!r || m > r.pct) && (r = { name: u2, pct: m });
1709
1709
  }
1710
- r && (b4 && (s.push(`country=${b4} (only ${W2(d2(b4))}% of values are country identifiers; using ${r.name} instead)`), C2.country = b4), o.country = r.name, S.add(r.name), a4.push(`country=${r.name}`));
1710
+ r && (b4 && (s.push(`country=${b4} (only ${B3(d2(b4))}% of values are country identifiers; using ${r.name} instead)`), C2.country = b4), o.country = r.name, S.add(r.name), a4.push(`country=${r.name}`));
1711
1711
  }
1712
1712
  if (!o.city) {
1713
1713
  let r = null;
1714
- for (let u2 of w3) {
1714
+ for (let u2 of N3) {
1715
1715
  if (S.has(u2)) continue;
1716
1716
  let m = d2(u2), p2 = et2(m, i);
1717
- p2 < m3 || V3(m, (D3) => p3(D3, i)) < z3 || (!r || p2 > r.pct) && (r = { name: u2, pct: p2 });
1717
+ p2 < m3 || z3(m, (D3) => p3(D3, i)) < K3 || (!r || p2 > r.pct) && (r = { name: u2, pct: p2 });
1718
1718
  }
1719
1719
  r && (o.city = r.name, a4.push(`city=${r.name} (${r.pct}% known cities)`));
1720
1720
  }
1721
- let U3 = o.country ? d2(o.country) : [], _2 = !!o.country && M(U3), ie = _2 ? new Set(U3.map((r) => E(r == null ? null : String(r))).filter(Boolean)).size : 0, H3 = _2 && ie >= 2, F3 = !!(o.lat && o.lon) && e.some((r) => {
1721
+ let U3 = o.country ? d2(o.country) : [], F3 = !!o.country && M(U3), ie = F3 ? new Set(U3.map((r) => E(r == null ? null : String(r))).filter(Boolean)).size : 0, H3 = F3 && ie >= 2, _2 = !!(o.lat && o.lon) && e.some((r) => {
1722
1722
  let u2 = +String(r[o.lat] ?? "").trim(), m = +String(r[o.lon] ?? "").trim();
1723
1723
  return isFinite(u2) && isFinite(m) && u2 >= -90 && u2 <= 90 && m >= -180 && m <= 180 && String(r[o.lat] ?? "").trim() !== "" && String(r[o.lon] ?? "").trim() !== "";
1724
1724
  });
1725
- return o.lat && o.lon && !F3 && s.push(`lat/lon=${o.lat}/${o.lon} (no row holds a usable coordinate pair)`), o.country && !H3 && !(o.city || o.state || o.zip || F3) && s.push(_2 ? `country=${o.country} (every row resolves to the same country - nothing to place apart)` : `country=${o.country} (values are not country identifiers)`), { bind: !!(o.city || o.state || o.zip || H3 || F3) ? o : null, backfilled: a4, refused: s, ...Object.keys(C2).length ? { labelFallback: C2 } : {} };
1725
+ return o.lat && o.lon && !_2 && s.push(`lat/lon=${o.lat}/${o.lon} (no row holds a usable coordinate pair)`), o.country && !H3 && !(o.city || o.state || o.zip || _2) && s.push(F3 ? `country=${o.country} (every row resolves to the same country - nothing to place apart)` : `country=${o.country} (values are not country identifiers)`), { bind: !!(o.city || o.state || o.zip || H3 || _2) ? o : null, backfilled: a4, refused: s, ...Object.keys(C2).length ? { labelFallback: C2 } : {} };
1726
1726
  }
1727
1727
 
1728
1728
  // src/payload.ts
package/dist/index.mjs CHANGED
@@ -140,7 +140,7 @@ import {
140
140
  unpinScrolledAxis,
141
141
  valuePlacementFlag,
142
142
  withoutViewOnlyKeys
143
- } from "./chunk-HLNXKVQP.mjs";
143
+ } from "./chunk-JVJKBNWB.mjs";
144
144
  import "./chunk-A2GMXZP7.mjs";
145
145
  import "./chunk-GHODWOAL.mjs";
146
146
 
@@ -2383,6 +2383,23 @@ function reconcileChartPick(pick, offered, autoLabel) {
2383
2383
  };
2384
2384
  }
2385
2385
 
2386
+ // src/duplicateGenerateGuard.ts
2387
+ var DUPLICATE_GENERATE_WINDOW_MS = 2500;
2388
+ function sameRequest(a2, b2) {
2389
+ return a2.schemaHash === b2.schemaHash && a2.gennew === b2.gennew && a2.trycnt === b2.trycnt && a2.favorStyle === b2.favorStyle;
2390
+ }
2391
+ function isDuplicateGenerate(prev, next, now) {
2392
+ if (!prev) return false;
2393
+ if (!sameRequest(prev, next)) return false;
2394
+ if (prev.inFlight) return true;
2395
+ const elapsed = now - prev.startedAt;
2396
+ if (elapsed < 0) return false;
2397
+ return elapsed < DUPLICATE_GENERATE_WINDOW_MS;
2398
+ }
2399
+ function armGenerateGuard(next, now) {
2400
+ return { ...next, startedAt: now, inFlight: true };
2401
+ }
2402
+
2386
2403
  // src/clientIdentity.ts
2387
2404
  function stableFingerprintOptions() {
2388
2405
  return { exclude: ["fonts", "system.useragent", "system.browser.version"], logging: false };
@@ -2450,6 +2467,7 @@ export {
2450
2467
  DARK_TEXT,
2451
2468
  DIM_OPACITY_DEFAULT,
2452
2469
  DIM_OPACITY_VAR,
2470
+ DUPLICATE_GENERATE_WINDOW_MS,
2453
2471
  FILTER_MIN_HEIGHT_PX,
2454
2472
  FILTER_MIN_TERM_CHARS,
2455
2473
  FILTER_MIN_WIDTH_PX,
@@ -2504,6 +2522,7 @@ export {
2504
2522
  XFILTER_REFRESH_EVENT,
2505
2523
  actionFor,
2506
2524
  applyLabelContrast,
2525
+ armGenerateGuard,
2507
2526
  askApplyImprovements,
2508
2527
  assembleD3,
2509
2528
  autoRampCanvas,
@@ -2565,6 +2584,7 @@ export {
2565
2584
  invalidSentinelReason,
2566
2585
  isBlankRender,
2567
2586
  isBlindMarker,
2587
+ isDuplicateGenerate,
2568
2588
  isExcelDateFormat,
2569
2589
  isHorizontalLabelRow,
2570
2590
  isInsideControl,
package/dist/react.mjs CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  loadGeo,
8
8
  syncMemberSelection,
9
9
  toSourceRows
10
- } from "./chunk-HLNXKVQP.mjs";
10
+ } from "./chunk-JVJKBNWB.mjs";
11
11
  import "./chunk-A2GMXZP7.mjs";
12
12
  import "./chunk-GHODWOAL.mjs";
13
13
 
@@ -0,0 +1,33 @@
1
+ /** What identifies one generate request for suppression purposes. */
2
+ export interface GenerateGuardKey {
3
+ /** Field/column fingerprint. A field change moves this, and must not be suppressed. */
4
+ schemaHash: number;
5
+ /** A fresh generation vs a fetch/regeneration - different intents. */
6
+ gennew: boolean;
7
+ /** The explicit chart-type pick ("" when the picker is free to choose). */
8
+ favorStyle: string;
9
+ /** The retry counter. Differs on every retry, so a retry is never suppressed. */
10
+ trycnt: number;
11
+ }
12
+ /** The last generate a host started, plus whether it is still running. */
13
+ export interface GenerateGuardState extends GenerateGuardKey {
14
+ /** The host's clock (performance.now()) when the call STARTED. */
15
+ startedAt: number;
16
+ /** True from the start of the generate until it settles. */
17
+ inFlight: boolean;
18
+ }
19
+ /** Two calls this close together, with everything else equal, are one user action. */
20
+ export declare const DUPLICATE_GENERATE_WINDOW_MS = 2500;
21
+ /**
22
+ * Should this generate be suppressed as a duplicate of the one before it?
23
+ *
24
+ * Suppress when the request is identical AND either the previous call is still running, or it
25
+ * started within the window. Anything else proceeds.
26
+ *
27
+ * @param prev what the host last started, or null on its first generate
28
+ * @param next the request about to be made
29
+ * @param now the host's clock (performance.now()) at the moment of the call
30
+ */
31
+ export declare function isDuplicateGenerate(prev: GenerateGuardState | null | undefined, next: GenerateGuardKey, now: number): boolean;
32
+ /** The state to record when a generate is allowed to proceed. */
33
+ export declare function armGenerateGuard(next: GenerateGuardKey, now: number): GenerateGuardState;
@@ -38,5 +38,6 @@ export { resolveAutoColorScale, autoRampMinStep, autoRampCanvas, AUTO_RAMP_CLASS
38
38
  export { PENDING_RECOVERY_WINDOW_MS, PENDING_RECOVERY_POLL_MS, PENDING_RECOVERY_FIRST_POLL_MS, PENDING_RECOVERY_FAST_PHASE_MS, PENDING_RECOVERY_MID_POLL_MS, PENDING_RECOVERY_SLOW_PHASE_MS, PENDING_RECOVERY_SLOW_POLL_MS, pendingRecoveryNextDelayMs, encodePendingGenerate, parsePendingGenerate, markerArmedBlind, isBlindMarker, servedCorrelationProves, sameMarker, decidePendingRecovery, recoveryPollRunning, recoveryOwnsTheSentence, latePickupAction, latePickupKeepsMarker, pollGiveUpKeepsMarker, pendingRecoveryRemainingMs, transportFailureShouldRecover, TRANSPORT_LOST_CHECKING_MESSAGE, GENERATION_CANCELLED_MESSAGE, recoveryAnswerIsCancelled, generationCancelledMessage, type PendingGenerateMarker, type PendingRecoveryDecision, type LatePickupAction, } from "./pendingGenerate";
39
39
  export { stripJsComments } from "./codeComments";
40
40
  export { reconcileChartPick, type ChartPickReconciliation } from "./chartPick";
41
+ export { isDuplicateGenerate, armGenerateGuard, DUPLICATE_GENERATE_WINDOW_MS, type GenerateGuardKey, type GenerateGuardState, } from "./duplicateGenerateGuard";
41
42
  export { stableFingerprintOptions, fingerprintComponentDigest, type ClientIdSource } from "./clientIdentity";
42
43
  export type { HostServices, MarkerStore, PreferenceSource, HostTheme, ThemeSource, ThumbnailConsent, SnapshotTarget, WireSigner, WireTransport, WireResponse, CredentialTriple, CredentialSource, ViewportSource, Clock, DiagnosticEntry, DiagnosticsSink, RendererId, } from "./host/services";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bicharts/chart-host",
3
- "version": "0.6.15",
3
+ "version": "0.6.17",
4
4
  "description": "Run a BIC-generated D3 chart in any web host: compiles the generated render() function, applies the shared option defaults, resolves mark clicks (through tooltip overlays), owns the selection affordance, and translates row indices between cross-filtered charts. The same contract the BIC Power BI visual implements, minus Power BI. React bindings at @bicharts/chart-host/react.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",