@forgecharts/sdk 1.5.71 → 1.5.73

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.
@@ -47,8 +47,14 @@ function timeframeToMs(tf) {
47
47
  const secs = parseTfSeconds(tf);
48
48
  return secs !== null ? secs * 1e3 : null;
49
49
  }
50
+ function normalizeTimeframe(tf) {
51
+ const m = /^(\d+)([a-zA-Z])$/.exec(tf.trim());
52
+ if (!m) return tf.trim();
53
+ const unit = m[2];
54
+ return m[1] + (unit === "M" ? unit : unit.toLowerCase());
55
+ }
50
56
  function parseTfSeconds(tf) {
51
- const m = /^(\d+)(s|m|h|d|w|M)$/.exec(tf);
57
+ const m = /^(\d+)(s|m|h|d|w|M)$/.exec(normalizeTimeframe(tf));
52
58
  if (!m) return null;
53
59
  const n = parseInt(m[1], 10);
54
60
  const unit = m[2];
@@ -64,6 +70,7 @@ function parseTfSeconds(tf) {
64
70
  return unitSec !== void 0 ? n * unitSec : null;
65
71
  }
66
72
  function getBucketStart(timeMs, timeframe) {
73
+ timeframe = normalizeTimeframe(timeframe);
67
74
  if (timeframe === "1w") return getWeekBucketStart(timeMs);
68
75
  if (timeframe === "1M") return getMonthBucketStart(timeMs);
69
76
  if (timeframe === "3M") return getQuarterBucketStart(timeMs);
@@ -7670,32 +7677,7 @@ function formatCountdown(secs) {
7670
7677
  return `${m}:${String(s).padStart(2, "0")}`;
7671
7678
  }
7672
7679
  function tfToSeconds(tf) {
7673
- const map = {
7674
- "1s": 1,
7675
- "5s": 5,
7676
- "10s": 10,
7677
- "15s": 15,
7678
- "30s": 30,
7679
- "1m": 60,
7680
- "3m": 180,
7681
- "5m": 300,
7682
- "15m": 900,
7683
- "30m": 1800,
7684
- "1h": 3600,
7685
- "2h": 7200,
7686
- "4h": 14400,
7687
- "6h": 21600,
7688
- "8h": 28800,
7689
- "12h": 43200,
7690
- "1D": 86400,
7691
- "3D": 259200,
7692
- "1W": 604800,
7693
- "1M": 2592e3,
7694
- "3M": 7776e3,
7695
- "6M": 15552e3,
7696
- "12M": 31536e3
7697
- };
7698
- return map[tf] ?? 3600;
7680
+ return parseTfSeconds(tf) ?? 3600;
7699
7681
  }
7700
7682
  var PixiLastPriceRenderer = class {
7701
7683
  _lineGfx;
@@ -9680,34 +9662,16 @@ var PixiChart = class {
9680
9662
  }
9681
9663
  return { time: bestBar.time, price: snappedPrice };
9682
9664
  }
9683
- /** Convert a Timeframe string to seconds (internal helper). */
9665
+ /**
9666
+ * Convert a Timeframe string to seconds (internal helper).
9667
+ *
9668
+ * Delegates to the shared parser — this was one of three private maps, and
9669
+ * the only one still keyed '1D'/'1W' uppercase, so canonical '1d' fell to
9670
+ * the 3600 fallback here while '1D' fell to the 1m fallback everywhere
9671
+ * else. One derivation, one dialect.
9672
+ */
9684
9673
  _tfToSeconds(tf) {
9685
- const map = {
9686
- "1s": 1,
9687
- "5s": 5,
9688
- "10s": 10,
9689
- "15s": 15,
9690
- "30s": 30,
9691
- "1m": 60,
9692
- "3m": 180,
9693
- "5m": 300,
9694
- "15m": 900,
9695
- "30m": 1800,
9696
- "1h": 3600,
9697
- "2h": 7200,
9698
- "4h": 14400,
9699
- "6h": 21600,
9700
- "8h": 28800,
9701
- "12h": 43200,
9702
- "1D": 86400,
9703
- "3D": 259200,
9704
- "1W": 604800,
9705
- "1M": 2592e3,
9706
- "3M": 7776e3,
9707
- "6M": 15552e3,
9708
- "12M": 31536e3
9709
- };
9710
- return map[tf] ?? 3600;
9674
+ return parseTfSeconds(tf) ?? 3600;
9711
9675
  }
9712
9676
  // ─── Option resolvers ────────────────────────────────────────────────────────
9713
9677
  _resolveOptions(opts) {
@@ -18367,7 +18331,7 @@ var DEMONSTRATION_STROKE = "rgba(255, 200, 50, 0.7)";
18367
18331
  var DEMONSTRATION_COLOR = "var(--crosshair-overlay, rgba(255,255,255,0.75))";
18368
18332
 
18369
18333
  // src/version.ts
18370
- var FORGECHARTS_VERSION = "1.5.71" ;
18334
+ var FORGECHARTS_VERSION = "1.5.73" ;
18371
18335
  function applyRuntimeConfig(caps, config) {
18372
18336
  if (!config) return caps;
18373
18337
  const orderEntry = config.enableOrderEntry === false ? false : caps.orderEntry;
@@ -18594,11 +18558,19 @@ var _listeners = /* @__PURE__ */ new Set();
18594
18558
  var _subscribed = /* @__PURE__ */ new Set();
18595
18559
  var _reconnectTimer = null;
18596
18560
  var _authToken = null;
18561
+ var _baseUrl = null;
18597
18562
  function setWsAuthToken(token) {
18598
18563
  _authToken = token;
18599
18564
  }
18565
+ function setWsBaseUrl(url) {
18566
+ if (!url) {
18567
+ _baseUrl = null;
18568
+ return;
18569
+ }
18570
+ _baseUrl = url.replace(/\/$/, "").replace(/^http/, "ws");
18571
+ }
18600
18572
  function _wsUrl() {
18601
- const base = typeof window === "undefined" ? "ws://localhost:4001/ws" : `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/ws`;
18573
+ const base = _baseUrl ?? (typeof window === "undefined" ? "ws://localhost:4001/ws" : `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/ws`);
18602
18574
  return _authToken ? `${base}?token=${encodeURIComponent(_authToken)}` : base;
18603
18575
  }
18604
18576
  function _send(msg) {
@@ -26198,6 +26170,7 @@ function IndicatorsDialog({ onAdd, onClose, maxIndicators, getAuthToken }) {
26198
26170
  ] }) });
26199
26171
  }
