retold-data-service 2.1.5 → 2.1.6

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.
@@ -2,8 +2,8 @@
2
2
  # version tag push (e.g. `v1.2.3`). Generated by `quack docker-init`.
3
3
  #
4
4
  # Image lands at:
5
- # ghcr.io/stevenvelozo/retold-data-service:<version>
6
- # ghcr.io/stevenvelozo/retold-data-service:latest (only on stable tags)
5
+ # ghcr.io/fable-retold/retold-data-service:<version>
6
+ # ghcr.io/fable-retold/retold-data-service:latest (only on stable tags)
7
7
 
8
8
  name: Publish container image
9
9
 
@@ -110,7 +110,7 @@ BUILD_DOCKER=1 npm publish (or: npm run publish:docker)
110
110
  → postpublish: BUILD_DOCKER=1 → tag + push ← image trigger
111
111
  → .github/workflows/publish-image.yml fires
112
112
  → docker buildx build linux/amd64,linux/arm64
113
- → docker push ghcr.io/stevenvelozo/retold-data-service:<version>
113
+ → docker push ghcr.io/fable-retold/retold-data-service:<version>
114
114
  ```
115
115
 
116
116
  ---
@@ -119,7 +119,7 @@ BUILD_DOCKER=1 npm publish (or: npm run publish:docker)
119
119
 
120
120
  1. **npm**: `npm view retold-data-service version`
121
121
  2. **Workflow**: `https://github.com/fable-retold/retold-data-service/actions`
122
- 3. **Image**: `docker pull ghcr.io/stevenvelozo/retold-data-service:latest`
122
+ 3. **Image**: `docker pull ghcr.io/fable-retold/retold-data-service:latest`
123
123
 
124
124
  If the first `docker pull` returns `denied`, the package is private by
125
125
  default — flip visibility to public via Package Settings → Danger Zone
@@ -130,8 +130,8 @@ on the package page.
130
130
  ## Image consumption
131
131
 
132
132
  ```bash
133
- docker pull ghcr.io/stevenvelozo/retold-data-service:latest
134
- docker run --rm ghcr.io/stevenvelozo/retold-data-service:latest
133
+ docker pull ghcr.io/fable-retold/retold-data-service:latest
134
+ docker run --rm ghcr.io/fable-retold/retold-data-service:latest
135
135
  ```
136
136
 
137
137
  Configuration via env vars: see this module's README for the supported
package/CONTRIBUTING.md CHANGED
@@ -47,4 +47,4 @@ When in doubt, match what the surrounding code does.
47
47
 
48
48
  ## Repository Structure
49
49
 
