flexdesk 0.16.1 → 0.17.0

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.
Files changed (252) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/LICENSE +0 -0
  3. package/README.md +2217 -42
  4. package/THIRD_PARTY_LICENSES.md +0 -0
  5. package/css/base.css +1834 -75
  6. package/css/flexdesk.css +3146 -164
  7. package/css/overrides.css +16 -0
  8. package/css/reset.css +0 -0
  9. package/css/tokens.css +0 -0
  10. package/dist/canvas.js +6 -239
  11. package/dist/canvas.js.map +3 -3
  12. package/dist/charts.js +709 -18
  13. package/dist/charts.js.map +4 -4
  14. package/dist/chunk-3PHCPZHT.js +0 -0
  15. package/dist/chunk-3PHCPZHT.js.map +0 -0
  16. package/dist/chunk-4A7SJC3T.js +503 -0
  17. package/dist/chunk-4A7SJC3T.js.map +7 -0
  18. package/dist/{chunk-6JSOVNID.js → chunk-CVMCZZX2.js} +635 -10
  19. package/dist/chunk-CVMCZZX2.js.map +7 -0
  20. package/dist/chunk-D3COLZZ2.js +1311 -0
  21. package/dist/chunk-D3COLZZ2.js.map +7 -0
  22. package/dist/chunk-FOOS3T5L.js +0 -0
  23. package/dist/chunk-FOOS3T5L.js.map +0 -0
  24. package/dist/{chunk-SN4LSOAR.js → chunk-GOQLR5WR.js} +452 -2
  25. package/dist/chunk-GOQLR5WR.js.map +7 -0
  26. package/dist/{chunk-FL5KFNQH.js → chunk-HNU6MM2B.js} +52 -17
  27. package/dist/chunk-HNU6MM2B.js.map +7 -0
  28. package/dist/chunk-HYJYYEPK.js +375 -0
  29. package/dist/chunk-HYJYYEPK.js.map +7 -0
  30. package/dist/chunk-JKZLNKG6.js +2041 -0
  31. package/dist/chunk-JKZLNKG6.js.map +7 -0
  32. package/dist/chunk-JYWURG5T.js +0 -0
  33. package/dist/chunk-JYWURG5T.js.map +0 -0
  34. package/dist/{chunk-RQM5Z2MU.js → chunk-MCIXFNVF.js} +633 -311
  35. package/dist/chunk-MCIXFNVF.js.map +7 -0
  36. package/dist/chunk-N7HC3ADV.js +30 -0
  37. package/dist/chunk-N7HC3ADV.js.map +7 -0
  38. package/dist/{chunk-FBGP5KN5.js → chunk-Q36EPT2R.js} +3268 -203
  39. package/dist/chunk-Q36EPT2R.js.map +7 -0
  40. package/dist/chunk-QWQJUDPD.js +610 -0
  41. package/dist/chunk-QWQJUDPD.js.map +7 -0
  42. package/dist/{chunk-NLTOY57M.js → chunk-UURZ37SD.js} +28 -48
  43. package/dist/chunk-UURZ37SD.js.map +7 -0
  44. package/dist/{chunk-B5Q53LAJ.js → chunk-UWO43BZU.js} +2 -2
  45. package/dist/chunk-UWO43BZU.js.map +7 -0
  46. package/dist/chunk-WVFGV5FT.js +0 -0
  47. package/dist/chunk-WVFGV5FT.js.map +0 -0
  48. package/dist/core.js +170 -118
  49. package/dist/core.js.map +2 -2
  50. package/dist/editor.js +156 -70
  51. package/dist/editor.js.map +2 -2
  52. package/dist/flexdesk.css +3146 -164
  53. package/dist/flow.js +2789 -306
  54. package/dist/flow.js.map +4 -4
  55. package/dist/host.js +109 -3
  56. package/dist/host.js.map +3 -3
  57. package/dist/reset.css +0 -0
  58. package/dist/tile_registry-6WZPTUZV.js +0 -0
  59. package/dist/tile_registry-6WZPTUZV.js.map +0 -0
  60. package/dist/tiles.js +657 -234
  61. package/dist/tiles.js.map +4 -4
  62. package/dist/tokens.css +0 -0
  63. package/dist/widgets.js +3252 -2124
  64. package/dist/widgets.js.map +4 -4
  65. package/dist/wm.js +1227 -347
  66. package/dist/wm.js.map +4 -4
  67. package/package.json +3 -1
  68. package/src/canvas/canvas_adapter.js +5 -0
  69. package/src/canvas/edge_router.js +0 -0
  70. package/src/canvas/graph/connector_router.js +0 -0
  71. package/src/canvas/graph/history_service.js +0 -0
  72. package/src/canvas/graph/node_platform.js +0 -0
  73. package/src/canvas/index.js +1 -0
  74. package/src/canvas/layered_layout.js +244 -0
  75. package/src/charts/chart_types.js +0 -0
  76. package/src/charts/data_series_plot_window.js +0 -0
  77. package/src/charts/downsample.js +2 -2
  78. package/src/charts/plot_config.js +53 -29
  79. package/src/charts/plot_config_editor.js +627 -0
  80. package/src/charts/plot_grid.js +449 -0
  81. package/src/charts/plot_popout_window.js +103 -317
  82. package/src/charts/plotly_wrapper.js +22 -2
  83. package/src/charts/series_transforms.js +206 -0
  84. package/src/core/event_bus.js +0 -0
  85. package/src/core/logging.js +1 -1
  86. package/src/core/settings.js +105 -19
  87. package/src/core/state_guard.js +93 -51
  88. package/src/core/state_guard_config.js +85 -74
  89. package/src/core/state_machine.js +0 -0
  90. package/src/editor/editor_pane.js +3 -3
  91. package/src/editor/monaco_editor_factory.js +124 -60
  92. package/src/editor/monaco_loader.js +103 -28
  93. package/src/editor/notebook_search.js +0 -0
  94. package/src/editor/notebook_tab_bar.js +38 -52
  95. package/src/editor/notebook_undo_manager.js +0 -0
  96. package/src/editor/split_pane_container.js +6 -3
  97. package/src/flow/canvas_editor/connections.js +90 -0
  98. package/src/flow/canvas_editor/editor.js +2351 -153
  99. package/src/flow/canvas_editor/index.js +2 -1
  100. package/src/flow/canvas_editor/layout.js +119 -12
  101. package/src/flow/canvas_editor/strings.js +80 -0
  102. package/src/flow/kit/always_before.js +0 -0
  103. package/src/flow/kit/catalogue.js +97 -3
  104. package/src/flow/kit/chip_input.js +0 -0
  105. package/src/flow/kit/dom.js +0 -0
  106. package/src/flow/kit/findings.js +0 -0
  107. package/src/flow/kit/history.js +0 -0
  108. package/src/flow/kit/index.js +3 -3
  109. package/src/flow/kit/keys.js +7 -1
  110. package/src/flow/kit/logic_graph.js +97 -15
  111. package/src/flow/kit/references.js +0 -0
  112. package/src/flow/kit/settings_panel.js +0 -0
  113. package/src/flow/kit/settings_schema.js +2 -1
  114. package/src/flow/kit/step_picker.js +0 -0
  115. package/src/flow/kit/strings.js +3 -1
  116. package/src/flow/kit/value_picker.js +0 -0
  117. package/src/flow/kit/widgets.js +86 -109
  118. package/src/flow/lanes/editor.js +136 -14
  119. package/src/flow/lanes/index.js +3 -1
  120. package/src/flow/lanes/layout.js +0 -0
  121. package/src/flow/lanes/pipeline.js +44 -2
  122. package/src/flow/lanes/preview.js +0 -0
  123. package/src/flow/lanes/strings.js +1 -0
  124. package/src/flow/outline/editor.js +0 -0
  125. package/src/flow/outline/index.js +0 -0
  126. package/src/flow/outline/mapping.js +0 -0
  127. package/src/flow/outline/menu.js +0 -0
  128. package/src/flow/outline/operations.js +0 -0
  129. package/src/flow/outline/recognise.js +0 -0
  130. package/src/flow/outline/strings.js +0 -0
  131. package/src/help/help_modal.js +168 -42
  132. package/src/help/help_registry.js +12 -1
  133. package/src/host/external_links.js +0 -0
  134. package/src/host/file_picker.js +117 -0
  135. package/src/host/host.js +10 -2
  136. package/src/host/photino_host.js +9 -0
  137. package/src/host/photino_host.md +21 -3
  138. package/src/host/pywebview_host.js +10 -0
  139. package/src/tiles/chart_tiles.js +53 -245
  140. package/src/tiles/config_schema.js +8 -0
  141. package/src/tiles/figure_tile.js +322 -0
  142. package/src/tiles/layout_persistence.js +3 -3
  143. package/src/tiles/list_tiles.js +7 -7
  144. package/src/tiles/scope_picker.js +0 -0
  145. package/src/tiles/tile_base.js +1 -1
  146. package/src/tiles/tile_config_form.js +442 -0
  147. package/src/tiles/tile_grid.js +2 -0
  148. package/src/tiles/tile_registry.js +0 -0
  149. package/src/tiling/bottom_panel_tabs.js +67 -99
  150. package/src/tiling/command_palette.js +64 -19
  151. package/src/tiling/content_registry.js +4 -1
  152. package/src/tiling/desktops.js +11 -1
  153. package/src/tiling/entity_sources.js +0 -0
  154. package/src/tiling/keymap.js +403 -128
  155. package/src/tiling/kind_taxonomy.js +78 -0
  156. package/src/tiling/landing_table.js +0 -0
  157. package/src/tiling/loading_overlay.js +0 -0
  158. package/src/tiling/nav_panel.js +59 -10
  159. package/src/tiling/page_factory.js +5 -5
  160. package/src/tiling/panel_availability.js +49 -0
  161. package/src/tiling/panel_keys.js +0 -0
  162. package/src/tiling/shell.js +114 -12
  163. package/src/tiling/tab_strip.js +0 -0
  164. package/src/tiling/tile_breadcrumb.js +0 -0
  165. package/src/tiling/tile_renderer.js +105 -9
  166. package/src/tiling/tile_tab_menu.js +0 -0
  167. package/src/tiling/tile_tree.js +0 -0
  168. package/src/tiling/wm.js +562 -30
  169. package/src/tiling/zoom.js +0 -0
  170. package/src/ui/base/component_base.js +0 -0
  171. package/src/ui/base/controller_base.js +0 -0
  172. package/src/ui/base/page_base.js +0 -0
  173. package/src/ui/components/about_dialog.js +0 -0
  174. package/src/ui/components/action_dropdown.js +30 -2
  175. package/src/ui/components/alert_log.js +0 -0
  176. package/src/ui/components/alerts_pane.js +0 -0
  177. package/src/ui/components/attribute_list_editor.js +0 -0
  178. package/src/ui/components/autocomplete_field.js +0 -0
  179. package/src/ui/components/cell_editor_host.js +211 -0
  180. package/src/ui/components/cell_grid.js +648 -0
  181. package/src/ui/components/cell_selection.js +220 -0
  182. package/src/ui/components/choice_controls.js +351 -0
  183. package/src/ui/components/color_field.js +211 -0
  184. package/src/ui/components/color_list_field.js +210 -0
  185. package/src/ui/components/column_fit.js +0 -0
  186. package/src/ui/components/column_groups.js +314 -0
  187. package/src/ui/components/column_order.js +142 -0
  188. package/src/ui/components/computing_status_window.js +98 -25
  189. package/src/ui/components/confirm_dialog.js +81 -38
  190. package/src/ui/components/context_menu.js +2 -2
  191. package/src/ui/components/conversation_view.js +440 -0
  192. package/src/ui/components/crosstab.js +289 -0
  193. package/src/ui/components/data_table.js +601 -62
  194. package/src/ui/components/detail_header.js +22 -11
  195. package/src/ui/components/document_outline.js +397 -0
  196. package/src/ui/components/drag_reorder.js +0 -0
  197. package/src/ui/components/fact_table.js +0 -0
  198. package/src/ui/components/fill_handle.js +322 -0
  199. package/src/ui/components/gallery_picker.js +19 -8
  200. package/src/ui/components/header_actions.js +55 -0
  201. package/src/ui/components/inline_renamer.js +0 -0
  202. package/src/ui/components/job_progress.js +51 -0
  203. package/src/ui/components/managed_window.js +27 -4
  204. package/src/ui/components/menu_bar.js +745 -0
  205. package/src/ui/components/modal.js +449 -75
  206. package/src/ui/components/notification_history.js +3 -3
  207. package/src/ui/components/progress.js +483 -0
  208. package/src/ui/components/record_list.js +0 -0
  209. package/src/ui/components/row_activation.js +0 -0
  210. package/src/ui/components/section_stack.js +298 -0
  211. package/src/ui/components/series.js +173 -0
  212. package/src/ui/components/settings_view.js +634 -0
  213. package/src/ui/components/slide_out_panel.js +43 -6
  214. package/src/ui/components/slider_field.js +275 -18
  215. package/src/ui/components/sortable_list.js +0 -0
  216. package/src/ui/components/staged_edits.js +343 -0
  217. package/src/ui/components/staged_history.js +172 -0
  218. package/src/ui/components/table_filter_chips.js +0 -0
  219. package/src/ui/components/table_state_store.js +0 -0
  220. package/src/ui/components/table_structure.js +182 -0
  221. package/src/ui/components/table_values.js +0 -0
  222. package/src/ui/components/tabs.js +497 -0
  223. package/src/ui/components/tag_input.js +215 -0
  224. package/src/ui/components/toast.js +25 -8
  225. package/src/ui/components/toggle_field.js +175 -0
  226. package/src/ui/components/tree_view.js +55 -34
  227. package/src/ui/components/window_taskbar.js +0 -0
  228. package/src/ui/components/wizard.js +563 -0
  229. package/src/ui/controllers/window_chrome_controller.js +2 -2
  230. package/src/ui/notification_center.js +375 -119
  231. package/src/ui/utils/auto_scrollbars.js +0 -0
  232. package/src/ui/utils/markdown.js +709 -0
  233. package/src/ui/utils/native_context_menu.js +0 -0
  234. package/src/ui/utils/overlay_scrollbar.js +16 -12
  235. package/src/ui/utils/raf_resize_observer.js +0 -0
  236. package/src/ui/utils/scroll_lock.js +0 -0
  237. package/src/ui/utils/strip_scroll.js +55 -0
  238. package/src/ui/utils/tooltip_service.js +0 -8
  239. package/dist/chunk-6JSOVNID.js.map +0 -7
  240. package/dist/chunk-B5Q53LAJ.js.map +0 -7
  241. package/dist/chunk-FBGP5KN5.js.map +0 -7
  242. package/dist/chunk-FL5KFNQH.js.map +0 -7
  243. package/dist/chunk-NLTOY57M.js.map +0 -7
  244. package/dist/chunk-NNFTETK3.js +0 -633
  245. package/dist/chunk-NNFTETK3.js.map +0 -7
  246. package/dist/chunk-O5OHMWBB.js +0 -284
  247. package/dist/chunk-O5OHMWBB.js.map +0 -7
  248. package/dist/chunk-RQM5Z2MU.js.map +0 -7
  249. package/dist/chunk-SN4LSOAR.js.map +0 -7
  250. package/dist/chunk-W6FBJLPW.js +0 -367
  251. package/dist/chunk-W6FBJLPW.js.map +0 -7
  252. package/src/ui/controllers/panel_state_machine.js +0 -634
