@happyvertical/smrt-svelte 0.55.7 → 0.55.9

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 (197) hide show
  1. package/AGENTS.md +7 -44
  2. package/README.md +112 -1
  3. package/agents/browser-ai.md +47 -0
  4. package/agents/command-palette.md +85 -0
  5. package/agents/import-export.md +62 -0
  6. package/agents/overview-surfaces.md +255 -0
  7. package/agents/screens.md +57 -0
  8. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +5 -0
  9. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -1
  10. package/dist/browser-ai/adapters/tts/browser-synthesis.js +83 -55
  11. package/dist/components/command-palette/CommandPalette.svelte +75 -0
  12. package/dist/components/command-palette/CommandPalette.svelte.d.ts +22 -0
  13. package/dist/components/command-palette/CommandPalette.svelte.d.ts.map +1 -0
  14. package/dist/components/command-palette/CommandPaletteDialog.svelte +406 -0
  15. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts +18 -0
  16. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts.map +1 -0
  17. package/dist/components/command-palette/CommandPaletteTrigger.svelte +91 -0
  18. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts +17 -0
  19. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts.map +1 -0
  20. package/dist/components/command-palette/context.d.ts +18 -0
  21. package/dist/components/command-palette/context.d.ts.map +1 -0
  22. package/dist/components/command-palette/context.js +38 -0
  23. package/dist/components/command-palette/controller.svelte.d.ts +70 -0
  24. package/dist/components/command-palette/controller.svelte.d.ts.map +1 -0
  25. package/dist/components/command-palette/controller.svelte.js +379 -0
  26. package/dist/components/command-palette/hotkeys.d.ts +30 -0
  27. package/dist/components/command-palette/hotkeys.d.ts.map +1 -0
  28. package/dist/components/command-palette/hotkeys.js +161 -0
  29. package/dist/components/command-palette/index.d.ts +19 -0
  30. package/dist/components/command-palette/index.d.ts.map +1 -0
  31. package/dist/components/command-palette/index.js +17 -0
  32. package/dist/components/command-palette/match.d.ts +38 -0
  33. package/dist/components/command-palette/match.d.ts.map +1 -0
  34. package/dist/components/command-palette/match.js +172 -0
  35. package/dist/components/command-palette/providers.d.ts +159 -0
  36. package/dist/components/command-palette/providers.d.ts.map +1 -0
  37. package/dist/components/command-palette/providers.js +345 -0
  38. package/dist/components/command-palette/rank.d.ts +20 -0
  39. package/dist/components/command-palette/rank.d.ts.map +1 -0
  40. package/dist/components/command-palette/rank.js +74 -0
  41. package/dist/components/command-palette/types.d.ts +119 -0
  42. package/dist/components/command-palette/types.d.ts.map +1 -0
  43. package/dist/components/command-palette/types.js +10 -0
  44. package/dist/components/command-palette/use-provider.svelte.d.ts +14 -0
  45. package/dist/components/command-palette/use-provider.svelte.d.ts.map +1 -0
  46. package/dist/components/command-palette/use-provider.svelte.js +23 -0
  47. package/dist/components/import-export/ImportExport.svelte +678 -0
  48. package/dist/components/import-export/ImportExport.svelte.d.ts +5 -0
  49. package/dist/components/import-export/ImportExport.svelte.d.ts.map +1 -0
  50. package/dist/components/import-export/collection-adapter.d.ts +35 -0
  51. package/dist/components/import-export/collection-adapter.d.ts.map +1 -0
  52. package/dist/components/import-export/collection-adapter.js +42 -0
  53. package/dist/components/import-export/csv.d.ts +60 -0
  54. package/dist/components/import-export/csv.d.ts.map +1 -0
  55. package/dist/components/import-export/csv.js +192 -0
  56. package/dist/components/import-export/download.d.ts +4 -0
  57. package/dist/components/import-export/download.d.ts.map +1 -0
  58. package/dist/components/import-export/download.js +17 -0
  59. package/dist/components/import-export/export.d.ts +25 -0
  60. package/dist/components/import-export/export.d.ts.map +1 -0
  61. package/dist/components/import-export/export.js +68 -0
  62. package/dist/components/import-export/fields.d.ts +48 -0
  63. package/dist/components/import-export/fields.d.ts.map +1 -0
  64. package/dist/components/import-export/fields.js +103 -0
  65. package/dist/components/import-export/index.d.ts +12 -0
  66. package/dist/components/import-export/index.d.ts.map +1 -0
  67. package/dist/components/import-export/index.js +9 -0
  68. package/dist/components/import-export/mapping.d.ts +12 -0
  69. package/dist/components/import-export/mapping.d.ts.map +1 -0
  70. package/dist/components/import-export/mapping.js +38 -0
  71. package/dist/components/import-export/props.d.ts +34 -0
  72. package/dist/components/import-export/props.d.ts.map +1 -0
  73. package/dist/components/import-export/props.js +1 -0
  74. package/dist/components/import-export/report.d.ts +13 -0
  75. package/dist/components/import-export/report.d.ts.map +1 -0
  76. package/dist/components/import-export/report.js +50 -0
  77. package/dist/components/import-export/runner.d.ts +17 -0
  78. package/dist/components/import-export/runner.d.ts.map +1 -0
  79. package/dist/components/import-export/runner.js +39 -0
  80. package/dist/components/import-export/types.d.ts +100 -0
  81. package/dist/components/import-export/types.d.ts.map +1 -0
  82. package/dist/components/import-export/types.js +6 -0
  83. package/dist/components/import-export/validate.d.ts +39 -0
  84. package/dist/components/import-export/validate.d.ts.map +1 -0
  85. package/dist/components/import-export/validate.js +268 -0
  86. package/dist/components/overview/OverviewGrid.svelte +579 -0
  87. package/dist/components/overview/OverviewGrid.svelte.d.ts +5 -0
  88. package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -0
  89. package/dist/components/overview/WidgetOptionsForm.svelte +193 -0
  90. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts +5 -0
  91. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -0
  92. package/dist/components/overview/controller.svelte.d.ts +92 -0
  93. package/dist/components/overview/controller.svelte.d.ts.map +1 -0
  94. package/dist/components/overview/controller.svelte.js +336 -0
  95. package/dist/components/overview/format.d.ts +13 -0
  96. package/dist/components/overview/format.d.ts.map +1 -0
  97. package/dist/components/overview/format.js +45 -0
  98. package/dist/components/overview/grid-types.d.ts +52 -0
  99. package/dist/components/overview/grid-types.d.ts.map +1 -0
  100. package/dist/components/overview/grid-types.js +1 -0
  101. package/dist/components/overview/index.d.ts +24 -0
  102. package/dist/components/overview/index.d.ts.map +1 -0
  103. package/dist/components/overview/index.js +22 -0
  104. package/dist/components/overview/load.d.ts +30 -0
  105. package/dist/components/overview/load.d.ts.map +1 -0
  106. package/dist/components/overview/load.js +92 -0
  107. package/dist/components/overview/markdown.d.ts +53 -0
  108. package/dist/components/overview/markdown.d.ts.map +1 -0
  109. package/dist/components/overview/markdown.js +203 -0
  110. package/dist/components/overview/model.d.ts +100 -0
  111. package/dist/components/overview/model.d.ts.map +1 -0
  112. package/dist/components/overview/model.js +460 -0
  113. package/dist/components/overview/recipe-widgets.d.ts +77 -0
  114. package/dist/components/overview/recipe-widgets.d.ts.map +1 -0
  115. package/dist/components/overview/recipe-widgets.js +151 -0
  116. package/dist/components/overview/registry.d.ts +45 -0
  117. package/dist/components/overview/registry.d.ts.map +1 -0
  118. package/dist/components/overview/registry.js +112 -0
  119. package/dist/components/overview/resize.d.ts +25 -0
  120. package/dist/components/overview/resize.d.ts.map +1 -0
  121. package/dist/components/overview/resize.js +41 -0
  122. package/dist/components/overview/schema.d.ts +34 -0
  123. package/dist/components/overview/schema.d.ts.map +1 -0
  124. package/dist/components/overview/schema.js +180 -0
  125. package/dist/components/overview/server.d.ts +14 -0
  126. package/dist/components/overview/server.d.ts.map +1 -0
  127. package/dist/components/overview/server.js +13 -0
  128. package/dist/components/overview/types.d.ts +235 -0
  129. package/dist/components/overview/types.d.ts.map +1 -0
  130. package/dist/components/overview/types.js +17 -0
  131. package/dist/components/overview/widgets/ChartWidget.svelte +111 -0
  132. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +6 -0
  133. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -0
  134. package/dist/components/overview/widgets/MetricWidget.svelte +86 -0
  135. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts +6 -0
  136. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts.map +1 -0
  137. package/dist/components/overview/widgets/NoteWidget.svelte +61 -0
  138. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts +5 -0
  139. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts.map +1 -0
  140. package/dist/components/overview/widgets/RecordListWidget.svelte +91 -0
  141. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts +6 -0
  142. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts.map +1 -0
  143. package/dist/components/overview/widgets/ShortcutsWidget.svelte +80 -0
  144. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts +6 -0
  145. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts.map +1 -0
  146. package/dist/components/overview/widgets/core.d.ts +44 -0
  147. package/dist/components/overview/widgets/core.d.ts.map +1 -0
  148. package/dist/components/overview/widgets/core.js +222 -0
  149. package/dist/components/overview/widgets/data.d.ts +76 -0
  150. package/dist/components/overview/widgets/data.d.ts.map +1 -0
  151. package/dist/components/overview/widgets/data.js +40 -0
  152. package/dist/components/screens/DetailScreen.svelte +220 -0
  153. package/dist/components/screens/DetailScreen.svelte.d.ts +5 -0
  154. package/dist/components/screens/DetailScreen.svelte.d.ts.map +1 -0
  155. package/dist/components/screens/EditForm.svelte +313 -0
  156. package/dist/components/screens/EditForm.svelte.d.ts +5 -0
  157. package/dist/components/screens/EditForm.svelte.d.ts.map +1 -0
  158. package/dist/components/screens/ListScreen.svelte +191 -0
  159. package/dist/components/screens/ListScreen.svelte.d.ts +5 -0
  160. package/dist/components/screens/ListScreen.svelte.d.ts.map +1 -0
  161. package/dist/components/screens/RecipeScreens.svelte +237 -0
  162. package/dist/components/screens/RecipeScreens.svelte.d.ts +5 -0
  163. package/dist/components/screens/RecipeScreens.svelte.d.ts.map +1 -0
  164. package/dist/components/screens/fields.d.ts +54 -0
  165. package/dist/components/screens/fields.d.ts.map +1 -0
  166. package/dist/components/screens/fields.js +229 -0
  167. package/dist/components/screens/index.d.ts +8 -0
  168. package/dist/components/screens/index.d.ts.map +1 -0
  169. package/dist/components/screens/index.js +6 -0
  170. package/dist/components/screens/types.d.ts +215 -0
  171. package/dist/components/screens/types.d.ts.map +1 -0
  172. package/dist/components/screens/types.js +1 -0
  173. package/dist/components/screens/values.d.ts +62 -0
  174. package/dist/components/screens/values.d.ts.map +1 -0
  175. package/dist/components/screens/values.js +289 -0
  176. package/dist/components/sortable/controller.svelte.d.ts +10 -0
  177. package/dist/components/sortable/controller.svelte.d.ts.map +1 -1
  178. package/dist/components/sortable/controller.svelte.js +29 -7
  179. package/dist/components/workspace/manifest-nav.d.ts +20 -0
  180. package/dist/components/workspace/manifest-nav.d.ts.map +1 -1
  181. package/dist/components/workspace/manifest-nav.js +42 -13
  182. package/dist/i18n/server.d.ts +6 -0
  183. package/dist/i18n/server.d.ts.map +1 -1
  184. package/dist/i18n/server.js +6 -0
  185. package/dist/i18n/strings.import-export.d.ts +88 -0
  186. package/dist/i18n/strings.import-export.d.ts.map +1 -0
  187. package/dist/i18n/strings.import-export.js +88 -0
  188. package/dist/i18n/strings.overview.d.ts +100 -0
  189. package/dist/i18n/strings.overview.d.ts.map +1 -0
  190. package/dist/i18n/strings.overview.js +107 -0
  191. package/dist/i18n/strings.palette.d.ts +18 -0
  192. package/dist/i18n/strings.palette.d.ts.map +1 -0
  193. package/dist/i18n/strings.palette.js +18 -0
  194. package/dist/i18n/strings.screens.d.ts +31 -0
  195. package/dist/i18n/strings.screens.d.ts.map +1 -0
  196. package/dist/i18n/strings.screens.js +31 -0
  197. package/package.json +45 -16
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Number formatting for overview widgets (#3727). Deterministic for a given
3
+ * locale so a server render and the client hydrate to the same text. Money is
4
+ * integer minor units end to end (never a decimal in data).
5
+ */
6
+ import { currencyMinorDigits } from '../screens/values.js';
7
+ const EN_DASH = '–';
8
+ function safeLocale(locale) {
9
+ try {
10
+ return Intl.getCanonicalLocales(locale)[0] ?? 'en';
11
+ }
12
+ catch {
13
+ return 'en';
14
+ }
15
+ }
16
+ /**
17
+ * Format a metric value. `money` takes integer minor units, `percent` takes a
18
+ * fraction (0.25 is 25%). Non-finite input renders as an en dash.
19
+ */
20
+ export function formatWidgetValue(value, { format = 'integer', currency = 'USD', locale }) {
21
+ if (typeof value !== 'number' || !Number.isFinite(value))
22
+ return EN_DASH;
23
+ const tag = safeLocale(locale);
24
+ switch (format) {
25
+ case 'money': {
26
+ const code = /^[A-Za-z]{3}$/.test(currency)
27
+ ? currency.toUpperCase()
28
+ : 'USD';
29
+ const digits = currencyMinorDigits(code);
30
+ return new Intl.NumberFormat(tag, {
31
+ style: 'currency',
32
+ currency: code,
33
+ }).format(value / 10 ** digits);
34
+ }
35
+ case 'percent':
36
+ return new Intl.NumberFormat(tag, {
37
+ style: 'percent',
38
+ maximumFractionDigits: 1,
39
+ }).format(value);
40
+ case 'decimal':
41
+ return new Intl.NumberFormat(tag, { maximumFractionDigits: 2 }).format(value);
42
+ default:
43
+ return new Intl.NumberFormat(tag, { maximumFractionDigits: 0 }).format(value);
44
+ }
45
+ }
@@ -0,0 +1,52 @@
1
+ import type { Component } from 'svelte';
2
+ import type { OverviewController } from './controller.svelte.js';
3
+ import type { OverviewOptions, RegisteredWidget, WidgetComponentProps } from './types.js';
4
+ /** A model the option editor offers for `model` fields. */
5
+ export interface OverviewModelChoice {
6
+ value: string;
7
+ label: string;
8
+ }
9
+ /** Props of `OverviewGrid`. */
10
+ export interface OverviewGridProps {
11
+ /** The overview's state, from `createOverview`. */
12
+ controller: OverviewController;
13
+ /**
14
+ * Resolved widget components (see `resolveWidgetComponents`). A type with
15
+ * no entry falls back to the registered `component`, else renders as
16
+ * unavailable.
17
+ */
18
+ components?: ReadonlyMap<string, Component<WidgetComponentProps>>;
19
+ /**
20
+ * Edit mode. Omit to follow the shell's layout editor (the pencil), so a
21
+ * grid inside `AppShell` edits with the rest of the page.
22
+ */
23
+ editing?: boolean;
24
+ /** Accessible name of the grid. */
25
+ label?: string;
26
+ /** Heading level of widget titles (default 2). */
27
+ headingLevel?: 2 | 3 | 4;
28
+ /** Models offered by `model` option fields (else a text box). */
29
+ models?: readonly OverviewModelChoice[];
30
+ /** Host renderer for icon names that are not built in. */
31
+ iconComponent?: Component<{
32
+ name: string;
33
+ size?: number;
34
+ }>;
35
+ }
36
+ /** An option-level problem shown next to its field. */
37
+ export interface OverviewFormIssue {
38
+ key: string;
39
+ code: string;
40
+ }
41
+ /** Props of `WidgetOptionsForm`. */
42
+ export interface WidgetOptionsFormProps {
43
+ /** The widget type being configured. */
44
+ definition: RegisteredWidget;
45
+ /** Current options (an existing widget) or starting values. */
46
+ initial: OverviewOptions;
47
+ models?: readonly OverviewModelChoice[];
48
+ /** Saves; returns issues to show, or `null` when it worked. */
49
+ onsave: (options: OverviewOptions) => OverviewFormIssue[] | null;
50
+ oncancel: () => void;
51
+ }
52
+ //# sourceMappingURL=grid-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-types.d.ts","sourceRoot":"","sources":["../../../src/components/overview/grid-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,UAAU,EAAE,kBAAkB,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAClE;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,iEAAiE;IACjE,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACxC,0DAA0D;IAC1D,aAAa,CAAC,EAAE,SAAS,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,uDAAuD;AACvD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oCAAoC;AACpC,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,+DAA+D;IAC/D,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACxC,+DAA+D;IAC/D,MAAM,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,iBAAiB,EAAE,GAAG,IAAI,CAAC;IACjE,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @happyvertical/smrt-svelte/overview
3
+ *
4
+ * Customizable overview surfaces (#3727): a flow grid of registered widgets
5
+ * with versioned option schemas, edited in place with the shell's layout
6
+ * editor. The Svelte-free model, registry and server load contract are also
7
+ * published on `@happyvertical/smrt-svelte/overview/server`.
8
+ */
9
+ export { createOverview, OverviewController, type OverviewControllerOptions, type OverviewOpResult, type OverviewWidgetEntry, } from './controller.svelte.js';
10
+ export { type FormatWidgetValueOptions, formatWidgetValue, type WidgetValueFormat, } from './format.js';
11
+ export type { OverviewFormIssue, OverviewGridProps, OverviewModelChoice, WidgetOptionsFormProps, } from './grid-types.js';
12
+ export { type BlockNode, type InlineNode, parseMarkdown, safeHref, } from './markdown.js';
13
+ export { default as OverviewGrid } from './OverviewGrid.svelte';
14
+ export { spanFromKey, spanFromPointer } from './resize.js';
15
+ export * from './server.js';
16
+ export { default as WidgetOptionsForm } from './WidgetOptionsForm.svelte';
17
+ export { default as ChartWidget } from './widgets/ChartWidget.svelte';
18
+ export { type CoreWidgetLoaders, createChartWidget, createMetricWidget, createNoteWidget, createRecordListWidget, createShortcutsWidget, registerCoreWidgets, } from './widgets/core.js';
19
+ export { type ChartWidgetData, type MetricWidgetData, type RecordListWidgetData, type ShortcutNavSection, type ShortcutsWidgetData, shortcutsFromNav, } from './widgets/data.js';
20
+ export { default as MetricWidget } from './widgets/MetricWidget.svelte';
21
+ export { default as NoteWidget } from './widgets/NoteWidget.svelte';
22
+ export { default as RecordListWidget } from './widgets/RecordListWidget.svelte';
23
+ export { default as ShortcutsWidget } from './widgets/ShortcutsWidget.svelte';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/overview/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,wBAAwB,EAC7B,iBAAiB,EACjB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,aAAa,EACb,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EACL,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @happyvertical/smrt-svelte/overview
3
+ *
4
+ * Customizable overview surfaces (#3727): a flow grid of registered widgets
5
+ * with versioned option schemas, edited in place with the shell's layout
6
+ * editor. The Svelte-free model, registry and server load contract are also
7
+ * published on `@happyvertical/smrt-svelte/overview/server`.
8
+ */
9
+ export { createOverview, OverviewController, } from './controller.svelte.js';
10
+ export { formatWidgetValue, } from './format.js';
11
+ export { parseMarkdown, safeHref, } from './markdown.js';
12
+ export { default as OverviewGrid } from './OverviewGrid.svelte';
13
+ export { spanFromKey, spanFromPointer } from './resize.js';
14
+ export * from './server.js';
15
+ export { default as WidgetOptionsForm } from './WidgetOptionsForm.svelte';
16
+ export { default as ChartWidget } from './widgets/ChartWidget.svelte';
17
+ export { createChartWidget, createMetricWidget, createNoteWidget, createRecordListWidget, createShortcutsWidget, registerCoreWidgets, } from './widgets/core.js';
18
+ export { shortcutsFromNav, } from './widgets/data.js';
19
+ export { default as MetricWidget } from './widgets/MetricWidget.svelte';
20
+ export { default as NoteWidget } from './widgets/NoteWidget.svelte';
21
+ export { default as RecordListWidget } from './widgets/RecordListWidget.svelte';
22
+ export { default as ShortcutsWidget } from './widgets/ShortcutsWidget.svelte';
@@ -0,0 +1,30 @@
1
+ import type { WidgetRegistry } from './registry.js';
2
+ import type { LoadedOverview, OverviewDefinition, OverviewDocument } from './types.js';
3
+ export interface LoadOverviewOptions {
4
+ /** Per-widget time budget in milliseconds (default 8000). */
5
+ timeoutMs?: number;
6
+ /** Largest serialized `data` a widget may return (default 262144 chars). */
7
+ maxDataLength?: number;
8
+ /**
9
+ * Receives the real error of a failed load for server logs. The client only
10
+ * ever gets a generic code.
11
+ */
12
+ onError?: (widget: {
13
+ id: string;
14
+ type: string;
15
+ }, error: unknown) => void;
16
+ }
17
+ /** The request-scoped context a page passes to {@link loadOverview}. */
18
+ export interface WidgetLoadInput {
19
+ signal?: AbortSignal;
20
+ locale?: string;
21
+ [capability: string]: unknown;
22
+ }
23
+ /**
24
+ * Sanitize `document` against the registry and the page's confined set, then
25
+ * run each widget's `load` in parallel. A widget that fails, times out or
26
+ * returns non-serializable data renders as an error tile; it never fails the
27
+ * page. Widgets without a `load` are `ready` with no data.
28
+ */
29
+ export declare function loadOverview(document: OverviewDocument, definition: OverviewDefinition, registry: WidgetRegistry, ctx: WidgetLoadInput, options?: LoadOverviewOptions): Promise<LoadedOverview>;
30
+ //# sourceMappingURL=load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/components/overview/load.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EACV,cAAc,EAGd,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1E;AAED,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AA0CD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,EAAE,kBAAkB,EAC9B,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,cAAc,CAAC,CAkCzB"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * The server load contract (#3727): run every widget's `load(options, ctx)`
3
+ * inside a page's server load, with the request's context, and hand the
4
+ * client a serializable {@link LoadedOverview} to render without any
5
+ * client-only fetching.
6
+ *
7
+ * ```ts
8
+ * // +page.server.ts
9
+ * export const load = async (event) => {
10
+ * const resolved = resolveOverview(definition, await storedOverride(event), registry);
11
+ * return { overview: await loadOverview(resolved.document, definition, registry, ctx(event)) };
12
+ * };
13
+ * ```
14
+ *
15
+ * Svelte-free. The context carries the user's permissions and tenant
16
+ * filters; this module never widens it.
17
+ */
18
+ import { sanitizeOverview } from './model.js';
19
+ const DEFAULT_TIMEOUT_MS = 8000;
20
+ const DEFAULT_MAX_DATA_LENGTH = 262_144;
21
+ class LoadTimeout extends Error {
22
+ }
23
+ function runWithTimeout(run, timeoutMs, parent) {
24
+ const controller = new AbortController();
25
+ const abort = () => controller.abort();
26
+ parent?.addEventListener('abort', abort, { once: true });
27
+ if (parent?.aborted)
28
+ controller.abort();
29
+ let timer;
30
+ const timeout = new Promise((_resolve, reject) => {
31
+ timer = setTimeout(() => {
32
+ controller.abort();
33
+ reject(new LoadTimeout('widget load timed out'));
34
+ }, timeoutMs);
35
+ });
36
+ return Promise.race([
37
+ Promise.resolve().then(() => run(controller.signal)),
38
+ timeout,
39
+ ]).finally(() => {
40
+ if (timer !== undefined)
41
+ clearTimeout(timer);
42
+ parent?.removeEventListener('abort', abort);
43
+ });
44
+ }
45
+ function serializable(data, maxLength) {
46
+ if (data === undefined)
47
+ return true;
48
+ try {
49
+ const json = JSON.stringify(data);
50
+ return json !== undefined && json.length <= maxLength;
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ }
56
+ /**
57
+ * Sanitize `document` against the registry and the page's confined set, then
58
+ * run each widget's `load` in parallel. A widget that fails, times out or
59
+ * returns non-serializable data renders as an error tile; it never fails the
60
+ * page. Widgets without a `load` are `ready` with no data.
61
+ */
62
+ export async function loadOverview(document, definition, registry, ctx, options = {}) {
63
+ const sanitized = sanitizeOverview(document, { registry, definition });
64
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
65
+ const maxLength = options.maxDataLength ?? DEFAULT_MAX_DATA_LENGTH;
66
+ const widgets = await Promise.all(sanitized.document.widgets.map(async (widget) => {
67
+ const def = registry.get(widget.type);
68
+ const base = { ...widget, status: 'ready' };
69
+ if (!def?.load)
70
+ return base;
71
+ const fail = (code) => ({
72
+ ...widget,
73
+ status: 'error',
74
+ error: { code },
75
+ });
76
+ try {
77
+ const data = await runWithTimeout((signal) => def.load?.(widget.options, {
78
+ ...ctx,
79
+ overviewId: definition.id,
80
+ signal,
81
+ }), timeoutMs, ctx.signal);
82
+ if (!serializable(data, maxLength))
83
+ return fail('invalid_data');
84
+ return data === undefined ? base : { ...base, data };
85
+ }
86
+ catch (error) {
87
+ options.onError?.({ id: widget.id, type: widget.type }, error);
88
+ return fail(error instanceof LoadTimeout ? 'timeout' : 'load_failed');
89
+ }
90
+ }));
91
+ return { overviewId: definition.id, widgets, issues: sanitized.issues };
92
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * A small, safe Markdown subset for the note widget (#3727).
3
+ *
4
+ * It parses to a node tree that components render as Svelte elements. There
5
+ * is no HTML output and no `{@html}`: raw HTML in the source is plain text,
6
+ * and links pass {@link safeHref}, so a stored note cannot inject markup or a
7
+ * `javascript:` URL by construction.
8
+ *
9
+ * Supported: `#`-`###` headings, paragraphs, `-`/`*` and `1.` lists,
10
+ * `>` quotes, fenced code, and inline **bold**, *italic*, `code`, and
11
+ * [links](https://example.com). Anything else is literal text.
12
+ */
13
+ export type InlineNode = {
14
+ type: 'text';
15
+ text: string;
16
+ } | {
17
+ type: 'code';
18
+ text: string;
19
+ } | {
20
+ type: 'strong' | 'em';
21
+ children: InlineNode[];
22
+ } | {
23
+ type: 'link';
24
+ href: string;
25
+ children: InlineNode[];
26
+ };
27
+ export type BlockNode = {
28
+ type: 'heading';
29
+ level: 1 | 2 | 3;
30
+ children: InlineNode[];
31
+ } | {
32
+ type: 'paragraph';
33
+ children: InlineNode[];
34
+ } | {
35
+ type: 'quote';
36
+ children: InlineNode[];
37
+ } | {
38
+ type: 'list';
39
+ ordered: boolean;
40
+ items: InlineNode[][];
41
+ } | {
42
+ type: 'code';
43
+ text: string;
44
+ };
45
+ /**
46
+ * The URL when it is safe to link: `http(s):`, `mailto:`, a same-site path
47
+ * (`/x`, not `//host`), or a fragment. Everything else (`javascript:`,
48
+ * `data:`, control characters, whitespace, quotes) is `null`.
49
+ */
50
+ export declare function safeHref(raw: string): string | null;
51
+ /** Parse a note into blocks. Total; capped in size and nesting. */
52
+ export declare function parseMarkdown(source: string): BlockNode[];
53
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/components/overview/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AAE3D,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,EAAE,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAMnC;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBnD;AA8FD,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAuEzD"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * A small, safe Markdown subset for the note widget (#3727).
3
+ *
4
+ * It parses to a node tree that components render as Svelte elements. There
5
+ * is no HTML output and no `{@html}`: raw HTML in the source is plain text,
6
+ * and links pass {@link safeHref}, so a stored note cannot inject markup or a
7
+ * `javascript:` URL by construction.
8
+ *
9
+ * Supported: `#`-`###` headings, paragraphs, `-`/`*` and `1.` lists,
10
+ * `>` quotes, fenced code, and inline **bold**, *italic*, `code`, and
11
+ * [links](https://example.com). Anything else is literal text.
12
+ */
13
+ const MAX_BLOCKS = 200;
14
+ const MAX_INLINE_DEPTH = 4;
15
+ const MAX_SOURCE = 20_000;
16
+ /**
17
+ * The URL when it is safe to link: `http(s):`, `mailto:`, a same-site path
18
+ * (`/x`, not `//host`), or a fragment. Everything else (`javascript:`,
19
+ * `data:`, control characters, whitespace, quotes) is `null`.
20
+ */
21
+ export function safeHref(raw) {
22
+ const url = raw.trim();
23
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: rejecting control characters is the point
24
+ if (!url || url.length > 2048 || /[\u0000-\u001f\u007f\s<>"'`\\]/.test(url)) {
25
+ return null;
26
+ }
27
+ if (/^https?:\/\//i.test(url)) {
28
+ try {
29
+ new URL(url);
30
+ return url;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ if (/^mailto:[^\s?]+(\?.*)?$/i.test(url))
37
+ return url;
38
+ if (url.startsWith('#'))
39
+ return url;
40
+ if (url.startsWith('/') && !url.startsWith('//'))
41
+ return url;
42
+ return null;
43
+ }
44
+ const isWordChar = (ch) => ch !== undefined && /[A-Za-z0-9]/.test(ch);
45
+ function parseInline(src, depth) {
46
+ const out = [];
47
+ let text = '';
48
+ const flush = () => {
49
+ if (text)
50
+ out.push({ type: 'text', text });
51
+ text = '';
52
+ };
53
+ let i = 0;
54
+ while (i < src.length) {
55
+ const ch = src[i];
56
+ if (ch === '\\' &&
57
+ i + 1 < src.length &&
58
+ /[\\`*_[\]()#>-]/.test(src[i + 1])) {
59
+ text += src[i + 1];
60
+ i += 2;
61
+ continue;
62
+ }
63
+ if (ch === '`') {
64
+ const end = src.indexOf('`', i + 1);
65
+ if (end > i + 1) {
66
+ flush();
67
+ out.push({ type: 'code', text: src.slice(i + 1, end) });
68
+ i = end + 1;
69
+ continue;
70
+ }
71
+ }
72
+ if (depth < MAX_INLINE_DEPTH && src.startsWith('**', i)) {
73
+ const end = src.indexOf('**', i + 2);
74
+ if (end > i + 2) {
75
+ flush();
76
+ out.push({
77
+ type: 'strong',
78
+ children: parseInline(src.slice(i + 2, end), depth + 1),
79
+ });
80
+ i = end + 2;
81
+ continue;
82
+ }
83
+ }
84
+ if (depth < MAX_INLINE_DEPTH &&
85
+ (ch === '*' || ch === '_') &&
86
+ src[i + 1] !== ' ' &&
87
+ !(ch === '_' && isWordChar(src[i - 1]))) {
88
+ const end = src.indexOf(ch, i + 1);
89
+ if (end > i + 1 &&
90
+ src[end - 1] !== ' ' &&
91
+ !(ch === '_' && isWordChar(src[end + 1]))) {
92
+ flush();
93
+ out.push({
94
+ type: 'em',
95
+ children: parseInline(src.slice(i + 1, end), depth + 1),
96
+ });
97
+ i = end + 1;
98
+ continue;
99
+ }
100
+ }
101
+ if (ch === '[' && depth < MAX_INLINE_DEPTH) {
102
+ const close = src.indexOf('](', i + 1);
103
+ const endParen = close > 0 ? src.indexOf(')', close + 2) : -1;
104
+ if (close > 0 && endParen > 0) {
105
+ const label = src.slice(i + 1, close);
106
+ const href = safeHref(src.slice(close + 2, endParen));
107
+ flush();
108
+ if (href) {
109
+ out.push({
110
+ type: 'link',
111
+ href,
112
+ children: parseInline(label, depth + 1),
113
+ });
114
+ }
115
+ else {
116
+ // An unsafe target keeps the label as plain text.
117
+ out.push(...parseInline(label, depth + 1));
118
+ }
119
+ i = endParen + 1;
120
+ continue;
121
+ }
122
+ }
123
+ text += ch;
124
+ i += 1;
125
+ }
126
+ flush();
127
+ return out;
128
+ }
129
+ /** Parse a note into blocks. Total; capped in size and nesting. */
130
+ export function parseMarkdown(source) {
131
+ const lines = source.slice(0, MAX_SOURCE).replace(/\r\n?/g, '\n').split('\n');
132
+ const blocks = [];
133
+ let paragraph = [];
134
+ let list = null;
135
+ const closeParagraph = () => {
136
+ if (paragraph.length) {
137
+ blocks.push({
138
+ type: 'paragraph',
139
+ children: parseInline(paragraph.join(' '), 0),
140
+ });
141
+ }
142
+ paragraph = [];
143
+ };
144
+ const closeList = () => {
145
+ if (list)
146
+ blocks.push({ type: 'list', ...list });
147
+ list = null;
148
+ };
149
+ for (let i = 0; i < lines.length && blocks.length < MAX_BLOCKS; i += 1) {
150
+ const line = lines[i];
151
+ if (/^\s*```/.test(line)) {
152
+ closeParagraph();
153
+ closeList();
154
+ const body = [];
155
+ i += 1;
156
+ while (i < lines.length && !/^\s*```/.test(lines[i])) {
157
+ body.push(lines[i]);
158
+ i += 1;
159
+ }
160
+ blocks.push({ type: 'code', text: body.join('\n') });
161
+ continue;
162
+ }
163
+ if (line.trim() === '') {
164
+ closeParagraph();
165
+ closeList();
166
+ continue;
167
+ }
168
+ const heading = /^(#{1,3})\s+(.*\S)\s*$/.exec(line);
169
+ if (heading) {
170
+ closeParagraph();
171
+ closeList();
172
+ blocks.push({
173
+ type: 'heading',
174
+ level: heading[1].length,
175
+ children: parseInline(heading[2], 0),
176
+ });
177
+ continue;
178
+ }
179
+ const bullet = /^\s*[-*]\s+(.*\S)\s*$/.exec(line);
180
+ const numbered = /^\s*\d+[.)]\s+(.*\S)\s*$/.exec(line);
181
+ if (bullet || numbered) {
182
+ closeParagraph();
183
+ const ordered = numbered !== null;
184
+ if (list && list.ordered !== ordered)
185
+ closeList();
186
+ list ??= { ordered, items: [] };
187
+ list.items.push(parseInline((bullet ?? numbered)?.[1] ?? '', 0));
188
+ continue;
189
+ }
190
+ const quote = /^\s*>\s?(.*)$/.exec(line);
191
+ if (quote) {
192
+ closeParagraph();
193
+ closeList();
194
+ blocks.push({ type: 'quote', children: parseInline(quote[1], 0) });
195
+ continue;
196
+ }
197
+ closeList();
198
+ paragraph.push(line.trim());
199
+ }
200
+ closeParagraph();
201
+ closeList();
202
+ return blocks.slice(0, MAX_BLOCKS);
203
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The pure overview data model (#3727): parse untrusted JSON, merge a stored
3
+ * override onto the page defaults, derive the sparse override back from an
4
+ * edited document, and sanitize a document against the widget registry.
5
+ *
6
+ * Everything here is total and never throws on bad input: unknown, invalid
7
+ * or disallowed widgets are dropped and reported as {@link OverviewIssue}s,
8
+ * never executed. Svelte-free; runs on the server on save and on load.
9
+ */
10
+ import type { WidgetRegistry } from './registry.js';
11
+ import { type OverviewDefinition, type OverviewDocument, type OverviewIssue, type OverviewOverride } from './types.js';
12
+ /** Parse untrusted JSON into a document. Malformed widgets are dropped. */
13
+ export declare function parseOverviewDocument(input: unknown): {
14
+ document: OverviewDocument;
15
+ issues: OverviewIssue[];
16
+ };
17
+ /**
18
+ * Parse an untrusted stored override. Never throws; an unknown version, or
19
+ * anything that is not an object, yields `null` (no override).
20
+ */
21
+ export declare function parseOverviewOverride(input: unknown): {
22
+ override: OverviewOverride | null;
23
+ issues: OverviewIssue[];
24
+ };
25
+ /** True when an override changes nothing. */
26
+ export declare function isEmptyOverride(override: OverviewOverride | null): boolean;
27
+ /**
28
+ * Merge an override onto a base document. Total: ids the base no longer has
29
+ * are ignored, added widgets whose id collides with the base are skipped, and
30
+ * widgets the order does not list keep their slots (listed ids permute among
31
+ * the slots they occupy), so a default shipped later still appears.
32
+ */
33
+ export declare function applyOverviewOverride(base: OverviewDocument, override: OverviewOverride | null): OverviewDocument;
34
+ /**
35
+ * The sparse override that turns `base` into `next` (the inverse of
36
+ * {@link applyOverviewOverride}); `null` when they are the same. Both
37
+ * documents should already be sanitized so versions compare like for like.
38
+ */
39
+ export declare function diffOverview(base: OverviewDocument, next: OverviewDocument): OverviewOverride | null;
40
+ /**
41
+ * The next unused widget id (`w1`, `w2`, ...) given every reserved id.
42
+ *
43
+ * Total for any reserved ids, including hostile stored ones such as
44
+ * `w9007199254740992`: only numeric suffixes that are safe integers below
45
+ * `Number.MAX_SAFE_INTEGER` raise the starting point (beyond it `n + 1` stops
46
+ * changing the number, which would loop forever), and when the high end is
47
+ * exhausted the scan restarts at `w1`. The reserved set is finite, so a free
48
+ * id is found within `size + 1` steps of the restart.
49
+ */
50
+ export declare function nextWidgetId(reserved: Iterable<string>): string;
51
+ export interface SanitizeOptions {
52
+ registry: WidgetRegistry;
53
+ definition: Pick<OverviewDefinition, 'id' | 'allowed' | 'models' | 'maxWidgets'>;
54
+ }
55
+ /**
56
+ * Sanitize a document against the registry and the page's confined set:
57
+ * drops (and reports) unknown types, types the page does not allow or the
58
+ * widget refuses (`allowedIn`), future versions, failed migrations, invalid
59
+ * options, duplicate ids and widgets over the cap; migrates older option
60
+ * versions; clamps spans to the widget's range. Idempotent. Nothing here
61
+ * calls a widget's `load`.
62
+ */
63
+ export declare function sanitizeOverview(document: OverviewDocument, { registry, definition }: SanitizeOptions): {
64
+ document: OverviewDocument;
65
+ issues: OverviewIssue[];
66
+ };
67
+ export interface ResolvedOverview {
68
+ /** The sanitized defaults (the base an override applies to). */
69
+ base: OverviewDocument;
70
+ /** The sanitized document to render. */
71
+ document: OverviewDocument;
72
+ /** The parsed, well-formed override that was applied (or `null`). */
73
+ override: OverviewOverride | null;
74
+ /** Everything dropped or reported along the way. */
75
+ issues: OverviewIssue[];
76
+ /** The subset caused by the override (not by the page's own defaults). */
77
+ overrideIssues: OverviewIssue[];
78
+ }
79
+ /**
80
+ * Resolve an overview: sanitize the page defaults, parse the stored override
81
+ * (untrusted JSON), merge, and sanitize the result. This is the one call a
82
+ * page's server load makes before loading widget data.
83
+ */
84
+ export declare function resolveOverview(definition: OverviewDefinition, override: unknown, registry: WidgetRegistry): ResolvedOverview;
85
+ export type OverviewOverrideCheck = {
86
+ ok: true;
87
+ override: OverviewOverride | null;
88
+ } | {
89
+ ok: false;
90
+ issues: OverviewIssue[];
91
+ };
92
+ /**
93
+ * Validate an override a client wants to save. Strict where load is lenient:
94
+ * any issue rejects the save. On success the returned override is canonical
95
+ * (re-derived from the sanitized result), so persist that, not the input.
96
+ */
97
+ export declare function checkOverviewOverride(definition: OverviewDefinition, input: unknown, registry: WidgetRegistry): OverviewOverrideCheck;
98
+ /** Validate and freeze a page's overview declaration. */
99
+ export declare function defineOverview(definition: OverviewDefinition): OverviewDefinition;
100
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/components/overview/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAML,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAElB,KAAK,gBAAgB,EAGtB,MAAM,YAAY,CAAC;AAmFpB,2EAA2E;AAC3E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG;IACrD,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB,CAiCA;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG;IACrD,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB,CA2DA;AAED,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAQ1E;AAaD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,gBAAgB,EACtB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAChC,gBAAgB,CAsClB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE,gBAAgB,GACrB,gBAAgB,GAAG,IAAI,CAiCzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAgB/D;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,IAAI,CACd,kBAAkB,EAClB,IAAI,GAAG,SAAS,GAAG,QAAQ,GAAG,YAAY,CAC3C,CAAC;CACH;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,gBAAgB,EAC1B,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,eAAe,GACxC;IAAE,QAAQ,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CA6FzD;AAED,MAAM,WAAW,gBAAgB;IAC/B,gEAAgE;IAChE,IAAI,EAAE,gBAAgB,CAAC;IACvB,wCAAwC;IACxC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,qEAAqE;IACrE,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,oDAAoD;IACpD,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,0EAA0E;IAC1E,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,kBAAkB,EAC9B,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,cAAc,GACvB,gBAAgB,CAkBlB;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAA;CAAE,GAC/C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,kBAAkB,EAC9B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,cAAc,GACvB,qBAAqB,CAMvB;AAED,yDAAyD;AACzD,wBAAgB,cAAc,CAC5B,UAAU,EAAE,kBAAkB,GAC7B,kBAAkB,CAiBpB"}