50
- Each module is its own git repository. The [retold](https://github.com/stevenvelozo/retold) repository tracks module organization but does not contain module source code. Direct your pull request to the specific module repository where your change belongs.
50
+ Each module is its own git repository. The [retold](https://github.com/fable-retold/retold) repository tracks module organization but does not contain module source code. Direct your pull request to the specific module repository where your change belongs.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "retold-data-service",
3
- "version": "2.1.5",
3
+ "version": "2.1.6",
4
4
  "description": "Serve up a whole model!",
5
5
  "main": "source/Retold-Data-Service.js",
6
6
  "bin": {
@@ -78,8 +78,8 @@
78
78
  "devDependencies": {
79
79
  "chai": "^4.5.0",
80
80
  "jsdom": "^25.0.1",
81
- "meadow-connection-sqlite": "^1.0.20",
82
- "mocha": "^11.0.1",
81
+ "meadow-connection-sqlite": "^1.0.21",
82
+ "mocha": "^11.7.6",
83
83
  "pict-docuserve": "^1.4.19",
84
84
  "puppeteer": "^24.40.0",
85
85
  "quackage": "^1.3.0",
@@ -88,23 +88,23 @@
88
88
  },
89
89
  "dependencies": {
90
90
  "bibliograph": "^1.0.0",
91
- "fable": "^3.1.75",
91
+ "fable": "^3.1.80",
92
92
  "fable-serviceproviderbase": "^3.0.19",
93
- "meadow": "^2.0.43",
93
+ "meadow": "^2.0.47",
94
94
  "meadow-connection-manager": "^1.1.5",
95
- "meadow-connection-mysql": "^1.0.19",
95
+ "meadow-connection-mysql": "^1.0.20",
96
96
  "meadow-endpoints": "^4.0.22",
97
- "meadow-integration": "^1.0.42",
98
- "meadow-migrationmanager": "^1.0.4",
97
+ "meadow-integration": "^1.1.3",
98
+ "meadow-migrationmanager": "^1.0.5",
99
99
  "orator": "^6.1.2",
100
100
  "orator-http-proxy": "^1.0.5",
101
101
  "orator-serviceserver-restify": "^2.0.11",
102
102
  "orator-static-server": "^2.1.4",
103
- "pict": "^1.0.372",
103
+ "pict": "^1.0.393",
104
104
  "pict-provider-theme": "^1.1.2",
105
105
  "pict-section-connection-form": "^1.0.0",
106
106
  "pict-section-histogram": "^1.0.1",
107
- "pict-section-modal": "^1.1.4",
107
+ "pict-section-modal": "^1.3.2",
108
108
  "pict-section-theme": "^1.1.1",
109
109
  "pict-sessionmanager": "^1.0.2",
110
110
  "stricture": "^4.0.6"
@@ -1277,12 +1277,18 @@ fResolve(pResult);}/**
1277
1277
  * a rect-like { left, top, width, height } anchor (handy for context menus).
1278
1278
  * @param {object} pOptions
1279
1279
  * @param {Array} pOptions.items - [{ Hash, Label, Style?, Disabled?, Tooltip?, Icon?, Separator? }]
1280
- * @param {string} [pOptions.align] - 'left'|'right' (default 'left')
1280
+ * @param {string} [pOptions.ContentHTML] - Free-form HTML body for the popover, rendered
1281
+ * verbatim via innerHTML INSTEAD of building a menu from items[]. When set, the element is
1282
+ * a plain anchored popover (no role=menu / keyboard item nav); outside-click, Escape,
1283
+ * auto-flip and reposition still apply. Sanitize untrusted content. items is ignored.
1284
+ * @param {string} [pOptions.align] - 'left'|'right'|'center' (default 'left')
1281
1285
  * @param {string} [pOptions.position]- 'auto'|'below'|'above' (default 'auto')
1282
1286
  * @param {string} [pOptions.minWidth]- CSS minWidth (default: anchor width if known, else '160px')
1287
+ * @param {string} [pOptions.maxWidth]- CSS maxWidth (default unset; the base menu caps at 360px,
1288
+ * the --content variant uncaps — set this for wide rich-content popovers)
1283
1289
  * @param {string} [pOptions.maxHeight]- CSS maxHeight (default '60vh')
1284
1290
  * @param {string} [pOptions.className]- extra class(es) for the menu element
1285
- * @param {boolean} [pOptions.closeOnSelect] - default true
1291
+ * @param {boolean} [pOptions.closeOnSelect] - default true (no-op in ContentHTML mode)
1286
1292
  * @param {function} [pOptions.onSelect]- called with (Hash, Item) on selection
1287
1293
  * @param {function} [pOptions.onClose] - called after dismiss
1288
1294
  * @returns {Promise<{Hash: string, Item: object}|null>}
@@ -1306,7 +1312,21 @@ setTimeout(()=>{this._focusFirstEnabled(tmpMenu);},0);this._activeMenu={element:
1306
1312
  // ─────────────────────────────────────────────
1307
1313
  _resolveAnchor(pAnchor){if(!pAnchor){return null;}if(typeof pAnchor==='string'){return document.querySelector(pAnchor);}if(pAnchor.nodeType===1){return pAnchor;}// rect-like — no element to attach focus / outside-click ignore to,
1308
1314
  // but that's fine, the caller knows what they're doing.
1309
- return null;}_anchorRect(pAnchor,pAnchorEl){if(pAnchorEl&&typeof pAnchorEl.getBoundingClientRect==='function'){return pAnchorEl.getBoundingClientRect();}if(pAnchor&&typeof pAnchor==='object'&&typeof pAnchor.left==='number'&&typeof pAnchor.top==='number'){return{left:pAnchor.left,top:pAnchor.top,width:pAnchor.width||0,height:pAnchor.height||0,right:pAnchor.left+(pAnchor.width||0),bottom:pAnchor.top+(pAnchor.height||0)};}return null;}_buildMenu(pItems,pOptions){let tmpId=this._modal._nextId();let tmpMenu=document.createElement('div');tmpMenu.className='pict-modal-dropdown';if(pOptions.className){tmpMenu.className+=' '+pOptions.className;}tmpMenu.id='pict-modal-dropdown-'+tmpId;tmpMenu.setAttribute('role','menu');tmpMenu.style.maxHeight=pOptions.maxHeight;let tmpHtml='';for(let i=0;i<pItems.length;i++){let tmpItem=pItems[i];if(tmpItem.Separator){tmpHtml+='<div class="pict-modal-dropdown-separator" role="separator"></div>';continue;}if(tmpItem.Header){tmpHtml+='<div class="pict-modal-dropdown-header">'+this._escapeHTML(tmpItem.Header)+'</div>';continue;}let tmpCls='pict-modal-dropdown-item';if(tmpItem.Style){tmpCls+=' pict-modal-dropdown-item--'+tmpItem.Style;}if(tmpItem.Disabled){tmpCls+=' pict-modal-dropdown-item--disabled';}let tmpAttrs=''+' data-pict-modal-dropdown-item'+' data-index="'+i+'"'+' data-hash="'+this._escapeHTML(tmpItem.Hash||'')+'"'+' role="menuitem"'+' tabindex="-1"';if(tmpItem.Disabled){tmpAttrs+=' aria-disabled="true" data-disabled';}if(tmpItem.Tooltip){tmpAttrs+=' title="'+this._escapeHTML(tmpItem.Tooltip)+'"';}let tmpIcon=tmpItem.Icon?'<span class="pict-modal-dropdown-item-icon">'+tmpItem.Icon+'</span>':'';let tmpHint=tmpItem.Hint?'<span class="pict-modal-dropdown-item-hint">'+this._escapeHTML(tmpItem.Hint)+'</span>':'';tmpHtml+='<div class="'+tmpCls+'"'+tmpAttrs+'>'+tmpIcon+'<span class="pict-modal-dropdown-item-label">'+this._escapeHTML(tmpItem.Label||'')+'</span>'+tmpHint+'</div>';}tmpMenu.innerHTML=tmpHtml;return tmpMenu;}_positionMenu(pMenu,pAnchorRect,pOptions){// Apply min-width before measuring so the menu's natural size accounts
1315
+ return null;}_anchorRect(pAnchor,pAnchorEl){if(pAnchorEl&&typeof pAnchorEl.getBoundingClientRect==='function'){return pAnchorEl.getBoundingClientRect();}if(pAnchor&&typeof pAnchor==='object'&&typeof pAnchor.left==='number'&&typeof pAnchor.top==='number'){return{left:pAnchor.left,top:pAnchor.top,width:pAnchor.width||0,height:pAnchor.height||0,right:pAnchor.left+(pAnchor.width||0),bottom:pAnchor.top+(pAnchor.height||0)};}return null;}/**
1316
+ * True when the value is usable as ContentHTML — a primitive string or a
1317
+ * boxed String object (some template engines hand back `new String(...)`,
1318
+ * which is `typeof 'object'` and would otherwise slip past the guard).
1319
+ *
1320
+ * @param {*} pValue
1321
+ * @returns {boolean}
1322
+ */_isContentHTML(pValue){return typeof pValue==='string'||pValue instanceof String;}_buildMenu(pItems,pOptions){let tmpId=this._modal._nextId();let tmpMenu=document.createElement('div');tmpMenu.className='pict-modal-dropdown';// Free-form content popovers carry a modifier so the host can reset the
1323
+ // menu-item chrome (padding / max-width) and style the body itself.
1324
+ if(this._isContentHTML(pOptions.ContentHTML)){tmpMenu.className+=' pict-modal-dropdown--content';}if(pOptions.className){tmpMenu.className+=' '+pOptions.className;}tmpMenu.id='pict-modal-dropdown-'+tmpId;tmpMenu.style.maxHeight=pOptions.maxHeight;if(pOptions.maxWidth){tmpMenu.style.maxWidth=pOptions.maxWidth;}// ContentHTML mode: render the caller's HTML verbatim instead of building
1325
+ // a menu from items[]. This is a free-form anchored popover (e.g. a rich
1326
+ // info card, or a pre-rendered template menu) — not a role=menu list, so
1327
+ // we skip the menu role and the per-item keyboard semantics. Outside-click
1328
+ // / Escape / auto-flip / reposition all still apply from dropdown().
1329
+ if(this._isContentHTML(pOptions.ContentHTML)){tmpMenu.innerHTML=pOptions.ContentHTML;return tmpMenu;}tmpMenu.setAttribute('role','menu');let tmpHtml='';for(let i=0;i<pItems.length;i++){let tmpItem=pItems[i];if(tmpItem.Separator){tmpHtml+='<div class="pict-modal-dropdown-separator" role="separator"></div>';continue;}if(tmpItem.Header){tmpHtml+='<div class="pict-modal-dropdown-header">'+this._escapeHTML(tmpItem.Header)+'</div>';continue;}let tmpCls='pict-modal-dropdown-item';if(tmpItem.Style){tmpCls+=' pict-modal-dropdown-item--'+tmpItem.Style;}if(tmpItem.Disabled){tmpCls+=' pict-modal-dropdown-item--disabled';}let tmpAttrs=''+' data-pict-modal-dropdown-item'+' data-index="'+i+'"'+' data-hash="'+this._escapeHTML(tmpItem.Hash||'')+'"'+' role="menuitem"'+' tabindex="-1"';if(tmpItem.Disabled){tmpAttrs+=' aria-disabled="true" data-disabled';}if(tmpItem.Tooltip){tmpAttrs+=' title="'+this._escapeHTML(tmpItem.Tooltip)+'"';}let tmpIcon=tmpItem.Icon?'<span class="pict-modal-dropdown-item-icon">'+tmpItem.Icon+'</span>':'';let tmpHint=tmpItem.Hint?'<span class="pict-modal-dropdown-item-hint">'+this._escapeHTML(tmpItem.Hint)+'</span>':'';tmpHtml+='<div class="'+tmpCls+'"'+tmpAttrs+'>'+tmpIcon+'<span class="pict-modal-dropdown-item-label">'+this._escapeHTML(tmpItem.Label||'')+'</span>'+tmpHint+'</div>';}tmpMenu.innerHTML=tmpHtml;return tmpMenu;}_positionMenu(pMenu,pAnchorRect,pOptions){// Apply min-width before measuring so the menu's natural size accounts
1310
1330
  // for the constraint.
1311
1331
  let tmpMinWidth=pOptions.minWidth||(pAnchorRect.width>=80?Math.ceil(pAnchorRect.width)+'px':'160px');pMenu.style.minWidth=tmpMinWidth;// Measure after attaching.
1312
1332
  let tmpMenuRect=pMenu.getBoundingClientRect();let tmpVw=window.innerWidth||document.documentElement.clientWidth;let tmpVh=window.innerHeight||document.documentElement.clientHeight;let tmpGap=4;// breathing room between anchor and menu
@@ -1692,9 +1712,11 @@ class PictModalShellManager{constructor(pModalSection){this._modal=pModalSection
1692
1712
  * Show a toast notification.
1693
1713
  *
1694
1714
  * @param {string} pMessage - Toast message text
1695
- * @param {object} [pOptions] - Options (type, duration, position, dismissible)
1715
+ * @param {object} [pOptions] - Options (type, duration, position, dismissible, allowHTML)
1716
+ * @param {boolean} [pOptions.allowHTML=false] - When true, render pMessage as raw HTML instead of escaping it. Only pass trusted markup.
1696
1717
  * @returns {{ dismiss: function }} Handle with dismiss method
1697
- */toast(pMessage,pOptions){let tmpOptions=Object.assign({},this._modal.options.DefaultToastOptions,pOptions);let tmpContainer=this._getContainer(tmpOptions.position);let tmpId=this._modal._nextId();let tmpToast=document.createElement('div');tmpToast.className='pict-modal-toast pict-modal-toast--'+tmpOptions.type;tmpToast.id='pict-modal-toast-'+tmpId;let tmpContent='<span class="pict-modal-toast-message">'+this._escapeHTML(pMessage)+'</span>';if(tmpOptions.dismissible){tmpContent+='<button class="pict-modal-toast-dismiss" aria-label="Dismiss">&times;</button>';}tmpToast.innerHTML=tmpContent;// Create handle
1718
+ */toast(pMessage,pOptions){let tmpOptions=Object.assign({},this._modal.options.DefaultToastOptions,pOptions);let tmpContainer=this._getContainer(tmpOptions.position);let tmpId=this._modal._nextId();let tmpToast=document.createElement('div');tmpToast.className='pict-modal-toast pict-modal-toast--'+tmpOptions.type;tmpToast.id='pict-modal-toast-'+tmpId;// Escape by default; render raw markup only when the caller opts in with allowHTML (trusted content).
1719
+ let tmpMessageMarkup=tmpOptions.allowHTML===true?pMessage:this._escapeHTML(pMessage);let tmpContent='<span class="pict-modal-toast-message">'+tmpMessageMarkup+'</span>';if(tmpOptions.dismissible){tmpContent+='<button class="pict-modal-toast-dismiss" aria-label="Dismiss">&times;</button>';}tmpToast.innerHTML=tmpContent;// Create handle
1698
1720
  let tmpDismissed=false;let tmpTimeoutHandle=null;let tmpDismiss=()=>{if(tmpDismissed){return;}tmpDismissed=true;if(tmpTimeoutHandle){clearTimeout(tmpTimeoutHandle);}// Exit animation
1699
1721
  tmpToast.classList.remove('pict-modal-visible');tmpToast.classList.add('pict-modal-toast-exit');// Remove from active list
1700
1722
  this._modal._activeToasts=this._modal._activeToasts.filter(pEntry=>{return pEntry.element!==tmpToast;});// Remove from DOM after transition
@@ -1740,6 +1762,19 @@ if(tmpOptions.duration>0){tmpTimeoutHandle=setTimeout(tmpDismiss,tmpOptions.dura
1740
1762
  * @param {object} [pOptions] - Options (position, delay, maxWidth, interactive)
1741
1763
  * @returns {{ destroy: function }} Handle to remove the tooltip
1742
1764
  */richTooltip(pElement,pHTMLContent,pOptions){let tmpOptions=Object.assign({},this._modal.options.DefaultTooltipOptions,pOptions);return this._attachTooltip(pElement,pHTMLContent,true,tmpOptions);}/**
1765
+ * Attach a pinnable rich HTML tooltip to an element.
1766
+ *
1767
+ * Behaves like richTooltip() on hover/focus, but a click on the element
1768
+ * toggles a pinned state: while pinned the tooltip stays open (it does not
1769
+ * hide on mouseleave/focusout) and follows its anchor on scroll/resize.
1770
+ * This is opt-in sugar over richTooltip() with `{ pinnable: true }` — the
1771
+ * default tooltip()/richTooltip() behavior is unchanged.
1772
+ *
1773
+ * @param {HTMLElement} pElement - Target element
1774
+ * @param {string} pHTMLContent - HTML content for the tooltip
1775
+ * @param {object} [pOptions] - Options (position, delay, maxWidth, interactive, startPinned, onPinChange)
1776
+ * @returns {{ destroy: function, pin: function, unpin: function, isPinned: function }} Handle
1777
+ */pinnableTooltip(pElement,pHTMLContent,pOptions){let tmpOptions=Object.assign({},this._modal.options.DefaultTooltipOptions,pOptions,{pinnable:true});return this._attachTooltip(pElement,pHTMLContent,true,tmpOptions);}/**
1743
1778
  * Internal: attach tooltip event listeners to an element.
1744
1779
  *
1745
1780
  * @param {HTMLElement} pElement
@@ -1747,18 +1782,46 @@ if(tmpOptions.duration>0){tmpTimeoutHandle=setTimeout(tmpDismiss,tmpOptions.dura
1747
1782
  * @param {boolean} pIsHTML
1748
1783
  * @param {object} pOptions
1749
1784
  * @returns {{ destroy: function }}
1750
- */_attachTooltip(pElement,pContent,pIsHTML,pOptions){let tmpTooltipElement=null;let tmpShowTimeout=null;let tmpHideTimeout=null;let tmpDestroyed=false;let tmpId=this._modal._nextId();let tmpShow=()=>{if(tmpDestroyed||tmpTooltipElement){return;}tmpTooltipElement=document.createElement('div');tmpTooltipElement.className='pict-modal-tooltip pict-modal-tooltip--'+pOptions.position;tmpTooltipElement.id='pict-modal-tooltip-'+tmpId;tmpTooltipElement.setAttribute('role','tooltip');tmpTooltipElement.style.maxWidth=pOptions.maxWidth;if(pOptions.interactive){tmpTooltipElement.classList.add('pict-modal-tooltip-interactive');}// Arrow
1785
+ */_attachTooltip(pElement,pContent,pIsHTML,pOptions){let tmpTooltipElement=null;let tmpShowTimeout=null;let tmpHideTimeout=null;let tmpDestroyed=false;let tmpId=this._modal._nextId();// Pin state — only meaningful when pOptions.pinnable is set. A pinned
1786
+ // tooltip stays visible (transient hide is suppressed) and follows its
1787
+ // anchor on scroll/resize.
1788
+ let tmpPinned=false;let tmpShow=()=>{if(tmpDestroyed||tmpTooltipElement){return;}tmpTooltipElement=document.createElement('div');tmpTooltipElement.className='pict-modal-tooltip pict-modal-tooltip--'+pOptions.position;tmpTooltipElement.id='pict-modal-tooltip-'+tmpId;tmpTooltipElement.setAttribute('role','tooltip');tmpTooltipElement.style.maxWidth=pOptions.maxWidth;if(pOptions.interactive){tmpTooltipElement.classList.add('pict-modal-tooltip-interactive');}// Optional consumer-supplied class(es) on the tooltip element, e.g.
1789
+ // to theme the bubble + arrow by overriding the --pict-modal-tooltip-*
1790
+ // custom properties for a specific tooltip.
1791
+ if(pOptions.className){let tmpExtraClasses=String(pOptions.className).split(/\s+/);for(let i=0;i<tmpExtraClasses.length;i++){if(tmpExtraClasses[i]){tmpTooltipElement.classList.add(tmpExtraClasses[i]);}}}// Arrow
1751
1792
  let tmpArrow=document.createElement('div');tmpArrow.className='pict-modal-tooltip-arrow';// Content
1752
1793
  let tmpContentDiv=document.createElement('div');if(pIsHTML){tmpContentDiv.innerHTML=pContent;}else{tmpContentDiv.textContent=pContent;}tmpTooltipElement.appendChild(tmpArrow);tmpTooltipElement.appendChild(tmpContentDiv);document.body.appendChild(tmpTooltipElement);// Set aria-describedby on target
1753
1794
  pElement.setAttribute('aria-describedby',tmpTooltipElement.id);// Position
1754
- this._positionTooltip(tmpTooltipElement,pElement,pOptions.position);// Animate in
1755
- void tmpTooltipElement.offsetHeight;tmpTooltipElement.classList.add('pict-modal-visible');// Track
1795
+ this._positionTooltip(tmpTooltipElement,pElement,pOptions.position);// Animate in — but only paint when the anchor is actually rendered.
1796
+ // A pinned / startPinned tooltip whose anchor lives in a hidden
1797
+ // container (e.g. an inactive tab panel) would otherwise show at the
1798
+ // clamped corner as an orphan. It is revealed later by tmpReposition
1799
+ // once the anchor gains a layout box (see the ResizeObserver below).
1800
+ void tmpTooltipElement.offsetHeight;if(this._isElementRendered(pElement)){tmpTooltipElement.classList.add('pict-modal-visible');}// Track
1756
1801
  this._modal._activeTooltips.push({element:tmpTooltipElement,targetElement:pElement,destroy:tmpDestroy});// For interactive tooltips, allow hovering over the tooltip itself
1757
- if(pOptions.interactive&&tmpTooltipElement){tmpTooltipElement.addEventListener('mouseenter',()=>{if(tmpHideTimeout){clearTimeout(tmpHideTimeout);tmpHideTimeout=null;}});tmpTooltipElement.addEventListener('mouseleave',()=>{tmpHide();});}};let tmpHide=()=>{if(!tmpTooltipElement){return;}tmpTooltipElement.classList.remove('pict-modal-visible');let tmpEl=tmpTooltipElement;tmpTooltipElement=null;// Remove aria
1802
+ if(pOptions.interactive&&tmpTooltipElement){tmpTooltipElement.addEventListener('mouseenter',()=>{if(tmpHideTimeout){clearTimeout(tmpHideTimeout);tmpHideTimeout=null;}});tmpTooltipElement.addEventListener('mouseleave',()=>{if(!tmpPinned){tmpHide();}});}// Reflect pinned state on a freshly-(re)created element.
1803
+ if(tmpPinned&&tmpTooltipElement){tmpTooltipElement.classList.add('pict-modal-tooltip-pinned');}};let tmpHide=()=>{if(!tmpTooltipElement){return;}tmpTooltipElement.classList.remove('pict-modal-visible');let tmpEl=tmpTooltipElement;tmpTooltipElement=null;// Remove aria
1758
1804
  pElement.removeAttribute('aria-describedby');// Remove from tracking
1759
- this._modal._activeTooltips=this._modal._activeTooltips.filter(pEntry=>{return pEntry.element!==tmpEl;});setTimeout(()=>{if(tmpEl.parentNode){tmpEl.parentNode.removeChild(tmpEl);}},220);};let tmpOnMouseEnter=()=>{if(tmpHideTimeout){clearTimeout(tmpHideTimeout);tmpHideTimeout=null;}tmpShowTimeout=setTimeout(tmpShow,pOptions.delay);};let tmpOnMouseLeave=()=>{if(tmpShowTimeout){clearTimeout(tmpShowTimeout);tmpShowTimeout=null;}// Small delay before hiding to allow moving to interactive tooltip
1760
- if(pOptions.interactive){tmpHideTimeout=setTimeout(tmpHide,100);}else{tmpHide();}};let tmpOnFocusIn=()=>{tmpShowTimeout=setTimeout(tmpShow,pOptions.delay);};let tmpOnFocusOut=()=>{if(tmpShowTimeout){clearTimeout(tmpShowTimeout);tmpShowTimeout=null;}tmpHide();};// Attach listeners
1761
- pElement.addEventListener('mouseenter',tmpOnMouseEnter);pElement.addEventListener('mouseleave',tmpOnMouseLeave);pElement.addEventListener('focusin',tmpOnFocusIn);pElement.addEventListener('focusout',tmpOnFocusOut);let tmpDestroy=()=>{if(tmpDestroyed){return;}tmpDestroyed=true;if(tmpShowTimeout){clearTimeout(tmpShowTimeout);}if(tmpHideTimeout){clearTimeout(tmpHideTimeout);}tmpHide();pElement.removeEventListener('mouseenter',tmpOnMouseEnter);pElement.removeEventListener('mouseleave',tmpOnMouseLeave);pElement.removeEventListener('focusin',tmpOnFocusIn);pElement.removeEventListener('focusout',tmpOnFocusOut);};return{destroy:tmpDestroy};}/**
1805
+ this._modal._activeTooltips=this._modal._activeTooltips.filter(pEntry=>{return pEntry.element!==tmpEl;});setTimeout(()=>{if(tmpEl.parentNode){tmpEl.parentNode.removeChild(tmpEl);}},220);};let tmpOnMouseEnter=()=>{if(tmpHideTimeout){clearTimeout(tmpHideTimeout);tmpHideTimeout=null;}tmpShowTimeout=setTimeout(tmpShow,pOptions.delay);};let tmpOnMouseLeave=()=>{if(tmpShowTimeout){clearTimeout(tmpShowTimeout);tmpShowTimeout=null;}// A pinned tooltip stays open regardless of pointer.
1806
+ if(tmpPinned){return;}// Small delay before hiding to allow moving to interactive tooltip
1807
+ if(pOptions.interactive){tmpHideTimeout=setTimeout(tmpHide,100);}else{tmpHide();}};let tmpOnFocusIn=()=>{tmpShowTimeout=setTimeout(tmpShow,pOptions.delay);};let tmpOnFocusOut=()=>{if(tmpShowTimeout){clearTimeout(tmpShowTimeout);tmpShowTimeout=null;}// A pinned tooltip stays open regardless of focus.
1808
+ if(tmpPinned){return;}tmpHide();};// -- Pin lifecycle (opt-in via pOptions.pinnable) --
1809
+ // Keep a pinned tooltip glued to its anchor as the page scrolls/resizes.
1810
+ // The element is position:fixed and portaled to <body>, so it does not
1811
+ // move with the document on its own. When the anchor scrolls out of the
1812
+ // viewport we fade the tooltip out (without dropping the pin) and bring
1813
+ // it back when the anchor returns.
1814
+ let tmpResizeObserver=null;let tmpReposition=()=>{if(!tmpTooltipElement){return;}let tmpRect=pElement.getBoundingClientRect();// Rendered (has a layout box) AND within the viewport. A hidden anchor
1815
+ // (display:none, or inside a hidden tab panel) has no box, so the
1816
+ // tooltip is hidden rather than stranded at the clamped corner.
1817
+ let tmpInView=this._isElementRendered(pElement)&&tmpRect.bottom>0&&tmpRect.top<window.innerHeight&&tmpRect.right>0&&tmpRect.left<window.innerWidth;if(tmpInView){this._positionTooltip(tmpTooltipElement,pElement,pOptions.position);tmpTooltipElement.classList.add('pict-modal-visible');}else{tmpTooltipElement.classList.remove('pict-modal-visible');}};let tmpAddRepositionListeners=()=>{// `true` (capture) so scrolls inside any nested container reposition too.
1818
+ window.addEventListener('scroll',tmpReposition,true);window.addEventListener('resize',tmpReposition);// A ResizeObserver on the anchor catches it being shown/hidden (e.g. a
1819
+ // tab panel toggling display) — transitions the window scroll/resize
1820
+ // listeners miss — so a pinned tooltip appears the moment its anchor
1821
+ // gains a layout box and hides again when it loses one.
1822
+ if(typeof ResizeObserver!=='undefined'){tmpResizeObserver=new ResizeObserver(()=>tmpReposition());tmpResizeObserver.observe(pElement);}};let tmpRemoveRepositionListeners=()=>{window.removeEventListener('scroll',tmpReposition,true);window.removeEventListener('resize',tmpReposition);if(tmpResizeObserver){tmpResizeObserver.disconnect();tmpResizeObserver=null;}};let tmpPin=()=>{if(tmpPinned||tmpDestroyed){return;}tmpPinned=true;if(!tmpTooltipElement){tmpShow();}if(tmpTooltipElement){tmpTooltipElement.classList.add('pict-modal-tooltip-pinned');}tmpAddRepositionListeners();if(typeof pOptions.onPinChange==='function'){pOptions.onPinChange(true,pElement);}};let tmpUnpin=()=>{if(!tmpPinned){return;}tmpPinned=false;tmpRemoveRepositionListeners();if(tmpTooltipElement){tmpTooltipElement.classList.remove('pict-modal-tooltip-pinned');}tmpHide();if(typeof pOptions.onPinChange==='function'){pOptions.onPinChange(false,pElement);}};let tmpOnClick=pEvent=>{if(pEvent){pEvent.preventDefault();pEvent.stopPropagation();}if(tmpPinned){tmpUnpin();}else{tmpPin();}};// Attach listeners
1823
+ pElement.addEventListener('mouseenter',tmpOnMouseEnter);pElement.addEventListener('mouseleave',tmpOnMouseLeave);pElement.addEventListener('focusin',tmpOnFocusIn);pElement.addEventListener('focusout',tmpOnFocusOut);if(pOptions.pinnable){pElement.addEventListener('click',tmpOnClick);}let tmpDestroy=()=>{if(tmpDestroyed){return;}tmpDestroyed=true;if(tmpShowTimeout){clearTimeout(tmpShowTimeout);}if(tmpHideTimeout){clearTimeout(tmpHideTimeout);}tmpRemoveRepositionListeners();tmpPinned=false;tmpHide();pElement.removeEventListener('mouseenter',tmpOnMouseEnter);pElement.removeEventListener('mouseleave',tmpOnMouseLeave);pElement.removeEventListener('focusin',tmpOnFocusIn);pElement.removeEventListener('focusout',tmpOnFocusOut);if(pOptions.pinnable){pElement.removeEventListener('click',tmpOnClick);}};// Optionally render already-pinned (explicit consumer opt-in).
1824
+ if(pOptions.pinnable&&pOptions.startPinned){tmpPin();}return{destroy:tmpDestroy,pin:tmpPin,unpin:tmpUnpin,isPinned:()=>{return tmpPinned;}};}/**
1762
1825
  * Position a tooltip element relative to the target element.
1763
1826
  * Flips direction if the tooltip would overflow the viewport.
1764
1827
  *
@@ -1769,6 +1832,14 @@ pElement.addEventListener('mouseenter',tmpOnMouseEnter);pElement.addEventListene
1769
1832
  if(tmpPosition==='top'&&tmpTargetRect.top<tmpTooltipRect.height+tmpGap){tmpPosition='bottom';}else if(tmpPosition==='bottom'&&window.innerHeight-tmpTargetRect.bottom<tmpTooltipRect.height+tmpGap){tmpPosition='top';}else if(tmpPosition==='left'&&tmpTargetRect.left<tmpTooltipRect.width+tmpGap){tmpPosition='right';}else if(tmpPosition==='right'&&window.innerWidth-tmpTargetRect.right<tmpTooltipRect.width+tmpGap){tmpPosition='left';}// Update class for arrow direction
1770
1833
  pTooltip.className=pTooltip.className.replace(/pict-modal-tooltip--\w+/,'pict-modal-tooltip--'+tmpPosition);let tmpTop=0;let tmpLeft=0;switch(tmpPosition){case'top':tmpTop=tmpTargetRect.top-tmpTooltipRect.height-tmpGap;tmpLeft=tmpTargetRect.left+tmpTargetRect.width/2-tmpTooltipRect.width/2;break;case'bottom':tmpTop=tmpTargetRect.bottom+tmpGap;tmpLeft=tmpTargetRect.left+tmpTargetRect.width/2-tmpTooltipRect.width/2;break;case'left':tmpTop=tmpTargetRect.top+tmpTargetRect.height/2-tmpTooltipRect.height/2;tmpLeft=tmpTargetRect.left-tmpTooltipRect.width-tmpGap;break;case'right':tmpTop=tmpTargetRect.top+tmpTargetRect.height/2-tmpTooltipRect.height/2;tmpLeft=tmpTargetRect.right+tmpGap;break;}// Clamp to viewport
1771
1834
  tmpLeft=Math.max(4,Math.min(tmpLeft,window.innerWidth-tmpTooltipRect.width-4));tmpTop=Math.max(4,Math.min(tmpTop,window.innerHeight-tmpTooltipRect.height-4));pTooltip.style.top=tmpTop+'px';pTooltip.style.left=tmpLeft+'px';}/**
1835
+ * Whether an element is currently rendered (has a layout box). Returns false
1836
+ * for a display:none element or one inside a display:none ancestor (e.g. an
1837
+ * inactive tab panel) — in which case a pinned tooltip should stay hidden
1838
+ * until the anchor reappears.
1839
+ *
1840
+ * @param {HTMLElement} pElement
1841
+ * @returns {boolean}
1842
+ */_isElementRendered(pElement){return!!(pElement&&typeof pElement.getClientRects==='function'&&pElement.getClientRects().length>0);}/**
1772
1843
  * Dismiss all active tooltips.
1773
1844
  */dismissAll(){let tmpTooltips=this._modal._activeTooltips.slice();for(let i=0;i<tmpTooltips.length;i++){tmpTooltips[i].destroy();}}}module.exports=PictModalTooltip;},{}],25:[function(require,module,exports){/**
1774
1845
  * Pict-Modal-Window
@@ -1823,7 +1894,7 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
1823
1894
  *
1824
1895
  * @param {string} pText
1825
1896
  * @returns {string}
1826
- */_escapeHTML(pText){if(typeof pText!=='string'){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}}module.exports=PictModalWindow;},{}],26:[function(require,module,exports){module.exports={"AutoInitialize":true,"AutoRender":false,"AutoSolveWithApp":false,"ViewIdentifier":"Pict-Section-Modal","OverlayClickDismisses":true,"DefaultConfirmOptions":{"title":"Confirm","confirmLabel":"OK","cancelLabel":"Cancel","dangerous":false,"unbounded":false},"DefaultDoubleConfirmOptions":{"title":"Are you sure?","confirmLabel":"Confirm","cancelLabel":"Cancel","phrasePrompt":"Type \"{phrase}\" to confirm:","confirmPhrase":"","unbounded":false},"DefaultModalOptions":{"title":"","content":"","buttons":[],"closeable":true,"width":"480px","unbounded":false},"DefaultTooltipOptions":{"position":"top","delay":200,"maxWidth":"300px","interactive":false},"DefaultToastOptions":{"type":"info","duration":3000,"position":"top-right","dismissible":true},"DefaultPanelOptions":{"position":"right","width":340,"minWidth":200,"maxWidth":600,"collapsible":true,"collapsed":false,"persist":false,"persistKey":""},"Templates":[],"Renderables":[],"CSS":/*css*/`
1897
+ */_escapeHTML(pText){if(typeof pText!=='string'){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}}module.exports=PictModalWindow;},{}],26:[function(require,module,exports){module.exports={"AutoInitialize":true,"AutoRender":false,"AutoSolveWithApp":false,"ViewIdentifier":"Pict-Section-Modal","OverlayClickDismisses":true,"DefaultConfirmOptions":{"title":"Confirm","confirmLabel":"OK","cancelLabel":"Cancel","dangerous":false,"unbounded":false},"DefaultDoubleConfirmOptions":{"title":"Are you sure?","confirmLabel":"Confirm","cancelLabel":"Cancel","phrasePrompt":"Type \"{phrase}\" to confirm:","confirmPhrase":"","unbounded":false},"DefaultModalOptions":{"title":"","content":"","buttons":[],"closeable":true,"width":"480px","unbounded":false},"DefaultTooltipOptions":{"position":"top","delay":200,"maxWidth":"300px","interactive":false,"pinnable":false,"startPinned":false},"DefaultToastOptions":{"type":"info","duration":3000,"position":"top-right","dismissible":true,"allowHTML":false},"DefaultPanelOptions":{"position":"right","width":340,"minWidth":200,"maxWidth":600,"collapsible":true,"collapsed":false,"persist":false,"persistKey":""},"Templates":[],"Renderables":[],"CSS":/*css*/`
1827
1898
  /* pict-section-modal */
1828
1899
  .pict-modal-root
1829
1900
  {
@@ -1874,6 +1945,7 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
1874
1945
  --pict-modal-tooltip-fg: var(--theme-color-text-primary, #ffffff);
1875
1946
  --pict-modal-tooltip-border-radius:4px;
1876
1947
  --pict-modal-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
1948
+ --pict-modal-tooltip-pinned-ring: var(--theme-color-brand-primary, #2E7D74);
1877
1949
 
1878
1950
  /* Dropdown */
1879
1951
  --pict-modal-dropdown-bg: var(--theme-color-background-panel, #ffffff);
@@ -2236,6 +2308,14 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
2236
2308
  opacity: 1;
2237
2309
  }
2238
2310
 
2311
+ /* Pinned tooltips stay open and can be interacted with; a subtle ring
2312
+ distinguishes a pinned tooltip from a transient hover tooltip. */
2313
+ .pict-modal-tooltip.pict-modal-tooltip-pinned
2314
+ {
2315
+ pointer-events: auto;
2316
+ box-shadow: var(--pict-modal-tooltip-shadow), 0 0 0 1px var(--pict-modal-tooltip-pinned-ring);
2317
+ }
2318
+
2239
2319
  .pict-modal-tooltip-arrow
2240
2320
  {
2241
2321
  position: absolute;
@@ -2299,6 +2379,16 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
2299
2379
  transform var(--pict-modal-transition-duration) ease;
2300
2380
  }
2301
2381
 
2382
+ /* Free-form content popovers keep the dropdown chrome (bg / border / shadow /
2383
+ flip / dismiss) but hand sizing + inner padding to the injected content, so a
2384
+ pre-rendered template menu or a wide rich card isn't boxed by the menu
2385
+ defaults. Cap width per-call via the maxWidth option. */
2386
+ .pict-modal-dropdown.pict-modal-dropdown--content
2387
+ {
2388
+ max-width: none;
2389
+ padding: 0;
2390
+ }
2391
+
2302
2392
  .pict-modal-dropdown.pict-modal-dropdown--above { transform: translateY(4px); }
2303
2393
 
2304
2394
  .pict-modal-dropdown.pict-modal-visible
@@ -3229,7 +3319,16 @@ if(typeof document!=='undefined'&&document.body){if(!document.body.classList.con
3229
3319
  * @param {string} pHTMLContent - HTML content
3230
3320
  * @param {object} [pOptions] - Options { position, delay, maxWidth, interactive }
3231
3321
  * @returns {{ destroy: function }}
3232
- */richTooltip(pElement,pHTMLContent,pOptions){return this._tooltip.richTooltip(pElement,pHTMLContent,pOptions);}// -- Toast API --
3322
+ */richTooltip(pElement,pHTMLContent,pOptions){return this._tooltip.richTooltip(pElement,pHTMLContent,pOptions);}/**
3323
+ * Attach a pinnable rich HTML tooltip to an element. Hover/focus behaves
3324
+ * like richTooltip(); a click on the element toggles a pinned state that
3325
+ * keeps the tooltip open and follows the anchor on scroll/resize.
3326
+ *
3327
+ * @param {HTMLElement} pElement - Target element
3328
+ * @param {string} pHTMLContent - HTML content
3329
+ * @param {object} [pOptions] - Options { position, delay, maxWidth, interactive, startPinned, onPinChange }
3330
+ * @returns {{ destroy: function, pin: function, unpin: function, isPinned: function }}
3331
+ */pinnableTooltip(pElement,pHTMLContent,pOptions){return this._tooltip.pinnableTooltip(pElement,pHTMLContent,pOptions);}// -- Toast API --
3233
3332
  /**
3234
3333
  * Show a toast notification.
3235
3334
  *
@@ -3239,13 +3338,16 @@ if(typeof document!=='undefined'&&document.body){if(!document.body.classList.con
3239
3338
  */toast(pMessage,pOptions){return this._toast.toast(pMessage,pOptions);}// -- Dropdown API --
3240
3339
  /**
3241
3340
  * Open an anchor-positioned dropdown menu (no backdrop, click-outside
3242
- * dismisses). Useful for nav menus and split-button addenda.
3341
+ * dismisses). Useful for nav menus and split-button addenda. Pass
3342
+ * `ContentHTML` instead of `items` to render a free-form anchored popover
3343
+ * (rich card, pre-rendered template menu) with the same dismiss/flip behavior.
3243
3344
  *
3244
3345
  * @param {HTMLElement|string|object} pAnchor - Element, CSS selector, or
3245
3346
  * { left, top, width, height } rect for context-menu style anchoring.
3246
- * @param {object} pOptions - { items, align, position, minWidth, maxHeight,
3247
- * className, closeOnSelect, onSelect, onClose }
3248
- * @returns {Promise<{Hash, Item}|null>} Selection or null on dismiss.
3347
+ * @param {object} pOptions - { items | ContentHTML, align, position, minWidth,
3348
+ * maxWidth, maxHeight, className, closeOnSelect, onSelect, onClose }
3349
+ * @returns {Promise<{Hash, Item}|null>} Selection or null on dismiss
3350
+ * (always resolves null in ContentHTML mode).
3249
3351
  */dropdown(pAnchor,pOptions){return this._dropdown.dropdown(pAnchor,pOptions);}/**
3250
3352
  * Dismiss any open dropdown.
3251
3353
  */dismissDropdowns(){this._dropdown.dismissAll();}// -- Panel API --
@@ -5280,7 +5382,7 @@ return cachedClearTimeout.call(null,marker);}catch(e){// same as above but when
5280
5382
  // Some versions of I.E. have different rules for clearTimeout vs setTimeout
5281
5383
  return cachedClearTimeout.call(this,marker);}}}var queue=[];var draining=false;var currentQueue;var queueIndex=-1;function cleanUpNextTick(){if(!draining||!currentQueue){return;}draining=false;if(currentQueue.length){queue=currentQueue.concat(queue);}else{queueIndex=-1;}if(queue.length){drainQueue();}}function drainQueue(){if(draining){return;}var timeout=runTimeout(cleanUpNextTick);draining=true;var len=queue.length;while(len){currentQueue=queue;queue=[];while(++queueIndex<len){if(currentQueue){currentQueue[queueIndex].run();}}queueIndex=-1;len=queue.length;}currentQueue=null;draining=false;runClearTimeout(timeout);}process.nextTick=function(fun){var args=new Array(arguments.length-1);if(arguments.length>1){for(var i=1;i<arguments.length;i++){args[i-1]=arguments[i];}}queue.push(new Item(fun,args));if(queue.length===1&&!draining){runTimeout(drainQueue);}};// v8 likes predictible objects
5282
5384
  function Item(fun,array){this.fun=fun;this.array=array;}Item.prototype.run=function(){this.fun.apply(null,this.array);};process.title='browser';process.browser=true;process.env={};process.argv=[];process.version='';// empty string to avoid regexp issues
5283
- process.versions={};function noop(){}process.on=noop;process.addListener=noop;process.once=noop;process.off=noop;process.removeListener=noop;process.removeAllListeners=noop;process.emit=noop;process.prependListener=noop;process.prependOnceListener=noop;process.listeners=function(name){return[];};process.binding=function(name){throw new Error('process.binding is not supported');};process.cwd=function(){return'/';};process.chdir=function(dir){throw new Error('process.chdir is not supported');};process.umask=function(){return 0;};},{}],91:[function(require,module,exports){module.exports={"name":"retold-data-service","version":"2.1.5","description":"Serve up a whole model!","main":"source/Retold-Data-Service.js","bin":{"retold-data-service-clone":"bin/retold-data-service-clone.js"},"scripts":{"start":"node bin/retold-data-service-clone.js","coverage":"npx quack coverage","test":"npx quack test","brand":"node node_modules/pict-section-theme/bin/pict-section-theme-brand.js --manifest ../../../Retold-Modules-Manifest.json --module retold-data-service --favicons source/services/comprehension-loader/web/favicons && cp -r source/services/comprehension-loader/web/favicons source/services/data-cloner/web/favicons","build":"node build-all.js","build:cloner":"npx quack build","build:loader":"node -e \"require('fs').writeFileSync('.quackage.json', require('fs').readFileSync('.quackage-comprehension-loader.json', 'utf8'))\" && npx quack build","prepublishOnly":"npm run build","build-test-model":"cd test && npx stricture -i model/ddl/BookStore.ddl","docker-dev-build":"docker build ./ -f Dockerfile_LUXURYCode -t retold-data-service-image:local","docker-dev-run":"docker run -it -d --name retold-data-service-dev -p 44444:8080 -p 43306:3306 -p 48086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/retold-data-service\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold-data-service-image:local","docker-dev-shell":"docker exec -it retold-data-service-dev /bin/bash","docker-service-build":"docker build ./ -f Dockerfile_Service -t retold-data-service-server-image:local","docker-service-run-test":"docker run -it --init -d --name retold-data-service -p 8086:8086 -p 43306:3306 -v \"$(pwd):/retold-data-service:z\" -u \"$(id -u):$(id -g)\" retold-data-service-server-image:local","docker-service-run":"docker run -it --init -d --name retold-data-service -p 8086:8086 -p 43306:3306 -v \"$(pwd):/retold-data-service:z\" retold-data-service-server-image:local","docker-service-shell":"docker exec -it retold-data-service /bin/bash","test:integration":"node test/run-integration-tests.js","test:integration:no-browser":"node test/run-integration-tests.js --skip-puppeteer","test:all":"npx quack test && node test/run-integration-tests.js --skip-puppeteer","postversion":"npx quack release postversion","postpublish":"npx quack release postpublish","publish:docker":"npx quack release publish --image","release:patch":"npx quack release patch","release:minor":"npx quack release minor","release:major":"npx quack release major","release:patch:image":"npx quack release patch --image","release:minor:image":"npx quack release minor --image","release:major:image":"npx quack release major --image"},"mocha":{"spec":["test/RetoldDataService_tests.js","test/Bundles_smoke_tests.js","test/ComprehensionLoader_smoke_tests.js","test/DataCloner_smoke_tests.js"],"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"repository":{"type":"git","url":"https://github.com/fable-retold/retold-data-service.git"},"keywords":["entity","behavior","api"],"author":"Steven Velozo <steven@velozo.com> (http://velozo.com/)","license":"MIT","bugs":{"url":"https://github.com/fable-retold/retold-data-service/issues"},"homepage":"https://github.com/fable-retold/retold-data-service","devDependencies":{"chai":"^4.5.0","jsdom":"^25.0.1","meadow-connection-sqlite":"^1.0.20","mocha":"^11.0.1","pict-docuserve":"^1.4.19","puppeteer":"^24.40.0","quackage":"^1.3.0","stricture":"^4.0.6","supertest":"^7.2.2"},"dependencies":{"bibliograph":"^1.0.0","fable":"^3.1.75","fable-serviceproviderbase":"^3.0.19","meadow":"^2.0.43","meadow-connection-manager":"^1.1.5","meadow-connection-mysql":"^1.0.19","meadow-endpoints":"^4.0.22","meadow-integration":"^1.0.42","meadow-migrationmanager":"^1.0.4","orator":"^6.1.2","orator-http-proxy":"^1.0.5","orator-serviceserver-restify":"^2.0.11","orator-static-server":"^2.1.4","pict":"^1.0.372","pict-provider-theme":"^1.1.2","pict-section-connection-form":"^1.0.0","pict-section-histogram":"^1.0.1","pict-section-modal":"^1.1.4","pict-section-theme":"^1.1.1","pict-sessionmanager":"^1.0.2","stricture":"^4.0.6"},"retold":{"brand":{"Hash":"retold-data-service","Name":"Retold Data Service","Tagline":"Schema-driven data movement and comprehension","Palette":"ocean","Icon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-retold-data-service-filled-light\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#23a6c7\"/>\n\t\t<g clip-path=\"url(#frame-retold-data-service-filled-light)\"><rect x=\"20\" y=\"20\" width=\"56\" height=\"56\" rx=\"8\" fill=\"rgba(255,255,255,0.18)\"/>\n\t\t\t\t\t<path d=\"M 48 30 L 70 48 L 48 66 L 26 48 Z\" fill=\"#e36b59\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"28\" font-weight=\"600\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">RDS</text>\n\t</svg>","IconType":"svg","Favicon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-data-service-light\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#23a6c7\"/>\n\t\t<g clip-path=\"url(#fav-retold-data-service-light)\"><rect x=\"16\" y=\"16\" width=\"64\" height=\"64\" rx=\"10\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">R</text>\n\t</svg>","FaviconDark":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-data-service-dark\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#67c6de\"/>\n\t\t<g clip-path=\"url(#fav-retold-data-service-dark)\"><rect x=\"16\" y=\"16\" width=\"64\" height=\"64\" rx=\"10\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">R</text>\n\t</svg>","Colors":{"Primary":"#23a6c7","Secondary":"#e36b59","PrimaryLight":"#23a6c7","PrimaryDark":"#67c6de","SecondaryLight":"#e36b59","SecondaryDark":"#edb3aa"}}}};},{}],92:[function(require,module,exports){'use strict';// Located at source/services/. Apps live one level deeper at
5385
+ process.versions={};function noop(){}process.on=noop;process.addListener=noop;process.once=noop;process.off=noop;process.removeListener=noop;process.removeAllListeners=noop;process.emit=noop;process.prependListener=noop;process.prependOnceListener=noop;process.listeners=function(name){return[];};process.binding=function(name){throw new Error('process.binding is not supported');};process.cwd=function(){return'/';};process.chdir=function(dir){throw new Error('process.chdir is not supported');};process.umask=function(){return 0;};},{}],91:[function(require,module,exports){module.exports={"name":"retold-data-service","version":"2.1.6","description":"Serve up a whole model!","main":"source/Retold-Data-Service.js","bin":{"retold-data-service-clone":"bin/retold-data-service-clone.js"},"scripts":{"start":"node bin/retold-data-service-clone.js","coverage":"npx quack coverage","test":"npx quack test","brand":"node node_modules/pict-section-theme/bin/pict-section-theme-brand.js --manifest ../../../Retold-Modules-Manifest.json --module retold-data-service --favicons source/services/comprehension-loader/web/favicons && cp -r source/services/comprehension-loader/web/favicons source/services/data-cloner/web/favicons","build":"node build-all.js","build:cloner":"npx quack build","build:loader":"node -e \"require('fs').writeFileSync('.quackage.json', require('fs').readFileSync('.quackage-comprehension-loader.json', 'utf8'))\" && npx quack build","prepublishOnly":"npm run build","build-test-model":"cd test && npx stricture -i model/ddl/BookStore.ddl","docker-dev-build":"docker build ./ -f Dockerfile_LUXURYCode -t retold-data-service-image:local","docker-dev-run":"docker run -it -d --name retold-data-service-dev -p 44444:8080 -p 43306:3306 -p 48086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/retold-data-service\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold-data-service-image:local","docker-dev-shell":"docker exec -it retold-data-service-dev /bin/bash","docker-service-build":"docker build ./ -f Dockerfile_Service -t retold-data-service-server-image:local","docker-service-run-test":"docker run -it --init -d --name retold-data-service -p 8086:8086 -p 43306:3306 -v \"$(pwd):/retold-data-service:z\" -u \"$(id -u):$(id -g)\" retold-data-service-server-image:local","docker-service-run":"docker run -it --init -d --name retold-data-service -p 8086:8086 -p 43306:3306 -v \"$(pwd):/retold-data-service:z\" retold-data-service-server-image:local","docker-service-shell":"docker exec -it retold-data-service /bin/bash","test:integration":"node test/run-integration-tests.js","test:integration:no-browser":"node test/run-integration-tests.js --skip-puppeteer","test:all":"npx quack test && node test/run-integration-tests.js --skip-puppeteer","postversion":"npx quack release postversion","postpublish":"npx quack release postpublish","publish:docker":"npx quack release publish --image","release:patch":"npx quack release patch","release:minor":"npx quack release minor","release:major":"npx quack release major","release:patch:image":"npx quack release patch --image","release:minor:image":"npx quack release minor --image","release:major:image":"npx quack release major --image"},"mocha":{"spec":["test/RetoldDataService_tests.js","test/Bundles_smoke_tests.js","test/ComprehensionLoader_smoke_tests.js","test/DataCloner_smoke_tests.js"],"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"repository":{"type":"git","url":"https://github.com/fable-retold/retold-data-service.git"},"keywords":["entity","behavior","api"],"author":"Steven Velozo <steven@velozo.com> (http://velozo.com/)","license":"MIT","bugs":{"url":"https://github.com/fable-retold/retold-data-service/issues"},"homepage":"https://github.com/fable-retold/retold-data-service","devDependencies":{"chai":"^4.5.0","jsdom":"^25.0.1","meadow-connection-sqlite":"^1.0.21","mocha":"^11.7.6","pict-docuserve":"^1.4.19","puppeteer":"^24.40.0","quackage":"^1.3.0","stricture":"^4.0.6","supertest":"^7.2.2"},"dependencies":{"bibliograph":"^1.0.0","fable":"^3.1.80","fable-serviceproviderbase":"^3.0.19","meadow":"^2.0.47","meadow-connection-manager":"^1.1.5","meadow-connection-mysql":"^1.0.20","meadow-endpoints":"^4.0.22","meadow-integration":"^1.1.3","meadow-migrationmanager":"^1.0.5","orator":"^6.1.2","orator-http-proxy":"^1.0.5","orator-serviceserver-restify":"^2.0.11","orator-static-server":"^2.1.4","pict":"^1.0.393","pict-provider-theme":"^1.1.2","pict-section-connection-form":"^1.0.0","pict-section-histogram":"^1.0.1","pict-section-modal":"^1.3.2","pict-section-theme":"^1.1.1","pict-sessionmanager":"^1.0.2","stricture":"^4.0.6"},"retold":{"brand":{"Hash":"retold-data-service","Name":"Retold Data Service","Tagline":"Schema-driven data movement and comprehension","Palette":"ocean","Icon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-retold-data-service-filled-light\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#23a6c7\"/>\n\t\t<g clip-path=\"url(#frame-retold-data-service-filled-light)\"><rect x=\"20\" y=\"20\" width=\"56\" height=\"56\" rx=\"8\" fill=\"rgba(255,255,255,0.18)\"/>\n\t\t\t\t\t<path d=\"M 48 30 L 70 48 L 48 66 L 26 48 Z\" fill=\"#e36b59\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"28\" font-weight=\"600\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">RDS</text>\n\t</svg>","IconType":"svg","Favicon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-data-service-light\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#23a6c7\"/>\n\t\t<g clip-path=\"url(#fav-retold-data-service-light)\"><rect x=\"16\" y=\"16\" width=\"64\" height=\"64\" rx=\"10\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">R</text>\n\t</svg>","FaviconDark":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-data-service-dark\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#67c6de\"/>\n\t\t<g clip-path=\"url(#fav-retold-data-service-dark)\"><rect x=\"16\" y=\"16\" width=\"64\" height=\"64\" rx=\"10\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">R</text>\n\t</svg>","Colors":{"Primary":"#23a6c7","Secondary":"#e36b59","PrimaryLight":"#23a6c7","PrimaryDark":"#67c6de","SecondaryLight":"#e36b59","SecondaryDark":"#edb3aa"}}}};},{}],92:[function(require,module,exports){'use strict';// Located at source/services/. Apps live one level deeper at
5284
5386
  // source/services/<app>/pict-app/. The package.json is two levels up.
5285
5387
  const tmpPackage=require('../../package.json');if(!tmpPackage.retold||!tmpPackage.retold.brand){throw new Error('retold-data-service: package.json is missing retold.brand — '+'run `npm run brand` (which calls pict-section-theme-brand) before building');}module.exports=tmpPackage.retold.brand;},{"../../package.json":91}],93:[function(require,module,exports){module.exports={"Name":"Retold Comprehension Loader","Hash":"ComprehensionLoader","MainViewportViewIdentifier":"ComprehensionLoader-Layout","MainViewportDestinationAddress":"#ComprehensionLoader-Application-Container","MainViewportDefaultDataAddress":"AppData.ComprehensionLoader","pict_configuration":{"Product":"ComprehensionLoader"},"AutoRenderMainViewportViewAfterInitialize":false};},{}],94:[function(require,module,exports){const libPictApplication=require('pict-application');const libProvider=require('./providers/Pict-Provider-ComprehensionLoader.js');const libViewLayout=require('./views/PictView-ComprehensionLoader-Layout.js');const libViewSession=require('./views/PictView-ComprehensionLoader-Session.js');const libViewSchema=require('./views/PictView-ComprehensionLoader-Schema.js');const libViewSource=require('./views/PictView-ComprehensionLoader-Source.js');const libViewLoad=require('./views/PictView-ComprehensionLoader-Load.js');const libViewHistogram=require('pict-section-histogram');const libPictSectionModal=require('pict-section-modal');const libPictSectionTheme=require('pict-section-theme');const libBrand=require('../../RetoldDataService-Brand.js');const libViewShell=require('./views/PictView-ComprehensionLoader-Shell.js');const libViewTopBarNav=require('./views/PictView-ComprehensionLoader-TopBar-Nav.js');const libViewTopBarUser=require('./views/PictView-ComprehensionLoader-TopBar-User.js');const libViewStatusBar=require('./views/PictView-ComprehensionLoader-StatusBar.js');const libViewStatusDetail=require('./views/PictView-ComprehensionLoader-StatusDetail.js');const libViewSettings=require('./views/PictView-ComprehensionLoader-SettingsPanel.js');class ComprehensionLoaderApplication extends libPictApplication{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);// 1. Modal section (provides shell + panels + modal API).
5286
5388
  this.pict.addView('Pict-Section-Modal',libPictSectionModal.default_configuration,libPictSectionModal);// 2. Provider + existing section views.