@bicharts/chart-host 0.5.101 → 0.5.103
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.
|
@@ -1440,7 +1440,7 @@ function Wt(n, s) {
|
|
|
1440
1440
|
return { iso: i, unmatched: M4, matchedRows: h3, totalRows: n.length };
|
|
1441
1441
|
}
|
|
1442
1442
|
|
|
1443
|
-
// ../shape-core/dist/chunk-
|
|
1443
|
+
// ../shape-core/dist/chunk-3IYFLQQR.mjs
|
|
1444
1444
|
var import_papaparse = __toESM(require_papaparse_min(), 1);
|
|
1445
1445
|
/*! @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. */
|
|
1446
1446
|
var Ae = { "north-america": "AG AI AW BB BL BM BQ BS BZ CA CR CU CW DM DO GD GL GP GT HN HT JM KN KY LC MF MQ MS MX NI PA PM PR SV SX TC TT US VC VG VI", "south-america": "AR BO BR CL CO EC FK GF GY PE PY SR UY VE", europe: "AD AL AT AX BA BE BG BY CH CY CZ DE DK EE ES FI FO FR GB GG GI GR HR HU IE IM IS IT JE LI LT LU LV MC MD ME MK MT NL NO PL PT RO RS RU SE SI SJ SK SM UA VA", africa: "AO BF BI BJ BW CD CF CG CI CM CV DJ DZ EG EH ER ET GA GH GM GN GQ GW KE KM LR LS LY MA MG ML MR MU MW MZ NA NE NG RE RW SC SD SH SL SN SO SS ST SZ TD TG TN TZ UG YT ZA ZM ZW", asia: "AE AF AM AZ BD BH BN BT CC CN CX GE HK ID IL IN IO IQ IR JO JP KG KH KP KR KW KZ LA LB LK MM MN MO MV MY NP OM PH PK PS QA SA SG SY TH TJ TL TM TR TW UZ VN YE", oceania: "AS AU CK FJ FM GU KI MH MP NC NF NR NU NZ PF PG PN PW SB TK TO TV UM VU WF WS", antarctica: "AQ BV GS HM TF" };
|
|
@@ -1456,8 +1456,8 @@ function He(n) {
|
|
|
1456
1456
|
}
|
|
1457
1457
|
}
|
|
1458
1458
|
He(N);
|
|
1459
|
-
var Ke = ["rate", "ratio", "pct", "percent", "percentage", "rating", "share", "score", "index", "nps", "csat", "margin", "yield", "coverage", "utilization", "z[_-]?score", "average", "avg", "mean", "median", "stddev", "variance", "gpa", "percentile", "quantile", "efficiency", "accuracy", "probability", "multiplier", "coefficient", "correlation", "occupancy", "age", "bmi", "temperature", "density", "pressure", "humidity", "ph", "velocity", "speed", "elevation", "altitude", "latency", "throughput", "bandwidth", "iops", "temperatuur", "temperatur", "temperatura", "teplota", "lampotila", "homerseklet", "sicaklik", "pression", "presion", "pressao", "pressione", "druck", "tryck", "tlak", "paine", "nyomas", "presiune", "humidite", "humedad", "umidade", "umidita", "feuchtigkeit", "vochtigheid", "kosteus", "vlhkost", "vitesse", "velocidad", "velocidade", "velocita", "geschwindigkeit", "snelheid", "hastighet", "hastighed", "rychlost", "nopeus", "sebesseg", "brzina", "predkosc", "densite", "densidad", "densidade", "densita", "dichte", "dichtheid", "hustota", "tiheys", "gustoca", "moyenne", "mediane", "promedio", "mediana", "gemiddelde", "durchschnitt", "mittelwert", "genomsnitt", "gennemsnit", "gjennomsnitt", "keskiarvo", "atlag", "ortalama", "prosjek", "srednia", "prumer", "priemer", "medie", "taux", "tasa", "taxa", "tasso", "verhaltnis", "verhouding", "aandeel", "anteil", "andel", "osuus", "podil", "udzial", "udio", "pourcentage", "porcentaje", "percentual", "prozent", "procent", "prosentti", "szazalek", "yuzde", "participacion", "participacao", "pondere", "omjer", "arany", "oran", "rata", "leeftijd", "edad", "idade", "wiek", "eletkor", "varsta", "puntuacion", "pontuacao", "punteggio", "betyg", "ocena", "indice", "indeks", "wskaznik", "puan"];
|
|
1460
|
-
var $e = ["pct", "percent", "percentage", "rate", "ratio", "rating", "share", "score", "index", "nps", "csat", "margin", "yield", "coverage", "utilization", "gpa", "percentile", "quantile", "bmi", "density", "pressure", "humidity", "velocity", "efficiency", "occupancy", "latency", "throughput", "bandwidth", "iops"];
|
|
1459
|
+
var Ke = ["rate", "ratio", "pct", "percent", "percentage", "rating", "share", "score", "index", "nps", "csat", "margin", "yield", "coverage", "utilization", "z[_-]?score", "average", "avg", "mean", "median", "stddev", "variance", "gpa", "percentile", "quantile", "efficiency", "accuracy", "probability", "multiplier", "coefficient", "correlation", "occupancy", "age", "bmi", "temperature", "density", "pressure", "humidity", "ph", "velocity", "speed", "elevation", "altitude", "latency", "throughput", "bandwidth", "iops", "ppm", "ppb", "dpmo", "bps", "temperatuur", "temperatur", "temperatura", "teplota", "lampotila", "homerseklet", "sicaklik", "pression", "presion", "pressao", "pressione", "druck", "tryck", "tlak", "paine", "nyomas", "presiune", "humidite", "humedad", "umidade", "umidita", "feuchtigkeit", "vochtigheid", "kosteus", "vlhkost", "vitesse", "velocidad", "velocidade", "velocita", "geschwindigkeit", "snelheid", "hastighet", "hastighed", "rychlost", "nopeus", "sebesseg", "brzina", "predkosc", "densite", "densidad", "densidade", "densita", "dichte", "dichtheid", "hustota", "tiheys", "gustoca", "moyenne", "mediane", "promedio", "mediana", "gemiddelde", "durchschnitt", "mittelwert", "genomsnitt", "gennemsnit", "gjennomsnitt", "keskiarvo", "atlag", "ortalama", "prosjek", "srednia", "prumer", "priemer", "medie", "taux", "tasa", "taxa", "tasso", "verhaltnis", "verhouding", "aandeel", "anteil", "andel", "osuus", "podil", "udzial", "udio", "pourcentage", "porcentaje", "percentual", "prozent", "procent", "prosentti", "szazalek", "yuzde", "participacion", "participacao", "pondere", "omjer", "arany", "oran", "rata", "leeftijd", "edad", "idade", "wiek", "eletkor", "varsta", "puntuacion", "pontuacao", "punteggio", "betyg", "ocena", "indice", "indeks", "wskaznik", "puan"];
|
|
1460
|
+
var $e = ["pct", "percent", "percentage", "rate", "ratio", "rating", "share", "score", "index", "nps", "csat", "margin", "yield", "coverage", "utilization", "gpa", "percentile", "quantile", "bmi", "density", "pressure", "humidity", "velocity", "efficiency", "occupancy", "latency", "throughput", "bandwidth", "iops", "ppm", "ppb", "dpmo", "bps"];
|
|
1461
1461
|
var Ze = ["latitude", "longitude"];
|
|
1462
1462
|
var Xe = ["latitude", "longitude"];
|
|
1463
1463
|
function j2(n) {
|
|
@@ -2926,7 +2926,7 @@ function hexToRGB(hex2) {
|
|
|
2926
2926
|
// src/labelContrastDom.ts
|
|
2927
2927
|
var LABEL_CONTRAST_DONE_ATTR = "data-lch-contrast";
|
|
2928
2928
|
var LABEL_CONTRAST_CAP = 2e3;
|
|
2929
|
-
var EMPTY5 = { rects: 0, scanned: 0, fixed: 0, pillsBoosted: 0, offFill: 0, pageMajority: 0 };
|
|
2929
|
+
var EMPTY5 = { rects: 0, scanned: 0, fixed: 0, pillsBoosted: 0, offFill: 0, pageMajority: 0, paintedOver: 0 };
|
|
2930
2930
|
function backedSamples(el, pts) {
|
|
2931
2931
|
try {
|
|
2932
2932
|
const ge = el;
|
|
@@ -2948,6 +2948,20 @@ function backedSamples(el, pts) {
|
|
|
2948
2948
|
return null;
|
|
2949
2949
|
}
|
|
2950
2950
|
}
|
|
2951
|
+
var DOC_POSITION_FOLLOWING = 4;
|
|
2952
|
+
function paintRoot(el, container) {
|
|
2953
|
+
let root = null;
|
|
2954
|
+
for (let n = el.parentElement; n; n = n.parentElement) {
|
|
2955
|
+
if (String(n.tagName || "").toLowerCase() === "svg") root = n;
|
|
2956
|
+
if (n === container) break;
|
|
2957
|
+
}
|
|
2958
|
+
return root;
|
|
2959
|
+
}
|
|
2960
|
+
function drawnBeneath(shape, text, textRoot) {
|
|
2961
|
+
if (!shape.root || shape.root !== textRoot) return true;
|
|
2962
|
+
if (typeof shape.el.compareDocumentPosition !== "function") return true;
|
|
2963
|
+
return (shape.el.compareDocumentPosition(text) & DOC_POSITION_FOLLOWING) !== 0;
|
|
2964
|
+
}
|
|
2951
2965
|
function applyLabelContrast(container, opts = {}) {
|
|
2952
2966
|
const report = { ...EMPTY5 };
|
|
2953
2967
|
if (!container) {
|
|
@@ -2972,7 +2986,15 @@ function applyLabelContrast(container, opts = {}) {
|
|
|
2972
2986
|
if (!fill || fill === "none") return;
|
|
2973
2987
|
const opAttr = el.getAttribute("fill-opacity");
|
|
2974
2988
|
const op = opAttr === null ? 1 : parseFloat(opAttr);
|
|
2975
|
-
rects.push({
|
|
2989
|
+
rects.push({
|
|
2990
|
+
r,
|
|
2991
|
+
fill,
|
|
2992
|
+
op: isFinite(op) ? op : 1,
|
|
2993
|
+
area: r.width * r.height,
|
|
2994
|
+
el,
|
|
2995
|
+
ord: ord++,
|
|
2996
|
+
root: paintRoot(el, container)
|
|
2997
|
+
});
|
|
2976
2998
|
};
|
|
2977
2999
|
const shapeEls = container.querySelectorAll("rect, path");
|
|
2978
3000
|
if (shapeEls.length === 0) {
|
|
@@ -3008,7 +3030,15 @@ function applyLabelContrast(container, opts = {}) {
|
|
|
3008
3030
|
if (tr.width <= 0 || tr.height <= 0) continue;
|
|
3009
3031
|
const ovArea = (r) => Math.max(0, Math.min(r.right, tr.right) - Math.max(r.left, tr.left)) * Math.max(0, Math.min(r.bottom, tr.bottom) - Math.max(r.top, tr.top));
|
|
3010
3032
|
const glyphArea = tr.width * tr.height;
|
|
3011
|
-
const
|
|
3033
|
+
const txRoot = paintRoot(tx, container);
|
|
3034
|
+
let over = 0;
|
|
3035
|
+
const boxed = rects.map((mk) => ({ mk, ov: ovArea(mk.r) })).filter((x3) => {
|
|
3036
|
+
if (!(x3.ov > 0)) return false;
|
|
3037
|
+
if (drawnBeneath(x3.mk, tx, txRoot)) return true;
|
|
3038
|
+
if (effAlpha(x3.mk) >= PILL_MIN_ALPHA) over++;
|
|
3039
|
+
return false;
|
|
3040
|
+
});
|
|
3041
|
+
if (over > 0) report.paintedOver++;
|
|
3012
3042
|
const pts = glyphSampleGrid({ left: tr.left, top: tr.top, width: tr.width, height: tr.height });
|
|
3013
3043
|
const painted = pts.map(() => false);
|
|
3014
3044
|
let unmeasured = 0;
|
|
@@ -3308,7 +3338,16 @@ function createChartHost(container, config) {
|
|
|
3308
3338
|
if (!el) el = resolver.penetrateOverlayAt(e?.clientX, e?.clientY, clickSel);
|
|
3309
3339
|
if (!el) el = resolver.resolveByGeometry(e?.clientX, e?.clientY, clickSel);
|
|
3310
3340
|
if (!el) {
|
|
3311
|
-
if (current && current.length)
|
|
3341
|
+
if (current && current.length) {
|
|
3342
|
+
const slot = container[CONTAINER_SLOT_XF_CLEAR];
|
|
3343
|
+
if (typeof slot === "function") {
|
|
3344
|
+
try {
|
|
3345
|
+
slot();
|
|
3346
|
+
} catch {
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
if (current && current.length) notify([], "user");
|
|
3350
|
+
}
|
|
3312
3351
|
return;
|
|
3313
3352
|
}
|
|
3314
3353
|
const rows = parseRowIdxs(el.getAttribute(ROW_IDX_ATTR));
|
package/dist/index.mjs
CHANGED
|
@@ -128,7 +128,7 @@ import {
|
|
|
128
128
|
unpinScrolledAxis,
|
|
129
129
|
valuePlacementFlag,
|
|
130
130
|
x
|
|
131
|
-
} from "./chunk-
|
|
131
|
+
} from "./chunk-EFOEZN4D.mjs";
|
|
132
132
|
import "./chunk-A2GMXZP7.mjs";
|
|
133
133
|
import "./chunk-GHODWOAL.mjs";
|
|
134
134
|
|
|
@@ -2114,6 +2114,88 @@ function sweepCandidates(seedHex) {
|
|
|
2114
2114
|
return out;
|
|
2115
2115
|
}
|
|
2116
2116
|
|
|
2117
|
+
// src/pendingGenerate.ts
|
|
2118
|
+
var PENDING_RECOVERY_WINDOW_MS = 9e5;
|
|
2119
|
+
var PENDING_RECOVERY_POLL_MS = 15e3;
|
|
2120
|
+
var PENDING_RECOVERY_FIRST_POLL_MS = 2e3;
|
|
2121
|
+
var PENDING_RECOVERY_FAST_PHASE_MS = 12e4;
|
|
2122
|
+
var PENDING_RECOVERY_MID_POLL_MS = 3e4;
|
|
2123
|
+
var PENDING_RECOVERY_SLOW_PHASE_MS = 3e5;
|
|
2124
|
+
var PENDING_RECOVERY_SLOW_POLL_MS = 6e4;
|
|
2125
|
+
function pendingRecoveryNextDelayMs(elapsedMs) {
|
|
2126
|
+
if (elapsedMs < PENDING_RECOVERY_FAST_PHASE_MS) return PENDING_RECOVERY_POLL_MS;
|
|
2127
|
+
if (elapsedMs < PENDING_RECOVERY_SLOW_PHASE_MS) return PENDING_RECOVERY_MID_POLL_MS;
|
|
2128
|
+
return PENDING_RECOVERY_SLOW_POLL_MS;
|
|
2129
|
+
}
|
|
2130
|
+
function encodePendingGenerate(m2) {
|
|
2131
|
+
const o2 = { v: m2.v, t: m2.t, c: m2.c, p: m2.p ?? "" };
|
|
2132
|
+
if (Number.isFinite(m2.h)) o2.h = Math.max(0, Math.floor(m2.h));
|
|
2133
|
+
return JSON.stringify(o2);
|
|
2134
|
+
}
|
|
2135
|
+
function parsePendingGenerate(raw) {
|
|
2136
|
+
if (typeof raw !== "string" || raw.trim() === "") return null;
|
|
2137
|
+
try {
|
|
2138
|
+
const o2 = JSON.parse(raw);
|
|
2139
|
+
const v2 = Number(o2?.v), t2 = Number(o2?.t);
|
|
2140
|
+
if (!Number.isFinite(v2) || v2 <= 0 || !Number.isFinite(t2) || t2 <= 0) return null;
|
|
2141
|
+
const h2 = Number(o2?.h);
|
|
2142
|
+
const m2 = { v: Math.floor(v2), t: Math.floor(t2), c: typeof o2.c === "string" ? o2.c : "", p: typeof o2.p === "string" ? o2.p : "" };
|
|
2143
|
+
if (Number.isFinite(h2) && h2 >= 0) m2.h = Math.floor(h2);
|
|
2144
|
+
return m2;
|
|
2145
|
+
} catch {
|
|
2146
|
+
return null;
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
function markerArmedBlind(m2) {
|
|
2150
|
+
if (!m2) return false;
|
|
2151
|
+
return (m2.h ?? m2.v - 1) <= 0;
|
|
2152
|
+
}
|
|
2153
|
+
function isBlindMarker(m2) {
|
|
2154
|
+
if (!m2) return false;
|
|
2155
|
+
return typeof m2.c !== "string" || m2.c.trim() === "";
|
|
2156
|
+
}
|
|
2157
|
+
function servedCorrelationProves(m2, served) {
|
|
2158
|
+
if (!m2 || typeof m2.c !== "string" || m2.c.trim() === "") return false;
|
|
2159
|
+
if (typeof served !== "string" || served.trim() === "") return false;
|
|
2160
|
+
return served.trim().toLowerCase() === m2.c.trim().toLowerCase();
|
|
2161
|
+
}
|
|
2162
|
+
function sameMarker(a2, b2) {
|
|
2163
|
+
if (!a2 || !b2) return false;
|
|
2164
|
+
if (typeof a2.c !== "string" || typeof b2.c !== "string") return false;
|
|
2165
|
+
const ca = a2.c.trim().toLowerCase(), cb = b2.c.trim().toLowerCase();
|
|
2166
|
+
if (ca === "" || cb === "") return false;
|
|
2167
|
+
return ca === cb;
|
|
2168
|
+
}
|
|
2169
|
+
function decidePendingRecovery(m2, nowMs, persistedVersion) {
|
|
2170
|
+
if (!m2) return "none";
|
|
2171
|
+
if ((persistedVersion ?? 0) >= m2.v) return "delivered";
|
|
2172
|
+
if (nowMs - m2.t > PENDING_RECOVERY_WINDOW_MS) return "expired";
|
|
2173
|
+
if (isBlindMarker(m2)) return "blind";
|
|
2174
|
+
return "poll";
|
|
2175
|
+
}
|
|
2176
|
+
function recoveryPollRunning(d2) {
|
|
2177
|
+
return d2 === "poll";
|
|
2178
|
+
}
|
|
2179
|
+
function recoveryOwnsTheSentence(trigger) {
|
|
2180
|
+
return trigger !== "transport-lost";
|
|
2181
|
+
}
|
|
2182
|
+
function latePickupAction(m2, triedThisInstance) {
|
|
2183
|
+
if (!m2 || isBlindMarker(m2)) return "clear";
|
|
2184
|
+
return triedThisInstance ? "keep" : "fetch";
|
|
2185
|
+
}
|
|
2186
|
+
function latePickupKeepsMarker(outcome) {
|
|
2187
|
+
return outcome === "transport";
|
|
2188
|
+
}
|
|
2189
|
+
function pollGiveUpKeepsMarker(outcome, m2) {
|
|
2190
|
+
return outcome === "window-closed" && !!m2 && !isBlindMarker(m2);
|
|
2191
|
+
}
|
|
2192
|
+
function pendingRecoveryRemainingMs(m2, nowMs) {
|
|
2193
|
+
return Math.max(0, m2.t + PENDING_RECOVERY_WINDOW_MS - nowMs);
|
|
2194
|
+
}
|
|
2195
|
+
function transportFailureShouldRecover(headersReceived, genNew) {
|
|
2196
|
+
return headersReceived && genNew;
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2117
2199
|
// src/index.ts
|
|
2118
2200
|
function registerCityTable(packed) {
|
|
2119
2201
|
L3(packed);
|
|
@@ -2177,6 +2259,13 @@ export {
|
|
|
2177
2259
|
MIN_HIT_BAND_PX,
|
|
2178
2260
|
MIN_RAMP_FILLS,
|
|
2179
2261
|
PAGE_MATCH_TOLERANCE,
|
|
2262
|
+
PENDING_RECOVERY_FAST_PHASE_MS,
|
|
2263
|
+
PENDING_RECOVERY_FIRST_POLL_MS,
|
|
2264
|
+
PENDING_RECOVERY_MID_POLL_MS,
|
|
2265
|
+
PENDING_RECOVERY_POLL_MS,
|
|
2266
|
+
PENDING_RECOVERY_SLOW_PHASE_MS,
|
|
2267
|
+
PENDING_RECOVERY_SLOW_POLL_MS,
|
|
2268
|
+
PENDING_RECOVERY_WINDOW_MS,
|
|
2180
2269
|
PHANTOM_FRACTION,
|
|
2181
2270
|
PILL_MIN_ALPHA,
|
|
2182
2271
|
PILL_MIN_COVERAGE,
|
|
@@ -2229,7 +2318,9 @@ export {
|
|
|
2229
2318
|
createMarkResolver,
|
|
2230
2319
|
ctmScaleOf,
|
|
2231
2320
|
decideLabelColor,
|
|
2321
|
+
decidePendingRecovery,
|
|
2232
2322
|
deltaEHex,
|
|
2323
|
+
encodePendingGenerate,
|
|
2233
2324
|
ensureCrossfilterHitTargets,
|
|
2234
2325
|
explainRenderFailure,
|
|
2235
2326
|
filterFitsChooser,
|
|
@@ -2245,14 +2336,18 @@ export {
|
|
|
2245
2336
|
hitBandFlag,
|
|
2246
2337
|
inlineFilterGate,
|
|
2247
2338
|
isBlankRender,
|
|
2339
|
+
isBlindMarker,
|
|
2248
2340
|
isHorizontalLabelRow,
|
|
2249
2341
|
isPhantomBox,
|
|
2250
2342
|
isPillBackdropAlpha,
|
|
2251
2343
|
labelBand,
|
|
2344
|
+
latePickupAction,
|
|
2345
|
+
latePickupKeepsMarker,
|
|
2252
2346
|
launchFavorStyle,
|
|
2253
2347
|
launchGenerates,
|
|
2254
2348
|
listNeedsFilter,
|
|
2255
2349
|
loadGeo,
|
|
2350
|
+
markerArmedBlind,
|
|
2256
2351
|
measureContainerBoxes,
|
|
2257
2352
|
needsScroll,
|
|
2258
2353
|
newQualifyGroupState,
|
|
@@ -2262,6 +2357,9 @@ export {
|
|
|
2262
2357
|
normalizeFilterTerm,
|
|
2263
2358
|
orderMostDistinct,
|
|
2264
2359
|
orderRefusalsForDisplay,
|
|
2360
|
+
parsePendingGenerate,
|
|
2361
|
+
pendingRecoveryNextDelayMs,
|
|
2362
|
+
pendingRecoveryRemainingMs,
|
|
2265
2363
|
periodTickSuppressesFeedback,
|
|
2266
2364
|
pickDistinctColorFromSeed,
|
|
2267
2365
|
pillBacksGlyph,
|
|
@@ -2269,6 +2367,7 @@ export {
|
|
|
2269
2367
|
planAxisPin,
|
|
2270
2368
|
planFrameGrow,
|
|
2271
2369
|
planTrivialChart,
|
|
2370
|
+
pollGiveUpKeepsMarker,
|
|
2272
2371
|
qualifyAuto,
|
|
2273
2372
|
qualifyCancel,
|
|
2274
2373
|
qualifyFailureFallsOpen,
|
|
@@ -2281,6 +2380,8 @@ export {
|
|
|
2281
2380
|
rasterizeSvgToPngDataUrl,
|
|
2282
2381
|
readQualifyChartRow,
|
|
2283
2382
|
readQualifyRefusalRow,
|
|
2383
|
+
recoveryOwnsTheSentence,
|
|
2384
|
+
recoveryPollRunning,
|
|
2284
2385
|
refusalIsSelectable,
|
|
2285
2386
|
registerCityTable,
|
|
2286
2387
|
registerGeo,
|
|
@@ -2289,7 +2390,9 @@ export {
|
|
|
2289
2390
|
requiredD3Plugins,
|
|
2290
2391
|
resolveAutoColorScale,
|
|
2291
2392
|
resolveOptions,
|
|
2393
|
+
sameMarker,
|
|
2292
2394
|
scrollFitFor,
|
|
2395
|
+
servedCorrelationProves,
|
|
2293
2396
|
sessionViewStateProvider,
|
|
2294
2397
|
shouldOpenChooserOnGenerate,
|
|
2295
2398
|
shouldOpenInlineChooserOnGenerate,
|
|
@@ -2299,6 +2402,7 @@ export {
|
|
|
2299
2402
|
svgNaturalSize,
|
|
2300
2403
|
svgToDataUrl,
|
|
2301
2404
|
toRGBA,
|
|
2405
|
+
transportFailureShouldRecover,
|
|
2302
2406
|
unpinScrolledAxis,
|
|
2303
2407
|
valuePlacementFlag,
|
|
2304
2408
|
vegaSpecReadsDatesInLocalTime
|
package/dist/react.mjs
CHANGED
package/dist/types/index.d.ts
CHANGED
|
@@ -32,3 +32,4 @@ export { pinScrolledAxis, unpinScrolledAxis, type AxisPinReport } from "./fitDom
|
|
|
32
32
|
export { MIN_DELTA_E, pickDistinctColorFromSeed, buildPalette, buildPaletteFromSeed, orderMostDistinct, LEGIBLE_LIGHTNESS, type PaletteResult, type SeedForSlot, type PaletteOptions, } from "./palette";
|
|
33
33
|
export { deltaEHex } from "./deltaE";
|
|
34
34
|
export { resolveAutoColorScale, autoRampMinStep, autoRampCanvas, AUTO_RAMP_CLASSES, AUTO_RAMP_DRAWN_OPACITY, AUTO_RAMP_MIN_STEP_DELTA_E, type AutoColorScale, type AutoColorScaleInput } from "./autoRamp";
|
|
35
|
+
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, type PendingGenerateMarker, type PendingRecoveryDecision, type LatePickupAction, } from "./pendingGenerate";
|
|
@@ -27,6 +27,9 @@ export interface LabelContrastReport {
|
|
|
27
27
|
offFill: number;
|
|
28
28
|
/** Labels mostly over the page with one end clipping a mark - handed back to the chart. */
|
|
29
29
|
pageMajority: number;
|
|
30
|
+
/** Labels with a painting shape over their box that was set aside because it is drawn ON TOP
|
|
31
|
+
* of them - an occluder, never a background. See drawnBeneath. */
|
|
32
|
+
paintedOver: number;
|
|
30
33
|
/** Why the pass did nothing, when it did nothing. */
|
|
31
34
|
skipped?: "no-container" | "no-shapes" | "too-many-shapes" | "too-many-texts" | "error";
|
|
32
35
|
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
export interface PendingGenerateMarker {
|
|
2
|
+
/** The version this generate will produce: (version in hand || 0) + 1.
|
|
3
|
+
* Diagnostic only - see "WHY `v` IS NOT A PREDICTION" below before trusting it. */
|
|
4
|
+
v: number;
|
|
5
|
+
/** Epoch ms when the generate started (client clock). */
|
|
6
|
+
t: number;
|
|
7
|
+
/** Correlation id of the generate - the ONLY safe handle for recovering it. */
|
|
8
|
+
c: string;
|
|
9
|
+
/** The explicit chart-type pick the user made for this generate ("" = none). */
|
|
10
|
+
p: string;
|
|
11
|
+
/** The version the host actually HELD when the generate started (0 = none).
|
|
12
|
+
* Absent on markers written by older builds. Diagnostics, plus the blind test. */
|
|
13
|
+
h?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare const PENDING_RECOVERY_WINDOW_MS = 900000;
|
|
16
|
+
/** Poll cadence for the first {@link PENDING_RECOVERY_FAST_PHASE_MS}. Each poll is one
|
|
17
|
+
* cheap fetch (and one server log row), so this is deliberately slow: the cost of finding the
|
|
18
|
+
* chart 15 s late is nothing next to the cost of a second generation. */
|
|
19
|
+
export declare const PENDING_RECOVERY_POLL_MS = 15000;
|
|
20
|
+
/** First poll after a re-mount fires quickly - the service may already be done. */
|
|
21
|
+
export declare const PENDING_RECOVERY_FIRST_POLL_MS = 2000;
|
|
22
|
+
/** Up to here the poll runs at {@link PENDING_RECOVERY_POLL_MS} - covers production's p50. */
|
|
23
|
+
export declare const PENDING_RECOVERY_FAST_PHASE_MS = 120000;
|
|
24
|
+
/** ...then at this cadence up to {@link PENDING_RECOVERY_SLOW_PHASE_MS}. */
|
|
25
|
+
export declare const PENDING_RECOVERY_MID_POLL_MS = 30000;
|
|
26
|
+
export declare const PENDING_RECOVERY_SLOW_PHASE_MS = 300000;
|
|
27
|
+
/** ...and at this one for the rest of the window. */
|
|
28
|
+
export declare const PENDING_RECOVERY_SLOW_POLL_MS = 60000;
|
|
29
|
+
/**
|
|
30
|
+
* How long to wait before the NEXT poll, given how long the generate has been running.
|
|
31
|
+
*
|
|
32
|
+
* Tripling the window would have tripled the poll count at a flat 15 s (60 requests, 60 server log
|
|
33
|
+
* rows), and every one of them after the first couple of minutes is asking about a generate that is
|
|
34
|
+
* plainly slow. So the cadence backs off with age while leaving the FAST phase exactly as it was - a
|
|
35
|
+
* chart that lands inside production's normal range is still picked up within 15 s of finishing,
|
|
36
|
+
* which is the case that actually happens.
|
|
37
|
+
*
|
|
38
|
+
* 0 - 2 min every 15 s (9 polls) production p50 82 s lands here
|
|
39
|
+
* 2 - 5 min every 30 s (6 polls) production p99 383 s lands here
|
|
40
|
+
* 5 - 15 min every 60 s (10 polls) the long tail
|
|
41
|
+
*
|
|
42
|
+
* ~25 polls across 15 minutes, against 60 for a flat cadence over the same window.
|
|
43
|
+
*/
|
|
44
|
+
export declare function pendingRecoveryNextDelayMs(elapsedMs: number): number;
|
|
45
|
+
export declare function encodePendingGenerate(m: PendingGenerateMarker): string;
|
|
46
|
+
export declare function parsePendingGenerate(raw: unknown): PendingGenerateMarker | null;
|
|
47
|
+
export type PendingRecoveryDecision = "none" | "delivered" | "expired" | "blind" | "poll";
|
|
48
|
+
/**
|
|
49
|
+
* What to do with a marker found at mount (or after a transport failure).
|
|
50
|
+
* @param persistedVersion the version the host HAS, 0/null = none
|
|
51
|
+
*/
|
|
52
|
+
/**
|
|
53
|
+
* Was this marker armed holding NO version? If so its `v` is 1, which the service reads as "the
|
|
54
|
+
* shape's first chart" rather than "this host's first chart". `h` is the explicit signal; the
|
|
55
|
+
* `v - 1` fallback says the same thing for markers written by older builds.
|
|
56
|
+
*/
|
|
57
|
+
export declare function markerArmedBlind(m: PendingGenerateMarker | null | undefined): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Can this marker be recovered AT ALL? Only by CORRELATION, so only if it carries one.
|
|
60
|
+
*
|
|
61
|
+
* A version number is never a safe handle, not even when we held one: the number we hold came FROM
|
|
62
|
+
* the service and is therefore a shape version, so "mine + 1" is still a guess about what everyone
|
|
63
|
+
* else did next. The poll consequently asks by correlation ALONE and sends no version at all - which
|
|
64
|
+
* is also what makes this safe against a service too old to understand the field, because such a
|
|
65
|
+
* service refuses a fetchOnly request with no version and can serve nothing. A marker with no
|
|
66
|
+
* correlation (written by an older build) has no usable handle and is not polled.
|
|
67
|
+
*
|
|
68
|
+
* One definition, shared by the mount-time decision and the transport-lost message.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isBlindMarker(m: PendingGenerateMarker | null | undefined): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Does `served` (the service's statement of whose generation it returned) prove this marker's
|
|
73
|
+
* chart? Absence is REFUSAL, not assent: an older service says nothing here, and a recovery that
|
|
74
|
+
* cannot tell your chart from a stranger's is worse than no recovery.
|
|
75
|
+
*/
|
|
76
|
+
export declare function servedCorrelationProves(m: PendingGenerateMarker | null | undefined, served: string | null | undefined): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Are these the SAME pending generate? By correlation, never by version.
|
|
79
|
+
*
|
|
80
|
+
* Found 2026-08-30, and the log showed the bug in two adjacent lines. A poll was running for one
|
|
81
|
+
* correlation when the user clicked Generate again, arming a second. The poll's "has the marker
|
|
82
|
+
* changed under me?" guard compared `m.v` - and EVERY marker armed by a host holding no chart is
|
|
83
|
+
* `v: 1`, so `1 !== 1` was false and the stale poll did not notice it had been superseded. Four
|
|
84
|
+
* minutes later its window closed and it cleared the marker belonging to the generate that was
|
|
85
|
+
* still running:
|
|
86
|
+
*
|
|
87
|
+
* pending-gen-poll-end {"outcome":"window-closed","c":"<the first correlation>"}
|
|
88
|
+
* pending-gen-cleared {"reason":"poll-window-closed","c":"<the second correlation>"}
|
|
89
|
+
*
|
|
90
|
+
* The live generate lost its recovery marker 35 s after starting, and the user was told "nothing
|
|
91
|
+
* was delivered" about a chart that was still being written. The same lesson as `v` above: a shape
|
|
92
|
+
* version that the whole account moves can never identify one host's request. The correlation can.
|
|
93
|
+
*
|
|
94
|
+
* Two markers with no correlation are never "the same" - there is nothing to compare, and a false
|
|
95
|
+
* match here is what clears a stranger's marker.
|
|
96
|
+
*/
|
|
97
|
+
export declare function sameMarker(a: PendingGenerateMarker | null | undefined, b: PendingGenerateMarker | null | undefined): boolean;
|
|
98
|
+
export declare function decidePendingRecovery(m: PendingGenerateMarker | null, nowMs: number, persistedVersion: number | null | undefined): PendingRecoveryDecision;
|
|
99
|
+
/**
|
|
100
|
+
* Did the recovery actually START A PICKUP? Only "poll" does - "expired", "delivered", "blind" and
|
|
101
|
+
* "none" all clear the marker and walk away.
|
|
102
|
+
*
|
|
103
|
+
* ONE definition, because the caller's SENTENCE has to agree with it. Found 2026-08-28: a generate
|
|
104
|
+
* ran nearly seventeen minutes, the transport died, and the transport-lost branch chose its wording
|
|
105
|
+
* from `isBlindMarker` alone - true enough on its own terms, the marker did carry a correlation -
|
|
106
|
+
* while the recovery had already returned "expired" against the window and polled for nothing. The
|
|
107
|
+
* user was told the chart was being checked for and would appear, with nothing checking for
|
|
108
|
+
* anything. A property of the MARKER cannot answer a question about the DECISION; only the decision
|
|
109
|
+
* can.
|
|
110
|
+
*/
|
|
111
|
+
export declare function recoveryPollRunning(d: PendingRecoveryDecision): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Does the RECOVERY PATH own the sentence for this trigger, or does its caller?
|
|
114
|
+
*
|
|
115
|
+
* On "transport-lost" the host's retry loop is mid-render and already owns the message, which it
|
|
116
|
+
* words from the decision (recoveryPollRunning above). Anything the recovery says on top of that
|
|
117
|
+
* stacks a second sentence stating the same fact, and when both are painted the reader sees it twice
|
|
118
|
+
* in slightly different words - seen 2026-09-04, where the connection-dropped explanation appeared
|
|
119
|
+
* back to back with itself.
|
|
120
|
+
*
|
|
121
|
+
* On a MOUNT (or any other trigger) nothing else speaks, so the recovery must.
|
|
122
|
+
*/
|
|
123
|
+
export declare function recoveryOwnsTheSentence(trigger: string): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* THE ONE-SHOT LATE PICKUP.
|
|
126
|
+
*
|
|
127
|
+
* An EXPIRED marker used to be cleared on sight. But "expired" is a fact about the POLL WINDOW, not
|
|
128
|
+
* about the chart: the service writes the generation when it finishes and serves it by correlation
|
|
129
|
+
* for good. Seen in production: a corporate egress proxy cut the stream at 66 s, the poll armed, the
|
|
130
|
+
* host stopped reporting within seconds, the service finished at 75 s - and a reader who reopened
|
|
131
|
+
* the report later would have found the marker, called it expired, and cleared a finished, charged
|
|
132
|
+
* chart.
|
|
133
|
+
*
|
|
134
|
+
* So a MOUNT that finds an expired marker with a correlation fetches ONCE before letting go:
|
|
135
|
+
* "fetch" - a correlation to ask by, and this host instance has not asked for it yet;
|
|
136
|
+
* "keep" - this instance already asked (its own poll ran out, or a pickup already tried), so the
|
|
137
|
+
* marker waits for the NEXT mount - a data refresh seconds after the window closed must not
|
|
138
|
+
* spend the one fetch before a slow generate has finished;
|
|
139
|
+
* "clear" - no marker, or no correlation to ask by (a version is never a safe handle).
|
|
140
|
+
*/
|
|
141
|
+
export type LatePickupAction = "fetch" | "keep" | "clear";
|
|
142
|
+
export declare function latePickupAction(m: PendingGenerateMarker | null | undefined, triedThisInstance: boolean): LatePickupAction;
|
|
143
|
+
/**
|
|
144
|
+
* After the late pickup's one fetch: only a TRANSPORT failure keeps the marker - the question never
|
|
145
|
+
* reached the service, so a later mount may still ask. An answer of not-found, or a definitive
|
|
146
|
+
* refusal, is the service saying there is nothing to deliver, and the marker goes.
|
|
147
|
+
*/
|
|
148
|
+
export declare function latePickupKeepsMarker(outcome: "found" | "not-yet" | "hard-error" | "transport"): boolean;
|
|
149
|
+
/**
|
|
150
|
+
* When the 15-minute poll runs out ("window-closed"), the marker STAYS for the next mount's late
|
|
151
|
+
* pickup, as long as it carries a correlation. A definitive refusal ("hard-error") still clears it.
|
|
152
|
+
*/
|
|
153
|
+
export declare function pollGiveUpKeepsMarker(outcome: string, m: PendingGenerateMarker | null | undefined): boolean;
|
|
154
|
+
/** Milliseconds left in the recovery window from `nowMs`, floored at 0. */
|
|
155
|
+
export declare function pendingRecoveryRemainingMs(m: PendingGenerateMarker, nowMs: number): number;
|
|
156
|
+
/**
|
|
157
|
+
* Whether a transport failure on a generate should hand off to the recovery poll (true) or fall back
|
|
158
|
+
* to the ordinary retry (false). The discriminator is whether the service ACCEPTED the request: a
|
|
159
|
+
* streaming endpoint commits its 200 headers the moment it starts, so headers-received plus a later
|
|
160
|
+
* failure means the generate is running server-side and a retry would make a SECOND chart. No
|
|
161
|
+
* headers means the service never saw it, and retrying is the right move.
|
|
162
|
+
*/
|
|
163
|
+
export declare function transportFailureShouldRecover(headersReceived: boolean, genNew: boolean): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicharts/chart-host",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.103",
|
|
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",
|