package/dist/core.js CHANGED
@@ -2,6 +2,8 @@ import {
2
2
  StateMachine
3
3
  } from "./chunk-3PHCPZHT.js";
4
4
  import {
5
+ DEFAULT_SETTINGS_STORAGE_KEY,
6
+ configureSettings,
5
7
  createSettingsStore,
6
8
  getAllSettings,
7
9
  getCategories,
@@ -9,13 +11,15 @@ import {
9
11
  getSchema,
10
12
  getSetting,
11
13
  getSettingsByCategory,
14
+ getSettingsStorageKey,
15
+ getSettingsStore,
12
16
  registerSettings,
13
17
  registerSettingsEventBus,
14
18
  resetAllSettings,
15
19
  resetCategory,
16
20
  resetSetting,
17
21
  setSetting
18
- } from "./chunk-FL5KFNQH.js";
22
+ } from "./chunk-HNU6MM2B.js";
19
23
  import "./chunk-JYWURG5T.js";
20
24
 
21
25
  // src/core/event_bus.js
@@ -213,7 +217,7 @@ var DEFAULT_NAMESPACE = "app";
213
217
  var QUIET_MODE_LEVEL = "warn";
214
218
  var LoggingService = class {
215
219
  constructor({
216
- name = "ecosim",
220
+ name = "flexdesk",
217
221
  eventBus = null,
218
222
  minLevel = "info",
219
223
  historyLimit = 500,
@@ -464,7 +468,6 @@ var DEFAULT_ALLOWED_ATTRIBUTES = Object.freeze([
464
468
  "aria-busy",
465
469
  "role",
466
470
  "title",
467
- "twm-has-tooltip",
468
471
  "data-tooltip",
469
472
  "data-help-topic"
470
473
  ]);
@@ -476,7 +479,6 @@ var DEFAULT_ALLOWED_DATASET_KEYS = Object.freeze([
476
479
  "deleting",
477
480
  // Notification center
478
481
  "notification-id",
479
- "notificationId",
480
482
  // Plotly.js internal attributes (third-party charting library)
481
483
  "unformatted",
482
484
  "toggle",
@@ -491,56 +493,37 @@ var DEFAULT_ALLOWED_DATASET_KEYS = Object.freeze([
491
493
  "group",
492
494
  "trace",
493
495
  "point",
494
- "curveNumber",
495
- "pointNumber",
496
+ "curve-number",
497
+ "point-number",
496
498
  // UI state keys used by original HTML structure
497
499
  "active-content",
498
- "activeContent",
499
500
  "panel-content",
500
- "panelContent",
501
501
  "collapsible-id",
502
- "collapsibleId",
503
502
  "collapsible-default",
504
- "collapsibleDefault",
505
- "twm-collapsible-header",
506
- "collapsibleHeader",
507
- "twm-collapsible-content",
508
- "collapsibleContent",
503
+ "collapsible-header",
504
+ "collapsible-content",
509
505
  "collapsible-group",
510
- "collapsibleGroup",
511
506
  "collapsible-exclusive",
512
- "collapsibleExclusive",
513
507
  "collapsible-float",
514
- "collapsibleFloat",
515
508
  "collapsible-fill",
516
- "collapsibleFill",
517
509
  "tool",
518
510
  "tab",
519
511
  "role",
520
512
  "op",
521
513
  "func-name",
522
- "funcName",
523
514
  "func-expr",
524
- "funcExpr",
525
515
  "arity",
526
516
  "tooltip",
527
- "twm-latex-tooltip",
528
- "latexTooltip",
517
+ "latex-tooltip",
529
518
  "node-type",
530
- "nodeType",
531
- "twm-node-name",
532
- "nodeName",
519
+ "node-name",
533
520
  "lang",
534
521
  "playback-control",
535
- "playbackControl",
536
522
  // Simulation/scenario state keys
537
523
  "status",
538
524
  "scenario-id",
539
- "scenarioId",
540
525
  "run-id",
541
- "runId",
542
526
  "run-state",
543
- "runState",
544
527
  "selected",
545
528
  "active",
546
529
  "disabled",
@@ -550,53 +533,33 @@ var DEFAULT_ALLOWED_DATASET_KEYS = Object.freeze([
550
533
  "hidden",
551
534
  // Node/canvas state keys
552
535
  "node-id",
553
- "nodeId",
554
536
  "connector-id",
555
- "connectorId",
556
537
  "connector-type",
557
- "connectorType",
558
538
  "connection-id",
559
- "connectionId",
560
539
  "input-index",
561
- "inputIndex",
562
540
  "output-index",
563
- "outputIndex",
564
541
  "port-index",
565
- "portIndex",
566
542
  // Scenario editor keys
567
543
  "source",
568
544
  "series-id",
569
- "seriesId",
570
545
  "dataset-id",
571
- "datasetId",
572
546
  "mirror-input-bound",
573
- "mirrorInputBound",
574
547
  "mirror-change-bound",
575
- "mirrorChangeBound",
576
548
  "mirror-input",
577
- "mirrorInput",
578
549
  "bound",
579
550
  "field",
580
551
  "key",
581
552
  "namespace",
582
553
  "namespace-id",
583
- "namespaceId",
584
554
  "tab-id",
585
- "tabId",
586
555
  "param-id",
587
- "paramId",
588
556
  "target-id",
589
- "targetId",
590
557
  "override-type",
591
- "overrideType",
592
558
  // Tree view component keys
593
559
  "item-id",
594
- "itemId",
595
560
  "category-id",
596
- "categoryId",
597
561
  // Calibration page keys
598
562
  "info-for",
599
- "infoFor",
600
563
  "column",
601
564
  // Data page keys
602
565
  "readonly",
@@ -619,48 +582,101 @@ var DEFAULT_ALLOWED_DATASET_KEYS = Object.freeze([
619
582
  "description",
620
583
  // DSL generator keys
621
584
  "dsl-state",
622
- "dslState",
623
585
  "dsl-section-registered",
624
- "dslSectionRegistered",
625
586
  "dsl-scrollbars-installed",
626
- "dslScrollbarsInstalled",
627
587
  "dsl-tabs-bound",
628
- "dslTabsBound",
629
588
  "dsl-controls-bound",
630
- "dslControlsBound",
631
589
  // Inline highlighter keys
632
590
  "inline-hl",
633
- "inlineHl",
634
- "tooltip",
635
591
  // Overlay scrollbar keys (UI-only, not state storage)
636
592
  "scrollable",
637
593
  "scrollable-x",
638
- "scrollableX",
639
594
  "scrollable-y",
640
- "scrollableY",
641
595
  // ManagedWindow component keys
642
596
  "window-id",
643
- "windowId",
644
597
  // Help system keys
645
598
  "help-topic",
646
- "helpTopic"
647
- ]);
648
- var DEFAULT_OVERRIDES = Object.freeze([
649
- {
650
- // Panel controller writes dataset hooks for field identification/focus.
651
- pattern: /js_new\/ui\/controllers\/panel_controller\.js/,
652
- datasetKeys: ["field", "descriptor-key", "descriptorKey"],
653
- attributes: ["data-field", "data-descriptor-key"],
654
- attributePrefixes: []
655
- }
599
+ // FlexDesk widgets: every literal data key written under src/ is listed
600
+ // here (tests/state_guard_defaults.test.mjs scans for them), so the
601
+ // shell, dialogs, forms, tooltips and editors pass a strict guard.
602
+ "accent",
603
+ "act",
604
+ "action-idx",
605
+ "action-value",
606
+ "add",
607
+ "category",
608
+ "code",
609
+ "data",
610
+ "direction",
611
+ "dismiss",
612
+ "entry",
613
+ "error",
614
+ "extra",
615
+ "flow",
616
+ "from",
617
+ "gap",
618
+ "group-id",
619
+ "item",
620
+ "kind",
621
+ "lane",
622
+ "leaf-id",
623
+ "level",
624
+ "list-action",
625
+ "match",
626
+ "mode",
627
+ "node",
628
+ "note-id",
629
+ "notification-summary",
630
+ "open",
631
+ "pager",
632
+ "pane",
633
+ "pane-id",
634
+ "parameter",
635
+ "placeholder",
636
+ "placement",
637
+ "port",
638
+ "record-key",
639
+ "ref",
640
+ "refusal",
641
+ "refusal-for",
642
+ "renameable",
643
+ "row-key",
644
+ "rule",
645
+ "scope",
646
+ "shape",
647
+ "slot",
648
+ "slot-idx",
649
+ "split-id",
650
+ "state",
651
+ "step",
652
+ "syntax",
653
+ "tile-id",
654
+ "tile-type",
655
+ "tip",
656
+ "to",
657
+ "tone",
658
+ "tooltip-max-width",
659
+ "tooltip-placement",
660
+ "twm-flow-item",
661
+ "twm-flow-title",
662
+ "twm-icon",
663
+ "twm-required",
664
+ "twm-tabs",
665
+ "twm-tail",
666
+ "verb"
656
667
  ]);
657
- var DEFAULT_MODE = typeof window !== "undefined" && Boolean(window.__ECOSIM_DEBUG__) ? "strict" : "warn";
658
668
  var DEFAULT_STATE_GUARD_CONFIG = Object.freeze({
659
- mode: DEFAULT_MODE,
669
+ mode: "warn",
660
670
  allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES,
661
671
  allowedAttributePrefixes: DEFAULT_ALLOWED_ATTRIBUTE_PREFIXES,
662
672
  allowedDatasetKeys: DEFAULT_ALLOWED_DATASET_KEYS,
663
- moduleOverrides: DEFAULT_OVERRIDES
673
+ // FlexDesk ships no module overrides: which of YOUR modules may write which
674
+ // keys is yours to say, through `moduleOverrides` or `allow()`.
675
+ moduleOverrides: Object.freeze([]),
676
+ // null: a write is attributed to the frame that made it. A RegExp (or a
677
+ // literal string) picks the first frame from there up whose location
678
+ // matches instead; its first capture group, if any, names the module.
679
+ moduleFramePattern: null
664
680
  });
665
681
  function normalizeStateGuardConfig(config = {}) {
666
682
  if (!config || typeof config !== "object") {
@@ -679,7 +695,8 @@ function normalizeStateGuardConfig(config = {}) {
679
695
  ),
680
696
  moduleOverrides: normalizeOverrides(
681
697
  config.moduleOverrides ?? DEFAULT_STATE_GUARD_CONFIG.moduleOverrides
682
- )
698
+ ),
699
+ moduleFramePattern: config.moduleFramePattern == null || config.moduleFramePattern === "" ? DEFAULT_STATE_GUARD_CONFIG.moduleFramePattern : patternToRegExp(config.moduleFramePattern)
683
700
  };
684
701
  }
685
702
  function normalizeMode(mode) {
@@ -744,8 +761,10 @@ var HOOK_REGISTRY = {
744
761
  datasetDescriptor: null,
745
762
  datasetProxyCache: /* @__PURE__ */ new WeakMap()
746
763
  };
747
- var STACK_CACHE = /* @__PURE__ */ new Map();
764
+ var STACK_CACHE_LIMIT = 500;
765
+ var FRAME_LOCATION = /(?:\(|@|\bat\s+)([^()\s@][^()\s]*?):\d+(?::\d+)?\)?\s*$/;
748
766
  var DATA_ATTRIBUTE_PREFIX = "data-";
767
+ var VIA_DOM_HOOK = /* @__PURE__ */ Symbol("state-guard:via-dom-hook");
749
768
  var EVENT_CHANNELS = Object.freeze({
750
769
  READY: "state-guard:ready",
751
770
  VIOLATION: "state-guard:violation",
@@ -765,13 +784,15 @@ var StateGuardService = class {
765
784
  this.mode = this.config.mode;
766
785
  this.allowedAttributes = new Set(this.config.allowedAttributes.map((attr) => attr.toLowerCase()));
767
786
  this.allowedAttributePrefixes = this.config.allowedAttributePrefixes.map((attr) => attr.toLowerCase());
768
- this.allowedDatasetKeys = new Set(this.config.allowedDatasetKeys.map((key) => key.toLowerCase()));
787
+ this.allowedDatasetKeys = new Set(this.config.allowedDatasetKeys.map(normalizeDatasetKey));
769
788
  this.moduleOverrides = (this.config.moduleOverrides ?? []).map((entry) => ({
770
789
  pattern: entry.pattern,
771
790
  attributes: new Set(entry.attributes.map((attr) => attr.toLowerCase())),
772
- datasetKeys: new Set(entry.datasetKeys.map((key) => key.toLowerCase())),
791
+ datasetKeys: new Set(entry.datasetKeys.map(normalizeDatasetKey)),
773
792
  attributePrefixes: entry.attributePrefixes.map((prefix) => prefix.toLowerCase())
774
793
  }));
794
+ this.moduleFramePattern = this.config.moduleFramePattern;
795
+ this.stackCache = /* @__PURE__ */ new Map();
775
796
  this.#installHooks();
776
797
  }
777
798
  setMode(mode) {
@@ -797,7 +818,7 @@ var StateGuardService = class {
797
818
  const entry = {
798
819
  pattern,
799
820
  attributes: new Set(attributes.map((attr) => String(attr).toLowerCase())),
800
- datasetKeys: new Set(datasetKeys.map((key) => String(key).toLowerCase())),
821
+ datasetKeys: new Set(datasetKeys.map(normalizeDatasetKey)),
801
822
  attributePrefixes: attributePrefixes.map((prefix) => String(prefix).toLowerCase())
802
823
  };
803
824
  this.moduleOverrides.push(entry);
@@ -837,7 +858,11 @@ var StateGuardService = class {
837
858
  this.bypassDepth = Math.max(0, this.bypassDepth - 1);
838
859
  }
839
860
  }
840
- handleAttributeMutation(element, action, attribute, value) {
861
+ /**
862
+ * Check one attribute write. The write is attributed to the caller of this
863
+ * method, or to the caller of the patched DOM API when it came through one.
864
+ */
865
+ handleAttributeMutation(element, action, attribute, value, options = {}) {
841
866
  const attrName = this.#normalizeAttribute(attribute);
842
867
  if (!this.#shouldGuard(attrName)) {
843
868
  return;
@@ -847,15 +872,19 @@ var StateGuardService = class {
847
872
  attribute: attrName,
848
873
  element,
849
874
  value,
850
- source: "attribute"
875
+ source: "attribute",
876
+ stack: new Error().stack,
877
+ writerFrame: options?.[VIA_DOM_HOOK] ? 2 : 1
851
878
  });
852
879
  }
853
- handleDatasetMutation(element, key, value, { deleting = false } = {}) {
854
- const attrName = this.#datasetKeyToAttribute(key);
880
+ handleDatasetMutation(element, key, value, { deleting = false, [VIA_DOM_HOOK]: viaHook = false } = {}) {
881
+ const attrName = datasetKeyToAttribute(key);
855
882
  if (!this.#shouldGuard(attrName)) {
856
883
  return;
857
884
  }
858
885
  this.#evaluateMutation({
886
+ stack: new Error().stack,
887
+ writerFrame: viaHook ? 2 : 1,
859
888
  action: deleting ? "dataset:delete" : "dataset:set",
860
889
  attribute: attrName,
861
890
  element,
@@ -902,8 +931,8 @@ var StateGuardService = class {
902
931
  }
903
932
  return true;
904
933
  }
905
- #evaluateMutation({ action, attribute, element, value, source }) {
906
- const moduleKey = this.#resolveModuleFromStack();
934
+ #evaluateMutation({ action, attribute, element, value, source, stack, writerFrame }) {
935
+ const moduleKey = this.#resolveModuleFromStack(stack, writerFrame);
907
936
  if (this.#isAllowedForModule(moduleKey, attribute)) {
908
937
  return;
909
938
  }
@@ -955,37 +984,48 @@ var StateGuardService = class {
955
984
  }
956
985
  return String(attribute).toLowerCase();
957
986
  }
958
- #datasetKeyToAttribute(key) {
959
- if (!key && key !== 0) {
960
- return "";
961
- }
962
- const normalized = String(key).replace(/([A-Z])/g, "-$1").replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase().replace(/-{2,}/g, "-").replace(/^-+/, "").replace(/-+$/, "");
963
- if (!normalized) {
964
- return "";
965
- }
966
- return `${DATA_ATTRIBUTE_PREFIX}${normalized}`;
967
- }
968
- #resolveModuleFromStack() {
969
- const stack = new Error().stack;
987
+ /**
988
+ * The module a write is attributed to. `stack` was captured in a
989
+ * handle*Mutation method (frame 0); `writerFrame` is the index of the frame
990
+ * that made the write (1 for a direct call, 2 through a DOM hook). Without a
991
+ * `moduleFramePattern` that writer's location (its URL or path, line and
992
+ * column dropped) is the module. With one, the first frame from the writer
993
+ * up whose location matches is used, and the module is the pattern's first
994
+ * capture group, or that frame's whole location when it has none.
995
+ */
996
+ #resolveModuleFromStack(stack, writerFrame) {
970
997
  if (!stack) {
971
998
  return null;
972
999
  }
973
- if (STACK_CACHE.has(stack)) {
974
- return STACK_CACHE.get(stack);
1000
+ const cacheKey = `${writerFrame}
1001
+ ${stack}`;
1002
+ if (this.stackCache.has(cacheKey)) {
1003
+ return this.stackCache.get(cacheKey);
975
1004
  }
976
- const lines = stack.split("\n");
977
- let modulePath = null;
978
- for (const line of lines) {
979
- const match = line.match(/(js_new\/[^)\s]+)/);
1005
+ const locations = [];
1006
+ for (const line of String(stack).split("\n")) {
1007
+ const match = line.match(FRAME_LOCATION);
980
1008
  if (match) {
981
- modulePath = match[1];
982
- break;
1009
+ locations.push(match[1]);
983
1010
  }
984
1011
  }
985
- if (STACK_CACHE.size > 500) {
986
- STACK_CACHE.clear();
1012
+ const callers = locations.slice(writerFrame);
1013
+ let modulePath = null;
1014
+ if (!this.moduleFramePattern) {
1015
+ modulePath = callers[0] ?? null;
1016
+ } else {
1017
+ for (const location of callers) {
1018
+ const match = location.match(this.moduleFramePattern);
1019
+ if (match) {
1020
+ modulePath = match[1] ?? location;
1021
+ break;
1022
+ }
1023
+ }
1024
+ }
1025
+ if (this.stackCache.size > STACK_CACHE_LIMIT) {
1026
+ this.stackCache.clear();
987
1027
  }
988
- STACK_CACHE.set(stack, modulePath);
1028
+ this.stackCache.set(cacheKey, modulePath);
989
1029
  return modulePath;
990
1030
  }
991
1031
  #previewValue(value) {
@@ -999,6 +1039,19 @@ var StateGuardService = class {
999
1039
  return str.length > 50 ? `${str.slice(0, 47)}...` : str;
1000
1040
  }
1001
1041
  };
1042
+ function datasetKeyToAttribute(key) {
1043
+ if (!key && key !== 0) {
1044
+ return "";
1045
+ }
1046
+ const normalized = String(key).replace(/([A-Z])/g, "-$1").replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase().replace(/-{2,}/g, "-").replace(/^-+/, "").replace(/-+$/, "");
1047
+ if (!normalized) {
1048
+ return "";
1049
+ }
1050
+ return `${DATA_ATTRIBUTE_PREFIX}${normalized}`;
1051
+ }
1052
+ function normalizeDatasetKey(key) {
1053
+ return datasetKeyToAttribute(key).slice(DATA_ATTRIBUTE_PREFIX.length);
1054
+ }
1002
1055
  function installDomHooks(service) {
1003
1056
  if (HOOK_REGISTRY.installed) {
1004
1057
  HOOK_REGISTRY.service = service;
@@ -1013,20 +1066,12 @@ function installDomHooks(service) {
1013
1066
  HOOK_REGISTRY.originals.removeAttribute = nativeRemoveAttribute;
1014
1067
  Element.prototype.setAttribute = function patchedSetAttribute(name, value) {
1015
1068
  const guard = HOOK_REGISTRY.service;
1016
- try {
1017
- guard?.handleAttributeMutation(this, "setAttribute", name, value);
1018
- } catch (error) {
1019
- throw error;
1020
- }
1069
+ guard?.handleAttributeMutation(this, "setAttribute", name, value, { [VIA_DOM_HOOK]: true });
1021
1070
  return nativeSetAttribute.call(this, name, value);
1022
1071
  };
1023
1072
  Element.prototype.removeAttribute = function patchedRemoveAttribute(name) {
1024
1073
  const guard = HOOK_REGISTRY.service;
1025
- try {
1026
- guard?.handleAttributeMutation(this, "removeAttribute", name, void 0);
1027
- } catch (error) {
1028
- throw error;
1029
- }
1074
+ guard?.handleAttributeMutation(this, "removeAttribute", name, void 0, { [VIA_DOM_HOOK]: true });
1030
1075
  return nativeRemoveAttribute.call(this, name);
1031
1076
  };
1032
1077
  wrapDataset(service);
@@ -1056,7 +1101,7 @@ function wrapDataset(service) {
1056
1101
  const guard = HOOK_REGISTRY.service;
1057
1102
  const key = typeof prop === "string" ? prop : null;
1058
1103
  if (guard && key) {
1059
- guard.handleDatasetMutation(proxyState.element, key, value);
1104
+ guard.handleDatasetMutation(proxyState.element, key, value, { [VIA_DOM_HOOK]: true });
1060
1105
  }
1061
1106
  return Reflect.set(target, prop, value);
1062
1107
  },
@@ -1064,7 +1109,10 @@ function wrapDataset(service) {
1064
1109
  const guard = HOOK_REGISTRY.service;
1065
1110
  const key = typeof prop === "string" ? prop : null;
1066
1111
  if (guard && key) {
1067
- guard.handleDatasetMutation(proxyState.element, key, void 0, { deleting: true });
1112
+ guard.handleDatasetMutation(proxyState.element, key, void 0, {
1113
+ deleting: true,
1114
+ [VIA_DOM_HOOK]: true
1115
+ });
1068
1116
  }
1069
1117
  return Reflect.deleteProperty(target, prop);
1070
1118
  }
@@ -1075,11 +1123,13 @@ function wrapDataset(service) {
1075
1123
  });
1076
1124
  }
1077
1125
  export {
1126
+ DEFAULT_SETTINGS_STORAGE_KEY,
1078
1127
  DEFAULT_STATE_GUARD_CONFIG,
1079
1128
  EventBus,
1080
1129
  LoggingService,
1081
1130
  StateGuardService,
1082
1131
  StateMachine,
1132
+ configureSettings,
1083
1133
  createSettingsStore,
1084
1134
  getAllSettings,
1085
1135
  getCategories,
@@ -1087,6 +1137,8 @@ export {
1087
1137
  getSchema,
1088
1138
  getSetting,
1089
1139
  getSettingsByCategory,
1140
+ getSettingsStorageKey,
1141
+ getSettingsStore,
1090
1142
  normalizeStateGuardConfig,
1091
1143
  registerSettings,
1092
1144
  registerSettingsEventBus,