26200
26172
  var DEFAULT_FAVORITES = ["1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w"];
26173
+ var chipLabel = (tf) => /^\d+[dw]$/.test(tf) ? tf.toUpperCase() : tf;
26201
26174
  var TF_LABELS = {
26202
26175
  "1m": "1 minute",
26203
26176
  "2m": "2 minutes",
@@ -26637,7 +26610,7 @@ function TopToolbar({
26637
26610
  onClick: () => onTimeframeChange(tf),
26638
26611
  children: tf
26639
26612
  },
26640
- tf
26613
+ chipLabel(tf)
26641
26614
  )),
26642
26615
  /* @__PURE__ */ jsx(
26643
26616
  "button",
@@ -30205,6 +30178,7 @@ function ScriptDrawer({ onClose, onAddIndicator, apiUrl, getAuthToken }) {
30205
30178
  const [savedScripts, setSavedScripts] = useState([]);
30206
30179
  const [scriptsMenuOpen, setScriptsMenuOpen] = useState(false);
30207
30180
  const [saving, setSaving] = useState(false);
30181
+ const [saveError, setSaveError] = useState(null);
30208
30182
  const [activeScriptId, setActiveScriptId] = useState(null);
30209
30183
  const [saveNameInput, setSaveNameInput] = useState("");
30210
30184
  const [showSaveNamePrompt, setShowSaveNamePrompt] = useState(false);
@@ -30298,6 +30272,7 @@ function ScriptDrawer({ onClose, onAddIndicator, apiUrl, getAuthToken }) {
30298
30272
  }, [scriptsMenuOpen]);
30299
30273
  const handleSaveScript = useCallback(async (name) => {
30300
30274
  setSaving(true);
30275
+ setSaveError(null);
30301
30276
  const base = apiUrl ?? "";
30302
30277
  const auth = await _authHeaders();
30303
30278
  const scriptSource = code;
@@ -30305,27 +30280,28 @@ function ScriptDrawer({ onClose, onAddIndicator, apiUrl, getAuthToken }) {
30305
30280
  const scriptName = name ?? extractScriptName(scriptSource);
30306
30281
  try {
30307
30282
  if (activeScriptId) {
30308
- await fetch(`${base}/api/scripts/${encodeURIComponent(activeScriptId)}/versions`, {
30283
+ const res = await fetch(`${base}/api/scripts/${encodeURIComponent(activeScriptId)}/versions`, {
30309
30284
  method: "POST",
30310
30285
  headers: { "Content-Type": "application/json", ...auth },
30311
30286
  body: JSON.stringify({ source: scriptSource })
30312
30287
  });
30288
+ if (!res.ok) throw new Error(`save failed (${res.status})`);
30313
30289
  } else {
30314
30290
  const res = await fetch(`${base}/api/scripts`, {
30315
30291
  method: "POST",
30316
30292
  headers: { "Content-Type": "application/json", ...auth },
30317
30293
  body: JSON.stringify({ name: scriptName, language: scriptLang, source: scriptSource })
30318
30294
  });
30319
- if (res.ok) {
30320
- const created = await res.json();
30321
- setActiveScriptId(created.id);
30322
- }
30295
+ if (!res.ok) throw new Error(`save failed (${res.status})`);
30296
+ const created = await res.json();
30297
+ setActiveScriptId(created.id);
30323
30298
  }
30324
30299
  await fetchSavedScripts();
30325
- } catch {
30300
+ setShowSaveNamePrompt(false);
30301
+ } catch (err) {
30302
+ setSaveError(err instanceof Error ? err.message : "save failed");
30326
30303
  }
30327
30304
  setSaving(false);
30328
- setShowSaveNamePrompt(false);
30329
30305
  }, [apiUrl, _authHeaders, code, activeScriptId, extractScriptName, fetchSavedScripts]);
30330
30306
  const handleSaveClick = useCallback(() => {
30331
30307
  if (activeScriptId) {
@@ -30428,6 +30404,16 @@ function ScriptDrawer({ onClose, onAddIndicator, apiUrl, getAuthToken }) {
30428
30404
  ]
30429
30405
  }
30430
30406
  ),
30407
+ saveError && /* @__PURE__ */ jsx(
30408
+ "span",
30409
+ {
30410
+ className: "script-save-error",
30411
+ role: "alert",
30412
+ title: saveError,
30413
+ style: { color: "var(--fc-danger, #e5484d)", fontSize: 11, marginLeft: 6 },
30414
+ children: saveError
30415
+ }
30416
+ ),
30431
30417
  /* @__PURE__ */ jsxs("div", { className: "script-my-scripts-wrap", ref: scriptsMenuRef, children: [
30432
30418
  /* @__PURE__ */ jsxs(
30433
30419
  "button",
@@ -31518,6 +31504,8 @@ function ChartWorkspace({
31518
31504
  symbolResolver,
31519
31505
  rollRule,
31520
31506
  onRollRuleChange,
31507
+ quotesWsUrl,
31508
+ getQuotesAuthToken,
31521
31509
  extraTfGroups,
31522
31510
  // RightToolbar
31523
31511
  watchlistOpen,
@@ -31574,6 +31562,27 @@ function ChartWorkspace({
31574
31562
  tradingBridge,
31575
31563
  tradingOverlayStore
31576
31564
  }) {
31565
+ const [quotesReady, setQuotesReady] = React11.useState(false);
31566
+ React11.useEffect(() => {
31567
+ let cancelled = false;
31568
+ if (!quotesWsUrl || !getQuotesAuthToken) {
31569
+ setQuotesReady(false);
31570
+ return void 0;
31571
+ }
31572
+ void (async () => {
31573
+ try {
31574
+ const token = await getQuotesAuthToken();
31575
+ if (cancelled) return;
31576
+ setWsAuthToken(token || null);
31577
+ setWsBaseUrl(quotesWsUrl);
31578
+ setQuotesReady(true);
31579
+ } catch {
31580
+ }
31581
+ })();
31582
+ return () => {
31583
+ cancelled = true;
31584
+ };
31585
+ }, [quotesWsUrl, getQuotesAuthToken]);
31577
31586
  const capabilities = useChartCapabilities();
31578
31587
  const dataBlocked = useLicenseDataBlocked();
31579
31588
  useHostLicense(hostApiUrl, getAuthToken);
@@ -31754,7 +31763,7 @@ function ChartWorkspace({
31754
31763
  onClose: closeWatchlist,
31755
31764
  onSelectSymbol: onSymbolChange,
31756
31765
  symbolResolver,
31757
- liveQuotes: false,
31766
+ liveQuotes: quotesReady,
31758
31767
  ...hostApiUrl !== void 0 ? { apiUrl: hostApiUrl } : {},
31759
31768
  ...getAuthToken !== void 0 ? { getAuthToken } : {}
31760
31769
  }
@@ -36606,7 +36615,7 @@ var ManagedAppShell = forwardRef(
36606
36615
  const res = await fetch(`${base}/api/scripts`, {
36607
36616
  method: "POST",
36608
36617
  headers: { ...auth, "Content-Type": "application/json" },
36609
- body: JSON.stringify({ name, source, language: "tscript" })
36618
+ body: JSON.stringify({ name, source, language: "forgescript" })
36610
36619
  });
36611
36620
  if (!res.ok) throw new Error(`Failed to create script (${res.status})`);
36612
36621
  const data = await res.json();