openalgo-charts
Version:
From-scratch, dependency-free canvas charting engine for OpenAlgo: professional-grade interactive rendering, advanced on-chart trading, and a one-call widget tier that adds the toolbar, drawing rail, dialogs and shortcuts.
2 lines (1 loc) • 45 kB
JavaScript
if("undefined"==typeof OpenAlgoCharts)throw new Error("openalgo-charts.workspace.standalone.js needs openalgo-charts.standalone.js loaded before it");this.OpenAlgoCharts=this.OpenAlgoCharts||{},this.OpenAlgoCharts.workspace=function(e,t){"use strict";function n(e){return"string"==typeof e&&("right"===e||"left"===e||""===e||e.startsWith("overlay:"))}const a=5242880;class r extends Error{constructor(e){super(e),this.name="WorkspaceDocumentError"}}const o=new Set(["__proto__","prototype","constructor","apikey","secret","clientsecret","apisecret","password","passwordhash","token","accesstoken","refreshtoken","authtoken","authorization","credentials","credential","auth","armed","oneclick","orders","positions","balances","balance","accountbalance","accountid","account"]);function i(e){if("string"==typeof e){if(e.length>a||(new TextEncoder).encode(e).length>a)throw new r("Document size limit exceeded");try{e=JSON.parse(e)}catch{throw new r("Invalid document JSON")}}let t=0,i=0;const s=new Set,c=(e,l,d=!1,p=!1)=>{if(++t>1e5)throw new r("Document node limit exceeded");if(l>32)throw new r("Document depth limit exceeded");if(null===e||"boolean"==typeof e)return e;if("string"==typeof e){if(i+=e.length,i>a)throw new r("Document size limit exceeded");return e}if("number"==typeof e&&Number.isFinite(e))return e;if("object"!=typeof e)throw new r("Document values must be finite JSON data");if(s.has(e))throw new r("Document contains a cycle");if(!Array.isArray(e)&&![Object.prototype,null].includes(Object.getPrototypeOf(e)))throw new r("Document objects must be plain records");if(d||p)for(const t of Reflect.ownKeys(e)){if(Array.isArray(e)&&"length"===t)continue;const n=Object.getOwnPropertyDescriptor(e,t);if("string"!=typeof t||!n.enumerable||Array.isArray(e)&&(!/^(0|[1-9]\d*)$/.test(t)||Number(t)>=e.length))throw new r((p?"Plot scale map":"Opaque payload")+" properties must survive JSON")}let u;if(s.add(e),Array.isArray(e)){if(e.length>1e5)throw new r("Document array limit exceeded");const t=[];for(let n=0;n<e.length;n++){const a=Object.getOwnPropertyDescriptor(e,String(n));if(!a||!("value"in a))throw new r("Document arrays must contain data values");t.push(c(a.value,l+1,d))}u=t}else{const t={},s=Object.getOwnPropertyDescriptor(e,"settings")?.value,h=!d&&"string"==typeof Object.getOwnPropertyDescriptor(e,"indicatorId")?.value&&"number"==typeof Object.getOwnPropertyDescriptor(e,"paneIndex")?.value&&null!==s&&"object"==typeof s&&!Array.isArray(s);for(const s of Object.keys(e)){const u=s.toLowerCase().replace(/[^a-z0-9_]/g,"").replace(/_/g,"");if(!p&&(o.has(s)||o.has(u))){if(d)throw new r("Opaque payload contains a private workspace field");continue}if(i+=s.length,i>a)throw new r("Document size limit exceeded");const f=Object.getOwnPropertyDescriptor(e,s);if(!("value"in f))throw new r("Document accessors are not allowed");if(p&&!n(f.value))throw new r("Invalid indicator plot priceScaleId");const m=c(f.value,l+1,d||"payload"===s,h&&"plotPriceScaleIds"===s);p?Object.defineProperty(t,s,{value:m,enumerable:!0,configurable:!0,writable:!0}):t[s]=m}u=t}return s.delete(e),u},l=c(e,0);if((new TextEncoder).encode(JSON.stringify(l)).length>a)throw new r("Document size limit exceeded");return l}function s(e,t){if(null===e||"object"!=typeof e||Array.isArray(e))throw new r(`${t} must be an object`);return e}function c(e,t,n){if(!Array.isArray(e)||e.length>n)throw new r(`${t} must be an array within the ${n} item limit`);return e}function l(e,t,n=200,a=!1){if("string"!=typeof e||!a&&0===e.trim().length||e.length>n||Array.from(e).some(e=>e.charCodeAt(0)<32))throw new r(`${t} must be ${a?"0":"1"}-${n} characters`);return e.trim()}function d(e,t,n,a=Number.MAX_SAFE_INTEGER,o=!1){if("number"!=typeof e||!Number.isFinite(e)||e<n||e>a||o&&!Number.isInteger(e))throw new r(`${t} must be ${o?"an integer":"a number"} between ${n} and ${a}`);return e}function p(e,t,n){if(void 0===e&&void 0!==n)return n;if("boolean"!=typeof e)throw new r(`${t} must be a boolean`);return e}function u(e,t,n,a){if(void 0===e&&void 0!==a)return a;if("string"!=typeof e||!n.includes(e))throw new r(`${t} is not supported`);return e}function h(e){return!1===e?.removable||!1===e?.listed}const f=31,m=256;function w(e,t){if(e.kind!==t||1!==e.version)throw new r(`Unsupported ${t} kind or version`);const n=d(e.createdAt,"createdAt",0);return{version:1,id:l(e.id,"id",100),name:l(e.name,"name",120),createdAt:n,updatedAt:d(e.updatedAt,"updatedAt",n)}}function g(e,t){if(!n(e))throw new r(`Invalid ${t}`);return e}function y(e,n=!0,a=!0){const o=new Set;return c(e,"indicators",m).map(e=>{const i=s(e,"indicator"),h=s(i.settings,"indicator settings"),m={indicatorId:l(i.indicatorId,"indicatorId"),settings:h,paneIndex:d(i.paneIndex,"indicator paneIndex",0,f,!0)};if(void 0!==i.studyInputs){const e=c(i.studyInputs,"indicator studyInputs",1e5).map(e=>{if("string"!=typeof e||!e.trim())throw new r("Invalid study input key");const t=s(h[e],"study input reference");if("indicator"!==t.kind||3!==Object.keys(t).length)throw new r("Invalid study input reference");const n=l(t.instanceId,"study input instanceId");if("string"!=typeof t.plotKey||!t.plotKey.trim())throw new r("Invalid study input plotKey");return h[e]={kind:"indicator",instanceId:n,plotKey:t.plotKey},e});if(new Set(e).size!==e.length)throw new r("Duplicate study input key");m.studyInputs=e}if(void 0!==i.visible&&(m.visible=p(i.visible,"indicator visibility")),void 0!==i.barSource&&(m.barSource=u(i.barSource,"indicator bar source",["chart","underlying"])),a&&void 0!==i.policy){let e;try{e=t.parseIndicatorPolicy(i.policy)}catch{throw new r("Invalid indicator policy")}Object.keys(e).length&&(m.policy={...e})}if(void 0!==i.priceScaleId&&(m.priceScaleId=g(i.priceScaleId,"indicator priceScaleId")),void 0!==i.plotPriceScaleIds){const e=s(i.plotPriceScaleIds,"indicator plotPriceScaleIds"),t=Object.entries(e).map(([e,t])=>[e,g(t,"indicator plot priceScaleId")]);t.length&&(m.plotPriceScaleIds=Object.fromEntries(t))}if(n&&void 0!==i.instanceId){if(m.instanceId=l(i.instanceId,"indicator instanceId"),o.has(m.instanceId))throw new r("Duplicate indicator instance ID");o.add(m.instanceId)}return m})}function v(e){return y(i(e))}function I(e){const t=!0===e.indicatorRange?.manual;delete e.indicatorRange,delete e.fixedRange,t||(e.autoScale=!0,delete e.range,delete e.ratioLock)}function b(e,n=!1,a){const o=function(e){const n=e.map(e=>s(e,"indicator")),a=n.map(e=>{if(void 0===e.policy)return!1;try{return h(t.parseIndicatorPolicy(e.policy))}catch{throw new r("Invalid indicator policy")}}),o=new Set,i=e=>{const t=e.settings,n=Array.isArray(e.studyInputs)?e.studyInputs:[];return null!==t&&"object"==typeof t&&!Array.isArray(t)&&n.some(e=>{const n="string"==typeof e?t[e]:void 0;return null!==n&&"object"==typeof n&&!Array.isArray(n)&&"string"==typeof n.instanceId&&o.has(n.instanceId)})};for(let e=!0;e;)e=!1,n.forEach((t,n)=>{!a[n]&&i(t)&&(a[n]=e=!0),a[n]&&"string"==typeof t.instanceId&&!o.has(t.instanceId)&&(o.add(t.instanceId),e=!0)});return{kept:e.filter((e,t)=>!a[t]),left:o}}(c(e,"indicators",m)),i=o.kept;for(const e of o.left)a?.add(e);const l=i.some(e=>{const t=s(e,"indicator").studyInputs;return Array.isArray(t)&&t.length>0}),d=y(i,l||n,!1);if(n&&d.some(e=>void 0===e.instanceId))throw new r("Template layout requires every indicator instance ID");if(!l)return d;const p=new Map(d.flatMap((e,t)=>void 0===e.instanceId?[]:[[e.instanceId,t]])),u=d.map((e,t)=>(e.studyInputs??[]).map(n=>{const a=e.settings[n],o=p.get(a.instanceId);if(void 0===o)throw new r(`External study dependency: ${a.instanceId}`);if(o===t)throw new r("A study cannot depend on itself");return o})),f=new Set,w=new Set,g=e=>{if(f.has(e))throw new r("Study dependencies contain a cycle");if(!w.has(e)){f.add(e);for(const t of u[e])g(t);f.delete(e),w.add(e)}};for(let e=0;e<d.length;e++)g(e);return d}function _(e){return c(e,"chart panes",32).map(e=>{try{const n=t.parsePaneState(e);d(n.weight,"pane weight",Number.MIN_VALUE);for(const e of[n.priceScale,...Object.values(n.scales??{})])if(e){if(d(e.marginTop,"marginTop",0,1),d(e.marginBottom,"marginBottom",0,1),d(e.minMove,"minMove",0),e.marginTop+e.marginBottom>=1)throw new r("Price scale margins leave no chart area");for(const t of[e.range,e.fixedRange])if(t&&(d(t.min,"range.min",-Number.MAX_SAFE_INTEGER),d(t.max,"range.max",t.min),t.max===t.min))throw new r("Price scale range must have positive width")}return n}catch(e){throw new r(e instanceof Error?e.message:"Invalid pane scale state")}})}function S(e){if(Array.isArray(e))return{indicators:b(e)};const t=s(e,"indicator template payload"),n=new Set,a=b(t.indicators,void 0!==t.layout,n);if(void 0===t.layout)return{indicators:a};const o=s(t.layout,"indicator template layout"),i=_(o.panes);if(!i.length)throw new r("Template layout needs pane zero");const p=new Map(a.map(e=>[e.instanceId,e]));for(const e of a)if(e.paneIndex>=i.length)throw new r("Template indicator pane is missing");for(const e of i)for(const t of[e.priceScale,...Object.values(e.scales??{})]){const e=t?.indicatorRange;if(t&&e&&n.has(e.instanceId))I(t);else if(t?.indicatorRange&&!p.has(t.indicatorRange.instanceId))throw new r("Template scale range owner is missing")}const u=(e,t)=>{if("right"!==t&&!i[e].scales?.[t])throw new r("Template plot or primary scale is missing")},h=new Map,f=c(o.plots,"template plot bindings",1e5).filter(e=>{const t=s(e,"template plot binding").instanceId;return"string"!=typeof t||!n.has(t)}).map(e=>{const t=s(e,"template plot binding"),n=l(t.instanceId,"template plot instanceId"),a=p.get(n);if(!a)throw new r("Template plot indicator is missing");if("string"!=typeof t.plotKey)throw new r("Template plot key must be a string");const o=t.plotKey,c=d(t.paneIndex,"template plot paneIndex",0,i.length-1,!0);if(0!==c&&c!==a.paneIndex)throw new r("Template plot belongs to another pane");const f=g(t.scaleId,"template plot scaleId");u(c,f);const m=h.get(n)??new Map;if(m.has(o))throw new r("Duplicate template plot binding");return m.set(o,f),h.set(n,m),{instanceId:n,plotKey:o,paneIndex:c,scaleId:f}});for(const e of a)for(const[t,n]of Object.entries(e.plotPriceScaleIds??{}))if(h.get(e.instanceId)?.get(t)!==n)throw new r("Template plot override needs a matching scale binding");const m={indicators:a,layout:{panes:i,plots:f}};if(void 0!==o.primaryScaleId){const e=g(o.primaryScaleId,"template primaryScaleId");u(0,e),m.layout.primaryScaleId=e}return m}function A(e){return S(i(e))}function k(e){const n=s(e,"chart");if(1!==n.version&&2!==n.version)throw new r("Unsupported chart version");const a={version:2===n.version?2:1};void 0!==n.timezone&&(a.timezone=l(n.timezone,"timezone",100));for(const e of["navigation","canvas","statusLine","watermark","trading","events","axisChrome"])void 0!==n[e]&&Object.assign(a,{[e]:s(n[e],e)});if(void 0!==n.viewport){const e=s(n.viewport,"viewport"),t=d(e.from,"viewport.from",-Number.MAX_SAFE_INTEGER);a.viewport={from:t,to:d(e.to,"viewport.to",t)}}if(void 0!==n.barSpacing&&(a.barSpacing=d(n.barSpacing,"barSpacing",Number.MIN_VALUE)),void 0!==n.grid){const e=s(n.grid,"grid");a.grid={vertLines:p(e.vertLines,"vertical grid"),horzLines:p(e.horzLines,"horizontal grid")}}if(void 0!==n.crosshairMode&&(a.crosshairMode=u(n.crosshairMode,"crosshairMode",["normal","magnet"])),void 0!==n.crosshairSnapToBar&&(a.crosshairSnapToBar=p(n.crosshairSnapToBar,"crosshairSnapToBar")),void 0!==n.priceOnlyAutoScale&&(a.priceOnlyAutoScale=p(n.priceOnlyAutoScale,"priceOnlyAutoScale")),void 0!==n.indicatorLegendCollapsed&&(a.indicatorLegendCollapsed=p(n.indicatorLegendCollapsed,"indicatorLegendCollapsed")),void 0!==n.indicators&&(a.indicators=y(n.indicators)),void 0!==n.sourceAbove&&(a.sourceAbove=l(n.sourceAbove,"sourceAbove")),void 0!==n.alerts)try{a.alerts=t.parseAlertsDocument(n.alerts)}catch(e){throw new r(e instanceof Error?e.message:"Invalid alert document")}if(void 0!==n.drawings){if(null===n.drawings||"object"!=typeof n.drawings)throw new r("drawings must be a document or array");a.drawings=n.drawings}if(void 0!==n.panes&&(a.panes=_(n.panes)),void 0!==n.primaryPane){if(2!==n.version)throw new r("A moved price pane needs chart version 2");if(a.primaryPane=d(n.primaryPane,"primaryPane",0,f,!0),!a.panes||a.primaryPane>=a.panes.length)throw new r("The price pane slot must name a saved pane")}return void 0!==n.series&&(a.series=c(n.series,"series descriptors",512).map(e=>{const t=s(e,"series"),n=t.priceScaleId;if("string"!=typeof n)throw new r("priceScaleId must be a string");const a={type:l(t.type,"series type"),style:s(t.style,"series style"),paneIndex:d(t.paneIndex,"series paneIndex",0,f,!0),priceScaleId:n};return void 0!==t.transform&&(a.transform=function(e){const t=s(e,"series transform"),n={type:l(t.type,"series transform type",100)};if(void 0===t.options)return n;const a=s(t.options,"series transform options");for(const e of Object.values(a))if("string"!=typeof e&&("number"!=typeof e||!Number.isFinite(e)))throw new r("Series transform options must be finite numbers or text");return n.options=a,n}(t.transform)),a})),a}function x(e){const n=s(e,"workspace pane"),a=s(n.settings??{},"settings");for(const e of Object.values(a))if(!["string","number","boolean"].includes(typeof e))throw new r("Chart settings must be scalar values");const o=c(n.comparisons??[],"comparisons",32).map(e=>{const t=s(e,"comparison"),n={id:l(t.id,"comparison id",100),symbol:l(t.symbol,"comparison symbol"),exchange:l(t.exchange,"comparison exchange",200,!0),visible:p(t.visible,"comparison visibility",!0)};return void 0!==t.color&&(n.color=l(t.color,"comparison color",200)),n});if(new Set(o.map(e=>e.id)).size!==o.length)throw new r("Duplicate comparison ID");const i={id:l(n.id,"pane id",100),symbol:l(n.symbol,"symbol"),exchange:l(n.exchange,"exchange",200,!0),interval:l(n.interval,"interval",100),chartType:l(n.chartType,"chartType",100),chart:k(n.chart),settings:a,volume:p(n.volume,"volume",!0),magnet:u(n.magnet,"magnet",["off","weak","strong"],"off"),stay:p(n.stay,"stay",!1),comparisons:o,comparisonMode:u(n.comparisonMode,"comparisonMode",["price","percent"],"percent")};if(void 0!==n.historyPeriod&&(i.historyPeriod=l(n.historyPeriod,"historyPeriod",100)),void 0!==n.variant){let e;try{e=t.normalizeDataVariant(n.variant)}catch(e){throw new r(e instanceof Error?e.message:"Invalid data variant")}e&&(i.variant={...e})}return void 0!==n.linkGroup&&(i.linkGroup=l(n.linkGroup,"linkGroup",100)),i}function D(e,t){const n={crosshair:p(e.crosshair,`${t}crosshair sync`,!0),viewport:p(e.viewport,`${t}viewport sync`,!0),symbol:p(e.symbol,`${t}symbol sync`,!1),interval:p(e.interval,`${t}interval sync`,!1)};for(const a of["appearance","chartType","drawings"])void 0!==e[a]&&(n[a]=p(e[a],`${t}${a} sync`));return void 0!==e.whenMissing&&(n.whenMissing=u(e.whenMissing,`${t}whenMissing`,["nearest","hide"])),n}function O(e){const t=c(e.panes,"panes",16).map(x);if(0===t.length)throw new r("A workspace needs at least one pane");const n=new Set(t.map(e=>e.id));if(n.size!==t.length)throw new r("Duplicate pane ID");const a=l(e.activePaneId,"activePaneId",100);if(!n.has(a))throw new r("Focused pane is missing");const o=s(e.layout,"layout"),i=d(o.rows,"rows",1,8,!0),p=d(o.columns,"columns",1,8,!0),u=new Set,h=new Set,f=c(o.slots,"layout slots",16).map(e=>{const t=s(e,"slot"),a={paneId:l(t.paneId,"slot paneId",100),row:d(t.row,"row",0,i-1,!0),column:d(t.column,"column",0,p-1,!0),rowSpan:d(t.rowSpan??1,"rowSpan",1,i,!0),columnSpan:d(t.columnSpan??1,"columnSpan",1,p,!0)};if(!n.has(a.paneId)||u.has(a.paneId))throw new r("Invalid or duplicate layout pane ID");if(u.add(a.paneId),a.row+a.rowSpan>i||a.column+a.columnSpan>p)throw new r("Layout slot is outside the grid");for(let e=a.row;e<a.row+a.rowSpan;e++)for(let t=a.column;t<a.column+a.columnSpan;t++){const n=e*p+t;if(h.has(n))throw new r("Layout slots overlap");h.add(n)}return a});if(u.size!==t.length)throw new r("Every pane needs one layout slot");const m=s(e.sync??{},"sync"),w={layout:{rows:i,columns:p,slots:f},panes:t,activePaneId:a,sync:D(m,"")};void 0!==m.groups&&(w.sync.groups=function(e){const t=new Set;return c(e,"link groups",16).map(e=>{const n=s(e,"link group"),a=l(n.id,"link group id",100);if(t.has(a))throw new r("Duplicate link group ID");return t.add(a),{id:a,name:l(n.name,"link group name",120),...D(n,"link group ")}})}(m.groups));const g=new Set(w.sync.groups?.map(e=>e.id));for(const e of t)if(void 0!==e.linkGroup&&!g.has(e.linkGroup))throw new r(`Link group ${e.linkGroup} is not declared`);void 0!==o.preset&&(w.layout.preset=l(o.preset,"layout preset",100));for(const[e,t]of[["rowWeights",i],["columnWeights",p]]){if(void 0===o[e])continue;const n=c(o[e],e,8).map(t=>d(t,e,Number.MIN_VALUE,1e3));if(n.length!==t)throw new r(`${e} must match the number of grid tracks`);w.layout[e]=n}return w}function E(e){const t=s(i(e),"workspace");return{kind:"workspace",...w(t,"workspace"),...O(t)}}function P(e){return O(s(i(e),"workspace"))}function T(e){const t=s(i(e),"indicator template");return{kind:"indicator-template",...w(t,"indicator-template"),...S(t)}}const j=e=>i(e);function M(){if(!globalThis.crypto?.randomUUID)throw new r("Supply an ID factory when crypto.randomUUID is unavailable");return globalThis.crypto.randomUUID()}class ${constructor(e,t,n,a){Object.defineProperty(this,"_storage",{enumerable:!0,configurable:!0,writable:!0,value:e}),Object.defineProperty(this,"_kind",{enumerable:!0,configurable:!0,writable:!0,value:n}),Object.defineProperty(this,"_empty",{enumerable:!0,configurable:!0,writable:!0,value:a}),Object.defineProperty(this,"namespace",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_listeners",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),Object.defineProperty(this,"_queue",{enumerable:!0,configurable:!0,writable:!0,value:Promise.resolve()}),this.namespace=l(t,"storage namespace")}async load(){return await this._queue,this._read()}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}transact(e,t={}){const{signal:n}=t,a=void 0===t.expectedRevision?void 0:d(t.expectedRevision,"expected revision",0,Number.MAX_SAFE_INTEGER,!0),r=this._queue.then(async()=>{n?.throwIfAborted();const t=await this._read();if(n?.throwIfAborted(),void 0!==a&&t.revision!==a)throw this._kind.conflict();const r=t.revision,o=e(t);t.revision++;const i=this._kind.parse(t);n?.throwIfAborted(),await this._storage.write(this.namespace,i,r,{signal:n});for(const e of Array.from(this._listeners))try{e(j(i))}catch(e){queueMicrotask(()=>{throw e})}return void 0===o?o:j(o)});return this._queue=r.then(()=>{},()=>{}),r}async _read(){const e=await this._storage.read(this.namespace);return null===e?this._empty():this._kind.parse(e)}}function N(e,t){const n=new Map(Object.entries(e).map(([e,t])=>[e,j(t)]));return{async read(e){const t=n.get(l(e,"storage namespace"));return void 0===t?null:j(t)},async write(e,a,o,i){i?.signal?.throwIfAborted();const s=l(e,"storage namespace"),c=d(o,"expected revision",0,Number.MAX_SAFE_INTEGER,!0),p=t.parse(a);if(p.revision!==c+1)throw new r("A write must advance the catalog revision by one");const u=n.get(s);if((void 0===u?0:t.parse(u).revision)!==c)throw t.conflict();n.set(s,p)}}}function W(e,t,n,a,o,s=0){if("replace"!==n&&"append"!==n)throw new r("Unsupported indicator template mode");if(!Number.isInteger(s)||s<0||s>f)throw new r("Invalid price pane slot");const c=v(e),l=b(i(t));if(l.some(e=>e.studyInputs?.length)&&z(c,l),"append"===n){const e=Math.max(0,...c.map(e=>e.paneIndex));if(!Number.isInteger(o)||o<=Math.max(e,s)||o>32)throw new r("Invalid next indicator pane");const t=[...new Set(l.map(e=>e.paneIndex).filter(e=>e>0))].sort((e,t)=>e-t);for(const e of l)if(e.paneIndex=e.paneIndex>0?o+t.indexOf(e.paneIndex):s,e.paneIndex>f)throw new r("Indicator pane limit exceeded")}else if(s>0)for(const e of l)e.paneIndex=C(e.paneIndex,s);const d="replace"===n?c.filter(e=>h(e.policy)):[],p=new Set(d.map(e=>e.paneIndex).filter(e=>e!==s));if(p.size){const e=[...new Set(l.map(e=>e.paneIndex).filter(e=>e!==s))].sort((e,t)=>e-t),t=new Map;let n=-1;for(const a of e){do{n++}while(p.has(n)||n===s);t.set(a,n)}for(const e of l)e.paneIndex=t.get(e.paneIndex)??e.paneIndex;if(n>f)throw new r("Indicator pane limit exceeded")}const u="replace"===n?[...d,...l]:[...c,...l];return R(u,a),u}function R(e,t){if(e.length>m)throw new r("At most 256 indicator instances are supported");const n=[...new Set(e.filter(e=>!t.has(e.indicatorId)).map(e=>e.indicatorId))];if(n.length)throw new r(`Missing indicators: ${n.join(", ")}`)}function L(e,t){return e===t?0:e<t?e+1:e}function C(e,t){return 0===e?t:e<=t?e-1:e}function z(e,t){const n=new Map;if(!t.length)return n;const a=new Set([...e,...t].flatMap(e=>void 0===e.instanceId?[]:[e.instanceId]));for(const t of e)for(const e of t.studyInputs??[])a.add(t.settings[e].instanceId);if(!globalThis.crypto?.getRandomValues)throw new r("Random IDs are unavailable for connected template copies");const o=Array.from(globalThis.crypto.getRandomValues(new Uint32Array(4)),e=>e.toString(16).padStart(8,"0")).join("");let i=1;for(const e of t){let t;do{t=`template-study-${o}-${i++}`}while(a.has(t));a.add(t),void 0!==e.instanceId&&n.set(e.instanceId,t),e.instanceId=t}for(const e of t)for(const t of e.studyInputs??[]){const a=e.settings[t];e.settings[t]={...a,instanceId:n.get(a.instanceId)}}return n}function G(e){return[["right",e.priceScale],...Object.entries(e.scales??{})]}function U(e,t){return"right"===t?e.priceScale:e.scales?.[t]}function F(e,t,n){const a=e.primarySeries();if(!a)return;const r=a.priceScale();return G(n).find(([n])=>e.panes()[t].scaleFor(n)===r)?.[0]}function K(e,t){return[e[t],...e.filter((e,n)=>n!==t)]}function X(e,t){const n=[];return e.forEach((e,a)=>{n[C(a,t)]=e}),n}function q(e){const n=e.getState(),a=n.panes;if(!a?.length)throw new r("Cannot capture a destroyed chart");const o=e.primaryPaneIndex(),i=K(a,o),s=[];for(const n of e.indicators())for(const a of t.getIndicator(n.indicatorId).plots){const t=n.series(a.key),i=n.plotPriceScaleId(a.key);if(!t||null===e.seriesType(t)||null===i)throw new r("Cannot capture a removed indicator plot");s.push({instanceId:n.id,plotKey:a.key,paneIndex:!0===a.overlay?0:L(n.paneIndex,o),scaleId:i})}const c={panes:i,plots:s},l=F(e,o,i[0]);void 0!==l&&(c.primaryScaleId=l);return A({indicators:(n.indicators??[]).map(e=>({...e,paneIndex:L(e.paneIndex,o)})),layout:c})}function B(e,t,n){const a=e.plots.find(e=>!0!==e.overlay),o=a?n.find(e=>e.plotKey===a.key).scaleId:t.priceScaleId??"right";for(const a of e.fills??[]){const e=!0===a.overlay?0:t.paneIndex,i=a.between.map(t=>n.find(e=>e.plotKey===t)??{paneIndex:e,scaleId:!0===a.overlay?"right":o});if(i.some(t=>t.paneIndex!==e)||i[0].scaleId!==i[1].scaleId)throw new r("Template fill endpoints must share their pane and scale")}}function V(e,n,a){const r=t.parsePaneState({weight:1,priceScale:e}).priceScale;return a?r.indicatorRange&&(r.indicatorRange.instanceId=n.get(r.indicatorRange.instanceId)):(r.autoScale=!0,delete r.range,delete r.ratioLock,r.indicatorRange&&(delete r.indicatorRange,delete r.fixedRange)),r}function J(e,t){for(const n of e)for(const[,e]of G(n)){const n=e.indicatorRange;n&&t.has(n.instanceId)&&I(e)}}function Z(e,n,a,o={}){if("replace"!==a&&"append"!==a)throw new r("Unsupported indicator template mode");const c=e.primaryPaneIndex(),l=function(e,n,a,o,c){const l=s(i(o),"template apply options"),d=u(l.scalePolicy,"scale policy",["copy","share"],"copy"),p="preserve"===u(l.rangePolicy,"range policy",["auto","preserve"],"auto"),m=A(n),w=e.getState();if(!w.panes?.length)throw new r("Cannot plan for a destroyed chart");const g={...w,panes:K(w.panes,c),indicators:(w.indicators??[]).map(e=>({...e,paneIndex:L(e.paneIndex,c)}))},y=new Set(t.registeredIndicators().map(e=>e.id));if(!m.layout)return{indicators:W(g.indicators,m.indicators,a,y,g.panes.length)};const I=m.layout,b=m.indicators,_=v(g.indicators??[]),S="replace"===a?_.filter(e=>h(e.policy)):[],k="append"===a?[..._,...b]:[...S,...b];R(k,y);const x=function(e,n){const a=new Map;for(const e of n.plots){const t=a.get(e.instanceId)??[];t.push(e),a.set(e.instanceId,t)}for(const n of e){const o=t.getIndicator(n.indicatorId),i=a.get(n.instanceId)??[],s=o.inputs.filter(e=>"source"===e.type&&"string"!=typeof(Object.prototype.hasOwnProperty.call(n.settings,e.key)?n.settings[e.key]:e.default)),c=new Set(n.studyInputs??[]);if(s.length!==c.size||s.some(e=>!c.has(e.key)||"source"!==e.type||!0!==e.allowStudyOutputs))throw new r("Template dependency metadata disagrees with its source inputs");for(const a of c){const o=n.settings[a],i=e.find(e=>e.instanceId===o.instanceId),s=t.getIndicator(i.indicatorId).plots.filter(e=>e.key===o.plotKey);if(1!==s.length||void 0!==s[0].ohlc)throw new r("Template study source must identify one declared scalar plot")}if(i.length!==o.plots.length)throw new r("Template needs every declared plot binding");for(const e of i){const t=o.plots.find(t=>t.key===e.plotKey);if(!t||e.paneIndex!==(!0===t.overlay?0:n.paneIndex))throw new r("Template plot key or pane disagrees with its descriptor")}B(o,n,i)}return a}(b,I),D="replace"===a?function(e){const n=e.panes().map(e=>e.series().length),a=e.primaryPaneIndex();for(const r of e.indicators())for(const o of t.getIndicator(r.indicatorId).plots){const t=r.series(o.key);t&&null!==e.seriesType(t)&&n[!0===o.overlay?a:r.paneIndex]--}return new Set(n.flatMap((e,t)=>e>0?[L(t,a)]:[]))}(e):new Set;for(const e of S)e.paneIndex>0&&D.add(e.paneIndex);const O={preserveScaleFormats:g.panes.flatMap((e,t)=>0===t||"append"===a||D.has(t)?G(e).map(([e])=>({paneIndex:t,scaleId:e})):[])};if("append"===a&&!b.length)return{indicators:_,restoreOptions:O};const E=F(e,c,g.panes[0]),P=g.panes.map(e=>t.parsePaneState(e));"replace"===a&&J(P,new Set(_.filter(e=>!S.includes(e)).flatMap(e=>e.instanceId?[e.instanceId]:[])));const T=function(e,t,n){const a=new Map([[0,0]]);let o=n;for(const n of[...new Set(e.map(e=>e.paneIndex).filter(e=>e>0))].sort((e,t)=>e-t)){for(;t.has(o);)o++;if(o>f)throw new r("Indicator pane limit exceeded");a.set(n,o++)}return a}(b,D,"append"===a?P.length:1),j=b.map(e=>e.instanceId),M=z(_,b),$=P[0],N=I.panes[0];!function(e,t,n,a){const o=e[0],i=t[0];for(const[s,c]of n){if(!s)continue;const n=t[s],l=n.weight/i.weight*o.weight;if(!(l>0&&Number.isFinite(l)))throw new r("Template pane weight is not representable");const d=a(n);e[c]={weight:l,priceScale:d[0][1],...d.length>1?{scales:Object.fromEntries(d.slice(1))}:{}}}}(P,I.panes,T,e=>G(e).map(([e,t])=>[e,V(t,M,p)]));const C=new Set(G($).map(([e])=>e)),X=new Map,q=[];let Z=1;const H=(e,t)=>{if(e>0)return t;const n=X.get(t);if(void 0!==n)return n;if(t===I.primaryScaleId&&void 0!==E)return X.set(t,E),E;let a=t;if("copy"===d)do{a=`overlay:template-scale-${b[0].instanceId}-${Z++}`}while(U($,a));if(X.set(t,a),!U($,a)){const e=U(N,t)??{marginTop:.1,marginBottom:.1,minMove:0,minPrecision:0,mode:"linear",inverted:!1,autoScale:!0},n=V(e,M,p);"right"===a?$.priceScale=n:($.scales??($.scales={}),$.scales[a]=n),"copy"===d&&q.push({id:a,source:{...e,placement:e.placement??{side:"left"===t||"right"===t?t:"hidden",order:0}}})}return a};b.forEach((e,n)=>{const a=j[n],r=e.paneIndex,o=(x.get(a)??[]).map(e=>[e.plotKey,H(e.paneIndex,e.scaleId)]);o.length&&(e.plotPriceScaleIds=Object.fromEntries(o)),void 0!==e.priceScaleId?e.priceScaleId=H(r,e.priceScaleId):t.getIndicator(e.indicatorId).plots.some(e=>!0!==e.overlay)||(e.priceScaleId=H(r,"right")),e.paneIndex=T.get(r),B(t.getIndicator(e.indicatorId),e,(x.get(a)??[]).map(t=>({...t,paneIndex:T.get(t.paneIndex),scaleId:e.plotPriceScaleIds[t.plotKey]})))});for(const e of["left","right","hidden"]){let t=Math.max(-1,...G($).filter(([e])=>C.has(e)).map(([e,t])=>t.placement??{side:"left"===e||"right"===e?e:"hidden",order:0}).filter(t=>t.side===e).map(e=>e.order))+1;for(const n of q.filter(t=>t.source.placement.side===e).sort((e,t)=>e.source.placement.order-t.source.placement.order))U($,n.id).placement={side:e,order:t++}}return{indicators:k,panes:P,restoreOptions:O}}(e,n,a,o,c);if(0===c)return l;const d={indicators:l.indicators.map(e=>({...e,paneIndex:C(e.paneIndex,c)})),panes:l.panes?X(l.panes,c):H(e,a),primaryPane:c};return l.restoreOptions&&(d.restoreOptions={preserveScaleFormats:(l.restoreOptions.preserveScaleFormats??[]).map(e=>({...e,paneIndex:C(e.paneIndex,c)}))}),d}function H(e,n){const a=e.getState(),r=(a.panes??[]).map(e=>t.parsePaneState(e));return"replace"===n&&J(r,new Set((a.indicators??[]).flatMap(e=>e.instanceId?[e.instanceId]:[]))),r}class Q extends Error{constructor(){super("The saved workspace changed in another session. Reload and retry."),this.name="WorkspaceConflictError"}}const Y={parse:ee,conflict:()=>new Q};function ee(e){const t=s(i(e),"workspace catalog");if(1!==t.version)throw new r("Unsupported workspace catalog version");const n=c(t.workspaces,"workspaces",100).map(E),a=c(t.templates,"templates",100).map(T),o=[...n,...a].map(e=>e.id);if(new Set(o).size!==o.length)throw new r("Duplicate document ID");const u=new Set(n.map(e=>e.id)),h=c(t.recentWorkspaceIds,"recent workspaces",10).map(e=>l(e,"recent workspace ID",100));if(new Set(h).size!==h.length||h.some(e=>!u.has(e)))throw new r("Invalid recent workspace IDs");const f=null===t.activeWorkspaceId?null:l(t.activeWorkspaceId,"active workspace ID",100);if(null!==f&&!u.has(f))throw new r("Active workspace is missing");return{version:1,revision:d(t.revision,"catalog revision",0,Number.MAX_SAFE_INTEGER,!0),workspaces:n,templates:a,recentWorkspaceIds:h,activeWorkspaceId:f,autosave:p(t.autosave,"autosave")}}function te(){return{version:1,revision:0,workspaces:[],templates:[],recentWorkspaceIds:[],activeWorkspaceId:null,autosave:!1}}function ne(e){const t=s(i(e),"document");if("workspace"===t.kind)return E(t);if("indicator-template"===t.kind)return T(t);throw new r("Unsupported document kind")}function ae(e,t,n,a,o){const i=l(t,"database name");let s=null,c=null,p=!1;const u=()=>new Error(`${n} storage is closed. Create a new adapter to reconnect.`);function h(){return p?Promise.reject(u()):s||(s=new Promise((t,a)=>{const r=e.open(i,1);let o=!1;r.onupgradeneeded=()=>{r.result.objectStoreNames.contains("catalogs")||r.result.createObjectStore("catalogs")},r.onblocked=()=>{o=!0,a(new Error(`${n} database is blocked by another session. Close that session and retry.`))},r.onerror=()=>{o=!0,a(r.error??new Error(`Cannot open ${n.toLowerCase()} database`))},r.onsuccess=()=>{const e=r.result;if(p||o)return e.close(),void a(u());c=e,e.onversionchange=()=>{p=!0,e.close(),c=null},e.onclose=()=>{p=!0,c=null},t(e)}}).catch(e=>{throw s=null,e}),s)}return{async read(e){const t=l(e,"storage namespace"),a=await h();return new Promise((e,r)=>{const o=a.transaction("catalogs","readonly"),i=o.objectStore("catalogs").get(t);let s=null;i.onsuccess=()=>{s=i.result??null},o.oncomplete=()=>e(s),o.onabort=()=>r(o.error??new Error(`${n} read was aborted`))})},async write(e,t,i,s){const c=s?.signal;c?.throwIfAborted();const p=l(e,"storage namespace"),u=d(i,"expected revision",0,Number.MAX_SAFE_INTEGER,!0),f=a(t);if(f.revision!==u+1)throw new r("A write must advance the catalog revision by one");const m=await h();return c?.throwIfAborted(),new Promise((e,t)=>{const r=m.transaction("catalogs","readwrite"),i=r.objectStore("catalogs"),s=i.get(p);let l;const d=()=>{try{r.abort(),l=c?.reason}catch{}},h=()=>c?.removeEventListener("abort",d);c?.addEventListener("abort",d,{once:!0}),s.onsuccess=()=>{try{const e=s.result;if((void 0===e?0:a(e).revision)!==u)throw o();i.put(f,p)}catch(e){l=e,r.abort()}},r.oncomplete=()=>{h(),e()},r.onabort=()=>{h(),t(l??r.error??new Error(`${n} save was aborted`))}})},async close(){p=!0,c&&(c.close(),c=null),s&&await s.catch(()=>{})}}}class re extends Error{constructor(){super("The saved watchlists changed in another session. Reload and retry."),this.name="WatchlistConflictError"}}function oe(e){return JSON.stringify([e.symbol,e.exchange])}function ie(e){const t=s(e,"watchlist entry");return{symbol:l(t.symbol,"symbol",64),exchange:l(t.exchange,"exchange",32,!0)}}function se(e){const t=c(e,"watchlist entries",500).map(ie);if(new Set(t.map(oe)).size!==t.length)throw new r("Duplicate watchlist entry");return t}function ce(e){const t=s(e,"watchlist"),n=d(t.createdAt,"createdAt",0);return{id:l(t.id,"watchlist ID",100),name:l(t.name,"name",120),entries:se(t.entries),createdAt:n,updatedAt:d(t.updatedAt,"updatedAt",n)}}function le(e){const t=s(i(e),"watchlist catalog");if(1!==t.version)throw new r("Unsupported watchlist catalog version");const n=c(t.lists,"watchlists",100).map(ce),a=new Set(n.map(e=>e.id));if(a.size!==n.length)throw new r("Duplicate watchlist ID");const o=null===t.activeListId?null:l(t.activeListId,"active watchlist ID",100);if(null!==o&&!a.has(o))throw new r("Active watchlist is missing");return{version:1,revision:d(t.revision,"catalog revision",0,Number.MAX_SAFE_INTEGER,!0),lists:n,activeListId:o}}const de=()=>({version:1,revision:0,lists:[],activeListId:null}),pe=e=>""===e.exchange?e.symbol:`${e.symbol} on ${e.exchange}`,ue={parse:le,conflict:()=>new re};class he extends Error{constructor(){super("The saved drawing templates changed in another session. Reload and retry."),this.name="DrawingTemplateConflictError"}}const fe=/^(style|text|props)\.[A-Za-z][A-Za-z0-9_]{0,63}$/;function me(e){const t=s(e,"template level"),n={ratio:d(t.ratio,"level ratio",-1e6,1e6)};if(void 0!==t.color&&(n.color=l(t.color,"level color",64)),void 0!==t.enabled){if("boolean"!=typeof t.enabled)throw new r("level enabled must be a boolean");n.enabled=t.enabled}return void 0!==t.label&&(n.label=l(t.label,"level label",64,!0)),n}function we(e,t){if("boolean"==typeof e)return e;if("number"==typeof e)return d(e,t,-1e9,1e9);if("string"==typeof e)return l(e,t,256,!0);if(Array.isArray(e))return c(e,t,64).map(me);throw new r(`${t} must be a string, a number, a boolean or a list of levels`)}function ge(e){const t=s(i(e),"template values"),n=Object.keys(t);if(n.length>64)throw new r("template values must be within the 64 setting limit");const a={};for(const e of n){if(!fe.test(e)||"text.value"===e)throw new r(`${e} is not a template setting`);a[e]=we(t[e],e)}return a}const ye=e=>l(e,"drawing tool",100);function ve(e){const t=s(e,"drawing template"),n=d(t.createdAt,"createdAt",0);return{id:l(t.id,"template ID",100),name:l(t.name,"name",120),tool:ye(t.tool),values:ge(t.values),createdAt:n,updatedAt:d(t.updatedAt,"updatedAt",n)}}function Ie(e){const t=s(e,"drawing default");return{tool:ye(t.tool),values:ge(t.values),updatedAt:d(t.updatedAt,"updatedAt",0)}}function be(e){const t=s(i(e),"drawing template catalog");if(1!==t.version)throw new r("Unsupported drawing template catalog version");const n=c(t.templates,"drawing templates",200).map(ve);if(new Set(n.map(e=>e.id)).size!==n.length)throw new r("Duplicate template ID");const a=c(t.defaults,"drawing defaults",200).map(Ie);if(new Set(a.map(e=>e.tool)).size!==a.length)throw new r("Duplicate tool default");return{version:1,revision:d(t.revision,"catalog revision",0,Number.MAX_SAFE_INTEGER,!0),templates:n,defaults:a}}const _e=()=>({version:1,revision:0,templates:[],defaults:[]}),Se={parse:be,conflict:()=>new he},Ae=(e,t)=>e.trim().toLowerCase()===t.trim().toLowerCase();return e.DrawingTemplateConflictError=he,e.DrawingTemplateRepository=class{constructor(e,t,n={}){Object.defineProperty(this,"_catalog",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_now",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_id",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this._catalog=new $(e,t,Se,_e),this._now=n.now??Date.now,this._id=n.id??M}get namespace(){return this._catalog.namespace}load(){return this._catalog.load()}subscribe(e){return this._catalog.subscribe(e)}async saveTemplate(e,t,n,a){const r=l(e,"name",120),o=ye(t),i=ge(n);return this._catalog.transact(e=>{const t=this._now(),n=e.templates.find(e=>e.tool===o&&Ae(e.name,r));if(n)return n.values=i,n.updatedAt=this._later(n.updatedAt,t),n;const a={id:this._newId(e),name:r,tool:o,values:i,createdAt:t,updatedAt:t};return e.templates.push(a),a},a)}async renameTemplate(e,t,n){const a=l(t,"name",120);return this._catalog.transact(t=>{const n=this._find(t,e);if(t.templates.some(e=>e!==n&&e.tool===n.tool&&Ae(e.name,a)))throw new r(`A template named ${a} already exists for this tool`);return n.name=a,n.updatedAt=this._later(n.updatedAt,this._now()),n},n)}async removeTemplate(e,t){return this._catalog.transact(t=>{const n=this._find(t,e);t.templates=t.templates.filter(e=>e!==n)},t)}async setDefault(e,t,n){const a=ye(e),r=null===t?null:ge(t);return this._catalog.transact(e=>{const t=e.defaults.find(e=>e.tool===a);if(null===r)return void(e.defaults=e.defaults.filter(e=>e!==t));const n=this._later(t?.updatedAt??0,this._now());t?(t.values=r,t.updatedAt=n):e.defaults.push({tool:a,values:r,updatedAt:n})},n)}_find(e,t){const n=l(t,"template ID",100),a=e.templates.find(e=>e.id===n);if(!a)throw new r("Saved drawing template does not exist");return a}_later(e,t){return Math.max(e,d(t,"current time",0))}_newId(e){const t=l(this._id(),"generated template ID",100);if(e.templates.some(e=>e.id===t))throw new r("Generated template ID collision");return t}},e.WORKSPACE_VERSION=1,e.WatchlistConflictError=re,e.WatchlistRepository=class{constructor(e,t,n={}){Object.defineProperty(this,"_catalog",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_now",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_id",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this._catalog=new $(e,t,ue,de),this._now=n.now??Date.now,this._id=n.id??M}get namespace(){return this._catalog.namespace}load(){return this._catalog.load()}subscribe(e){return this._catalog.subscribe(e)}async createList(e,t=[],n){const a=l(e,"name",120),r=se(i(t));return this._catalog.transact(e=>{const t=this._now(),n={id:this._newId(e),name:a,entries:r,createdAt:t,updatedAt:t};return e.lists.push(n),n},n)}async renameList(e,t,n){const a=l(t,"name",120);return this._catalog.transact(t=>this._touch(this._find(t,e),e=>{e.name=a}),n)}async duplicateList(e,t,n){const a=l(t,"name",120);return this._catalog.transact(t=>{const n=this._find(t,e),r=this._now(),o={id:this._newId(t),name:a,entries:n.entries.map(e=>({...e})),createdAt:r,updatedAt:r};return t.lists.push(o),o},n)}async removeList(e,t){return this._catalog.transact(t=>{const n=this._find(t,e);t.lists=t.lists.filter(e=>e!==n),t.activeListId===n.id&&(t.activeListId=null)},t)}async setActiveList(e,t){return this._catalog.transact(t=>{t.activeListId=null===e?null:this._find(t,e).id},t)}async addEntry(e,t,n={}){const a=ie(i(t));return this._catalog.transact(t=>this._touch(this._find(t,e),e=>{if(e.entries.some(e=>oe(e)===oe(a)))throw new r(`${pe(a)} is already in this list`);e.entries.splice(this._index(n.index??e.entries.length,e.entries.length),0,a)}),n)}async removeEntry(e,t,n){const a=ie(i(t));return this._catalog.transact(t=>this._touch(this._find(t,e),e=>{e.entries.splice(this._position(e,a),1)}),n)}async moveEntry(e,t,n,a){const r=ie(i(t));return this._catalog.transact(t=>this._touch(this._find(t,e),e=>{const[t]=e.entries.splice(this._position(e,r),1);e.entries.splice(this._index(n,e.entries.length),0,t)}),a)}_find(e,t){const n=l(t,"watchlist ID",100),a=e.lists.find(e=>e.id===n);if(!a)throw new r("Saved watchlist does not exist");return a}_touch(e,t){return t(e),e.updatedAt=Math.max(e.updatedAt,d(this._now(),"current time",0)),e}_position(e,t){const n=e.entries.findIndex(e=>oe(e)===oe(t));if(n<0)throw new r(`${pe(t)} is not in this list`);return n}_index(e,t){return Math.max(0,Math.min(t,Math.trunc(d(e,"entry index",-Number.MAX_SAFE_INTEGER))))}_newId(e){const t=l(this._id(),"generated watchlist ID",100);if(e.lists.some(e=>e.id===t))throw new r("Generated watchlist ID collision");return t}},e.WorkspaceConflictError=Q,e.WorkspaceDocumentError=r,e.WorkspaceRepository=class{constructor(e,t,n={}){Object.defineProperty(this,"_catalog",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_now",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_id",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this._catalog=new $(e,t,Y,te),this._now=n.now??Date.now,this._id=n.id??M}get namespace(){return this._catalog.namespace}load(){return this._catalog.load()}subscribe(e){return this._catalog.subscribe(e)}async createWorkspace(e,t,n){const a=P(t),r=l(e,"name",120);return this._catalog.transact(e=>{const t=this._now(),n=E({...a,kind:"workspace",version:1,id:this._newId(e),name:r,createdAt:t,updatedAt:t});return e.workspaces.push(n),n},n)}async saveWorkspace(e,t,n){const a=P(t);return this._catalog.transact(t=>{const n=this._find(t,"workspace",e),r=E({...n,...a,updatedAt:this._updatedAt(n)});return t.workspaces[t.workspaces.indexOf(n)]=r,r},n)}async createTemplate(e,t,n){const a=A(t),r=l(e,"name",120);return this._catalog.transact(e=>{const t=this._now(),n=T({kind:"indicator-template",version:1,id:this._newId(e),name:r,createdAt:t,updatedAt:t,...a});return e.templates.push(n),n},n)}async saveTemplate(e,t,n){const a=A(t);return this._catalog.transact(t=>{const n=this._find(t,"indicator-template",e),r=T({kind:"indicator-template",version:n.version,id:n.id,name:n.name,createdAt:n.createdAt,updatedAt:this._updatedAt(n),...a});return t.templates[t.templates.indexOf(n)]=r,r},n)}async rename(e,t,n,a){const r=l(n,"name",120);return this._catalog.transact(n=>{const a=this._find(n,e,t);a.name=r,a.updatedAt=this._updatedAt(a)},a)}async duplicate(e,t,n,a){const r=l(n,"name",120);return this._catalog.transact(n=>this._insert(n,this._find(n,e,t),r),a)}async remove(e,t,n){return this._catalog.transact(n=>{this._find(n,e,t),"indicator-template"===e?n.templates=n.templates.filter(e=>e.id!==t):(n.workspaces=n.workspaces.filter(e=>e.id!==t),n.recentWorkspaceIds=n.recentWorkspaceIds.filter(e=>e!==t),n.activeWorkspaceId===t&&(n.activeWorkspaceId=n.recentWorkspaceIds[0]??null))},n)}async openWorkspace(e,t){return this._catalog.transact(t=>{const n=this._find(t,"workspace",e);return t.activeWorkspaceId=n.id,t.recentWorkspaceIds=[n.id,...t.recentWorkspaceIds.filter(e=>e!==n.id)].slice(0,10),n},t)}async setAutosave(e,t){const n=p(e,"autosave");return this._catalog.transact(e=>{e.autosave=n},t)}async importDocument(e,t){const n=ne(e);return this._catalog.transact(e=>this._insert(e,n,n.name),t)}captureIndicatorTemplate(e){return q(e)}planIndicatorTemplateState(e,t,n,a){return Z(e,t,n,a)}async exportDocument(e,t){const n=await this.load();return JSON.stringify(this._find(n,e,t),null,2)}_find(e,t,n){if("workspace"!==t&&"indicator-template"!==t)throw new r("Unsupported document kind");const a=l(n,"document ID",100),o=("workspace"===t?e.workspaces:e.templates).find(e=>e.id===a);if(!o)throw new r(`Saved ${t} does not exist`);return o}_updatedAt(e){return Math.max(e.updatedAt,d(this._now(),"current time",0))}_newId(e){const t=l(this._id(),"generated document ID",100);if([...e.workspaces,...e.templates].some(e=>e.id===t))throw new r("Generated document ID collision");return t}_insert(e,t,n){const a=this._now(),r=ne({...t,name:n,id:this._newId(e),createdAt:a,updatedAt:a});return"workspace"===r.kind?e.workspaces.push(r):e.templates.push(r),r}},e.captureIndicatorTemplate=q,e.createIndexedDbDrawingTemplateStorage=function(e,t="openalgo-chart-drawing-templates"){return ae(e,t,"Drawing template",be,()=>new he)},e.createIndexedDbWatchlistStorage=function(e,t="openalgo-chart-watchlists"){return ae(e,t,"Watchlist",le,()=>new re)},e.createIndexedDbWorkspaceStorage=function(e,t="openalgo-chart-workspaces"){return ae(e,t,"Workspace",ee,()=>new Q)},e.createMemoryDrawingTemplateStorage=function(e={}){return N(e,Se)},e.createMemoryWatchlistStorage=function(e={}){return N(e,ue)},e.createMemoryWorkspaceStorage=function(e={}){return N(e,Y)},e.migrateWidgetWorkspace=function(e,t){const n=s(i(e),"widget");if(1!==n.version||void 0!==n.kind)throw new r("Unsupported widget state");const a=null===n.rail?{}:s(n.rail??{},"rail");return E({kind:"workspace",version:1,id:t.id,name:t.name,createdAt:t.now,updatedAt:t.now,panes:[{id:"p0",symbol:n.symbol,exchange:n.exchange??"",interval:n.interval,chartType:n.chartType,chart:n.chart,magnet:a.magnet??"off",stay:a.stay??!1,...void 0===n.variant?{}:{variant:n.variant},settings:{"widget.theme":u(n.theme,"theme",["light","dark"],"dark")}}],layout:{rows:1,columns:1,slots:[{paneId:"p0",row:0,column:0,rowSpan:1,columnSpan:1}]},activePaneId:"p0"})},e.parseDrawingTemplateCatalog=be,e.parseDrawingTemplateValues=ge,e.parseIndicatorStates=v,e.parseIndicatorTemplate=T,e.parseIndicatorTemplatePayload=A,e.parseWatchlistCatalog=le,e.parseWorkspaceCatalog=ee,e.parseWorkspaceDocument=E,e.parseWorkspacePayload=P,e.planIndicatorTemplate=W,e.planIndicatorTemplateState=Z,e.watchlistKey=oe,e}({},OpenAlgoCharts);