@greensecurity/javascript-sdk 0.46.0-beta.10 → 0.46.0-beta.12

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 (183) hide show
  1. package/dist/commonjs/__tests__/apps/contract.test.js +288 -4
  2. package/dist/commonjs/__tests__/apps/contract.test.js.map +1 -1
  3. package/dist/commonjs/__tests__/apps/devpreview-routes.test.d.ts +2 -0
  4. package/dist/commonjs/__tests__/apps/devpreview-routes.test.d.ts.map +1 -0
  5. package/dist/commonjs/__tests__/apps/devpreview-routes.test.js +86 -0
  6. package/dist/commonjs/__tests__/apps/devpreview-routes.test.js.map +1 -0
  7. package/dist/commonjs/__tests__/apps/kit/example.test.js +84 -4
  8. package/dist/commonjs/__tests__/apps/kit/example.test.js.map +1 -1
  9. package/dist/commonjs/__tests__/apps/kit/pages.test.d.ts +2 -0
  10. package/dist/commonjs/__tests__/apps/kit/pages.test.d.ts.map +1 -0
  11. package/dist/commonjs/__tests__/apps/kit/pages.test.js +119 -0
  12. package/dist/commonjs/__tests__/apps/kit/pages.test.js.map +1 -0
  13. package/dist/commonjs/__tests__/apps/kit/render.test.js +24 -0
  14. package/dist/commonjs/__tests__/apps/kit/render.test.js.map +1 -1
  15. package/dist/commonjs/__tests__/apps/kit/store.test.d.ts +2 -0
  16. package/dist/commonjs/__tests__/apps/kit/store.test.d.ts.map +1 -0
  17. package/dist/commonjs/__tests__/apps/kit/store.test.js +123 -0
  18. package/dist/commonjs/__tests__/apps/kit/store.test.js.map +1 -0
  19. package/dist/commonjs/__tests__/apps/post-install-page.test.d.ts +2 -0
  20. package/dist/commonjs/__tests__/apps/post-install-page.test.d.ts.map +1 -0
  21. package/dist/commonjs/__tests__/apps/post-install-page.test.js +110 -0
  22. package/dist/commonjs/__tests__/apps/post-install-page.test.js.map +1 -0
  23. package/dist/commonjs/__tests__/apps/routes.test.d.ts +2 -0
  24. package/dist/commonjs/__tests__/apps/routes.test.d.ts.map +1 -0
  25. package/dist/commonjs/__tests__/apps/routes.test.js +238 -0
  26. package/dist/commonjs/__tests__/apps/routes.test.js.map +1 -0
  27. package/dist/commonjs/__tests__/vendors.test.js +1 -1
  28. package/dist/commonjs/__tests__/webhooks.test.js +1 -1
  29. package/dist/commonjs/__tests__/webhooks.test.js.map +1 -1
  30. package/dist/commonjs/__tests__/zones.test.js +22 -4
  31. package/dist/commonjs/__tests__/zones.test.js.map +1 -1
  32. package/dist/commonjs/apps/components.d.ts +321 -0
  33. package/dist/commonjs/apps/components.d.ts.map +1 -1
  34. package/dist/commonjs/apps/components.js +168 -2
  35. package/dist/commonjs/apps/components.js.map +1 -1
  36. package/dist/commonjs/apps/context.d.ts +24 -0
  37. package/dist/commonjs/apps/context.d.ts.map +1 -1
  38. package/dist/commonjs/apps/context.js.map +1 -1
  39. package/dist/commonjs/apps/devpreview.d.ts +20 -3
  40. package/dist/commonjs/apps/devpreview.d.ts.map +1 -1
  41. package/dist/commonjs/apps/devpreview.js +18 -7
  42. package/dist/commonjs/apps/devpreview.js.map +1 -1
  43. package/dist/commonjs/apps/hooks/index.d.ts +33 -2
  44. package/dist/commonjs/apps/hooks/index.d.ts.map +1 -1
  45. package/dist/commonjs/apps/hooks/index.js +41 -1
  46. package/dist/commonjs/apps/hooks/index.js.map +1 -1
  47. package/dist/commonjs/apps/hooks/store.d.ts +48 -0
  48. package/dist/commonjs/apps/hooks/store.d.ts.map +1 -0
  49. package/dist/commonjs/apps/hooks/store.js +87 -0
  50. package/dist/commonjs/apps/hooks/store.js.map +1 -0
  51. package/dist/commonjs/apps/manifest.d.ts +64 -3
  52. package/dist/commonjs/apps/manifest.d.ts.map +1 -1
  53. package/dist/commonjs/apps/manifest.js +128 -27
  54. package/dist/commonjs/apps/manifest.js.map +1 -1
  55. package/dist/commonjs/apps/protocol.d.ts +1 -1
  56. package/dist/commonjs/apps/protocol.d.ts.map +1 -1
  57. package/dist/commonjs/apps/route.d.ts +11 -1
  58. package/dist/commonjs/apps/route.d.ts.map +1 -1
  59. package/dist/commonjs/apps/route.js +13 -7
  60. package/dist/commonjs/apps/route.js.map +1 -1
  61. package/dist/commonjs/apps/routes.d.ts +65 -0
  62. package/dist/commonjs/apps/routes.d.ts.map +1 -0
  63. package/dist/commonjs/apps/routes.js +202 -0
  64. package/dist/commonjs/apps/routes.js.map +1 -0
  65. package/dist/commonjs/apps/surfaces.d.ts +20 -2
  66. package/dist/commonjs/apps/surfaces.d.ts.map +1 -1
  67. package/dist/commonjs/apps/surfaces.js +45 -7
  68. package/dist/commonjs/apps/surfaces.js.map +1 -1
  69. package/dist/commonjs/apps/testing/index.d.ts +17 -1
  70. package/dist/commonjs/apps/testing/index.d.ts.map +1 -1
  71. package/dist/commonjs/apps/testing/index.js +50 -1
  72. package/dist/commonjs/apps/testing/index.js.map +1 -1
  73. package/dist/commonjs/apps/ui/index.d.ts +13 -0
  74. package/dist/commonjs/apps/ui/index.d.ts.map +1 -1
  75. package/dist/commonjs/apps/ui/index.js +19 -2
  76. package/dist/commonjs/apps/ui/index.js.map +1 -1
  77. package/dist/commonjs/lib/config.d.ts +2 -2
  78. package/dist/commonjs/lib/config.js +2 -2
  79. package/dist/esm/__tests__/apps/contract.test.js +289 -5
  80. package/dist/esm/__tests__/apps/contract.test.js.map +1 -1
  81. package/dist/esm/__tests__/apps/devpreview-routes.test.d.ts +2 -0
  82. package/dist/esm/__tests__/apps/devpreview-routes.test.d.ts.map +1 -0
  83. package/dist/esm/__tests__/apps/devpreview-routes.test.js +84 -0
  84. package/dist/esm/__tests__/apps/devpreview-routes.test.js.map +1 -0
  85. package/dist/esm/__tests__/apps/kit/example.test.js +85 -5
  86. package/dist/esm/__tests__/apps/kit/example.test.js.map +1 -1
  87. package/dist/esm/__tests__/apps/kit/pages.test.d.ts +2 -0
  88. package/dist/esm/__tests__/apps/kit/pages.test.d.ts.map +1 -0
  89. package/dist/esm/__tests__/apps/kit/pages.test.js +117 -0
  90. package/dist/esm/__tests__/apps/kit/pages.test.js.map +1 -0
  91. package/dist/esm/__tests__/apps/kit/render.test.js +25 -1
  92. package/dist/esm/__tests__/apps/kit/render.test.js.map +1 -1
  93. package/dist/esm/__tests__/apps/kit/store.test.d.ts +2 -0
  94. package/dist/esm/__tests__/apps/kit/store.test.d.ts.map +1 -0
  95. package/dist/esm/__tests__/apps/kit/store.test.js +121 -0
  96. package/dist/esm/__tests__/apps/kit/store.test.js.map +1 -0
  97. package/dist/esm/__tests__/apps/post-install-page.test.d.ts +2 -0
  98. package/dist/esm/__tests__/apps/post-install-page.test.d.ts.map +1 -0
  99. package/dist/esm/__tests__/apps/post-install-page.test.js +108 -0
  100. package/dist/esm/__tests__/apps/post-install-page.test.js.map +1 -0
  101. package/dist/esm/__tests__/apps/routes.test.d.ts +2 -0
  102. package/dist/esm/__tests__/apps/routes.test.d.ts.map +1 -0
  103. package/dist/esm/__tests__/apps/routes.test.js +236 -0
  104. package/dist/esm/__tests__/apps/routes.test.js.map +1 -0
  105. package/dist/esm/__tests__/vendors.test.js +1 -1
  106. package/dist/esm/__tests__/webhooks.test.js +1 -1
  107. package/dist/esm/__tests__/webhooks.test.js.map +1 -1
  108. package/dist/esm/__tests__/zones.test.js +22 -4
  109. package/dist/esm/__tests__/zones.test.js.map +1 -1
  110. package/dist/esm/apps/components.d.ts +321 -0
  111. package/dist/esm/apps/components.d.ts.map +1 -1
  112. package/dist/esm/apps/components.js +163 -1
  113. package/dist/esm/apps/components.js.map +1 -1
  114. package/dist/esm/apps/context.d.ts +24 -0
  115. package/dist/esm/apps/context.d.ts.map +1 -1
  116. package/dist/esm/apps/context.js.map +1 -1
  117. package/dist/esm/apps/devpreview.d.ts +20 -3
  118. package/dist/esm/apps/devpreview.d.ts.map +1 -1
  119. package/dist/esm/apps/devpreview.js +19 -8
  120. package/dist/esm/apps/devpreview.js.map +1 -1
  121. package/dist/esm/apps/hooks/index.d.ts +33 -2
  122. package/dist/esm/apps/hooks/index.d.ts.map +1 -1
  123. package/dist/esm/apps/hooks/index.js +37 -1
  124. package/dist/esm/apps/hooks/index.js.map +1 -1
  125. package/dist/esm/apps/hooks/store.d.ts +48 -0
  126. package/dist/esm/apps/hooks/store.d.ts.map +1 -0
  127. package/dist/esm/apps/hooks/store.js +84 -0
  128. package/dist/esm/apps/hooks/store.js.map +1 -0
  129. package/dist/esm/apps/manifest.d.ts +64 -3
  130. package/dist/esm/apps/manifest.d.ts.map +1 -1
  131. package/dist/esm/apps/manifest.js +116 -26
  132. package/dist/esm/apps/manifest.js.map +1 -1
  133. package/dist/esm/apps/protocol.d.ts +1 -1
  134. package/dist/esm/apps/protocol.d.ts.map +1 -1
  135. package/dist/esm/apps/route.d.ts +11 -1
  136. package/dist/esm/apps/route.d.ts.map +1 -1
  137. package/dist/esm/apps/route.js +14 -8
  138. package/dist/esm/apps/route.js.map +1 -1
  139. package/dist/esm/apps/routes.d.ts +65 -0
  140. package/dist/esm/apps/routes.d.ts.map +1 -0
  141. package/dist/esm/apps/routes.js +194 -0
  142. package/dist/esm/apps/routes.js.map +1 -0
  143. package/dist/esm/apps/surfaces.d.ts +20 -2
  144. package/dist/esm/apps/surfaces.d.ts.map +1 -1
  145. package/dist/esm/apps/surfaces.js +39 -2
  146. package/dist/esm/apps/surfaces.js.map +1 -1
  147. package/dist/esm/apps/testing/index.d.ts +17 -1
  148. package/dist/esm/apps/testing/index.d.ts.map +1 -1
  149. package/dist/esm/apps/testing/index.js +49 -1
  150. package/dist/esm/apps/testing/index.js.map +1 -1
  151. package/dist/esm/apps/ui/index.d.ts +13 -0
  152. package/dist/esm/apps/ui/index.d.ts.map +1 -1
  153. package/dist/esm/apps/ui/index.js +17 -1
  154. package/dist/esm/apps/ui/index.js.map +1 -1
  155. package/dist/esm/lib/config.d.ts +2 -2
  156. package/dist/esm/lib/config.js +2 -2
  157. package/examples/apps/hello-green/src/store.ts +15 -0
  158. package/jsr.json +1 -1
  159. package/package.json +1 -1
  160. package/src/__tests__/apps/contract.test.ts +305 -4
  161. package/src/__tests__/apps/devpreview-routes.test.ts +103 -0
  162. package/src/__tests__/apps/kit/example.test.ts +94 -5
  163. package/src/__tests__/apps/kit/pages.test.ts +137 -0
  164. package/src/__tests__/apps/kit/render.test.ts +35 -1
  165. package/src/__tests__/apps/kit/store.test.ts +149 -0
  166. package/src/__tests__/apps/post-install-page.test.ts +126 -0
  167. package/src/__tests__/apps/routes.test.ts +318 -0
  168. package/src/__tests__/vendors.test.ts +1 -1
  169. package/src/__tests__/webhooks.test.ts +1 -1
  170. package/src/__tests__/zones.test.ts +22 -4
  171. package/src/apps/components.ts +183 -1
  172. package/src/apps/context.ts +25 -0
  173. package/src/apps/devpreview.ts +20 -7
  174. package/src/apps/hooks/index.ts +42 -2
  175. package/src/apps/hooks/store.ts +115 -0
  176. package/src/apps/manifest.ts +151 -27
  177. package/src/apps/protocol.ts +1 -1
  178. package/src/apps/route.ts +22 -10
  179. package/src/apps/routes.ts +230 -0
  180. package/src/apps/surfaces.ts +45 -12
  181. package/src/apps/testing/index.ts +48 -2
  182. package/src/apps/ui/index.ts +18 -1
  183. package/src/lib/config.ts +2 -2
@@ -9,13 +9,21 @@
9
9
  * nodes, and `children`. There are no `ref`, `style` or `className` props, and no render props.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.FormFieldGroup = exports.DateField = exports.Switch = exports.Radio = exports.RadioGroup = exports.Checkbox = exports.SelectOption = exports.Select = exports.TextArea = exports.TextField = exports.TabPanel = exports.TabPanels = exports.Tab = exports.TabList = exports.Tabs = exports.TableCell = exports.TableHeaderCell = exports.TableRow = exports.TableBody = exports.TableHead = exports.Table = exports.PropertyListItem = exports.PropertyList = exports.ListItem = exports.List = exports.AccordionItem = exports.Accordion = exports.MenuItem = exports.MenuGroup = exports.Menu = exports.Link = exports.ButtonGroup = exports.Button = exports.Avatar = exports.Img = exports.Icon = exports.Progress = exports.Spinner = exports.Banner = exports.Badge = exports.Heading = exports.Text = exports.Card = exports.Divider = exports.Inline = exports.Box = exports.SettingsView = exports.ContextView = void 0;
12
+ exports.BarChart = exports.FormFieldGroup = exports.DateField = exports.Switch = exports.Radio = exports.RadioGroup = exports.Checkbox = exports.SelectOption = exports.Select = exports.TextArea = exports.TextField = exports.TabPanel = exports.TabPanels = exports.Tab = exports.TabList = exports.Tabs = exports.TableCell = exports.TableHeaderCell = exports.TableRow = exports.TableBody = exports.TableHead = exports.Table = exports.PropertyListItem = exports.PropertyList = exports.ListItem = exports.List = exports.AccordionItem = exports.Accordion = exports.MenuItem = exports.MenuGroup = exports.Menu = exports.Link = exports.ButtonGroup = exports.Button = exports.Avatar = exports.Img = exports.Icon = exports.Progress = exports.Spinner = exports.Banner = exports.Badge = exports.Heading = exports.Text = exports.Card = exports.Divider = exports.Inline = exports.Box = exports.PageView = exports.SettingsView = exports.ContextView = void 0;
13
+ exports.PieChart = exports.ComboChart = exports.AreaChart = exports.LineChart = exports.StackedBarChart = exports.HorizontalBarChart = void 0;
13
14
  exports.FocusView = FocusView;
14
15
  const react_1 = require("react");
15
16
  const factory_js_1 = require("./factory.js");
16
- // View roots. A view component renders exactly one ContextView or SettingsView at its top.
17
+ // View roots. A view component renders exactly one of these at its top: ContextView on a surface,
18
+ // SettingsView on the settings page, PageView on an app page.
17
19
  exports.ContextView = (0, factory_js_1.createUiComponent)("ContextView");
18
20
  exports.SettingsView = (0, factory_js_1.createUiComponent)("SettingsView");
21
+ /**
22
+ * An app page (`ui_extensions.routes`), full width inside the portal's own chrome. `title` is the
23
+ * page header; the `actions` slot joins the header's actions and `banner` sits above the body.
24
+ * Read the route's params with `usePageRoute()` from `apps/hooks`.
25
+ */
26
+ exports.PageView = (0, factory_js_1.createUiComponent)("PageView");
19
27
  const FocusViewElement = /* @__PURE__ */ (0, factory_js_1.createUiComponent)("FocusView");
20
28
  /**
21
29
  * A full-screen (mobile) or large modal (web) view opened from a ContextView. The app owns
@@ -93,4 +101,13 @@ exports.Radio = (0, factory_js_1.createUiComponent)("Radio");
93
101
  exports.Switch = (0, factory_js_1.createUiComponent)("Switch");
94
102
  exports.DateField = (0, factory_js_1.createUiComponent)("DateField");
95
103
  exports.FormFieldGroup = (0, factory_js_1.createUiComponent)("FormFieldGroup");
104
+ // Charts. Data only: pick a palette with `theme`; `onClick` receives a `ChartClickEvent`
105
+ // (`index`, `label`, `value` and, on multi-series charts, `series`).
106
+ exports.BarChart = (0, factory_js_1.createUiComponent)("BarChart");
107
+ exports.HorizontalBarChart = (0, factory_js_1.createUiComponent)("HorizontalBarChart");
108
+ exports.StackedBarChart = (0, factory_js_1.createUiComponent)("StackedBarChart");
109
+ exports.LineChart = (0, factory_js_1.createUiComponent)("LineChart");
110
+ exports.AreaChart = (0, factory_js_1.createUiComponent)("AreaChart");
111
+ exports.ComboChart = (0, factory_js_1.createUiComponent)("ComboChart");
112
+ exports.PieChart = (0, factory_js_1.createUiComponent)("PieChart");
96
113
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/apps/ui/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/apps/ui/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;AAsCH,8BAaC;AAjDD,iCAAsD;AACtD,6CAA+D;AAI/D,kGAAkG;AAClG,8DAA8D;AACjD,QAAA,WAAW,GAAmB,IAAA,8BAAiB,EAAC,aAAa,CAAC,CAAC;AAC/D,QAAA,YAAY,GAAmB,IAAA,8BAAiB,EAAC,cAAc,CAAC,CAAC;AAC9E;;;;GAIG;AACU,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AAEtE,MAAM,gBAAgB,GAAG,eAAe,CAAC,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAUxE;;;;;;;;;GASG;AACH,SAAgB,SAAS,CAAC,KAAqB;IAC7C,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IACnD,MAAM,SAAS,GAAyB,QAAQ,IAAI,aAAa;QAC/D,CAAC,CAAC;YACA,GAAG,IAAI;YACP,aAAa,EAAE,CAAC,KAAc,EAAE,EAAE;gBAChC,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC;gBACtC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC;gBAClB,OAAO,MAAM,CAAC;YAChB,CAAC;SACF;QACD,CAAC,CAAC,IAAI,CAAC;IACT,OAAO,IAAA,qBAAa,EAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;AACpD,CAAC;AAED,SAAS;AACI,QAAA,GAAG,GAAmB,IAAA,8BAAiB,EAAC,KAAK,CAAC,CAAC;AAC/C,QAAA,MAAM,GAAmB,IAAA,8BAAiB,EAAC,QAAQ,CAAC,CAAC;AACrD,QAAA,OAAO,GAAmB,IAAA,8BAAiB,EAAC,SAAS,CAAC,CAAC;AACvD,QAAA,IAAI,GAAmB,IAAA,8BAAiB,EAAC,MAAM,CAAC,CAAC;AAE9D,kBAAkB;AACL,QAAA,IAAI,GAAmB,IAAA,8BAAiB,EAAC,MAAM,CAAC,CAAC;AACjD,QAAA,OAAO,GAAmB,IAAA,8BAAiB,EAAC,SAAS,CAAC,CAAC;AACvD,QAAA,KAAK,GAAmB,IAAA,8BAAiB,EAAC,OAAO,CAAC,CAAC;AACnD,QAAA,MAAM,GAAmB,IAAA,8BAAiB,EAAC,QAAQ,CAAC,CAAC;AACrD,QAAA,OAAO,GAAmB,IAAA,8BAAiB,EAAC,SAAS,CAAC,CAAC;AACvD,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AACzD,QAAA,IAAI,GAAmB,IAAA,8BAAiB,EAAC,MAAM,CAAC,CAAC;AACjD,QAAA,GAAG,GAAmB,IAAA,8BAAiB,EAAC,KAAK,CAAC,CAAC;AAC/C,QAAA,MAAM,GAAmB,IAAA,8BAAiB,EAAC,QAAQ,CAAC,CAAC;AAElE,UAAU;AACG,QAAA,MAAM,GAAmB,IAAA,8BAAiB,EAAC,QAAQ,CAAC,CAAC;AACrD,QAAA,WAAW,GAAmB,IAAA,8BAAiB,EAAC,aAAa,CAAC,CAAC;AAC/D,QAAA,IAAI,GAAmB,IAAA,8BAAiB,EAAC,MAAM,CAAC,CAAC;AACjD,QAAA,IAAI,GAAmB,IAAA,8BAAiB,EAAC,MAAM,CAAC,CAAC;AACjD,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AAEtE,UAAU;AACG,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,aAAa,GAAmB,IAAA,8BAAiB,EAAC,eAAe,CAAC,CAAC;AACnE,QAAA,IAAI,GAAmB,IAAA,8BAAiB,EAAC,MAAM,CAAC,CAAC;AACjD,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AACzD,QAAA,YAAY,GAAmB,IAAA,8BAAiB,EAAC,cAAc,CAAC,CAAC;AACjE,QAAA,gBAAgB,GAAmB,IAAA,8BAAiB,EAAC,kBAAkB,CAAC,CAAC;AACzE,QAAA,KAAK,GAAmB,IAAA,8BAAiB,EAAC,OAAO,CAAC,CAAC;AACnD,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AACzD,QAAA,eAAe,GAAmB,IAAA,8BAAiB,EAAC,iBAAiB,CAAC,CAAC;AACvE,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,IAAI,GAAmB,IAAA,8BAAiB,EAAC,MAAM,CAAC,CAAC;AACjD,QAAA,OAAO,GAAmB,IAAA,8BAAiB,EAAC,SAAS,CAAC,CAAC;AACvD,QAAA,GAAG,GAAmB,IAAA,8BAAiB,EAAC,KAAK,CAAC,CAAC;AAC/C,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AAEtE,uFAAuF;AACvF,0DAA0D;AAC7C,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AACzD,QAAA,MAAM,GAAmB,IAAA,8BAAiB,EAAC,QAAQ,CAAC,CAAC;AACrD,QAAA,YAAY,GAAmB,IAAA,8BAAiB,EAAC,cAAc,CAAC,CAAC;AACjE,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AACzD,QAAA,UAAU,GAAmB,IAAA,8BAAiB,EAAC,YAAY,CAAC,CAAC;AAC7D,QAAA,KAAK,GAAmB,IAAA,8BAAiB,EAAC,OAAO,CAAC,CAAC;AACnD,QAAA,MAAM,GAAmB,IAAA,8BAAiB,EAAC,QAAQ,CAAC,CAAC;AACrD,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,cAAc,GAAmB,IAAA,8BAAiB,EAAC,gBAAgB,CAAC,CAAC;AAElF,yFAAyF;AACzF,qEAAqE;AACxD,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;AACzD,QAAA,kBAAkB,GAAmB,IAAA,8BAAiB,EAAC,oBAAoB,CAAC,CAAC;AAC7E,QAAA,eAAe,GAAmB,IAAA,8BAAiB,EAAC,iBAAiB,CAAC,CAAC;AACvE,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,SAAS,GAAmB,IAAA,8BAAiB,EAAC,WAAW,CAAC,CAAC;AAC3D,QAAA,UAAU,GAAmB,IAAA,8BAAiB,EAAC,YAAY,CAAC,CAAC;AAC7D,QAAA,QAAQ,GAAmB,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC"}
@@ -35,8 +35,8 @@ export declare function serverURLFromOptions(options: SDKOptions): URL | null;
35
35
  export declare const SDK_METADATA: {
36
36
  readonly language: "typescript";
37
37
  readonly openapiDocVersion: "0.45.0";
38
- readonly sdkVersion: "0.46.0-beta.10";
38
+ readonly sdkVersion: "0.46.0-beta.12";
39
39
  readonly genVersion: "2.943.0";
40
- readonly userAgent: "speakeasy-sdk/typescript 0.46.0-beta.10 2.943.0 0.45.0 @greensecurity/javascript-sdk";
40
+ readonly userAgent: "speakeasy-sdk/typescript 0.46.0-beta.12 2.943.0 0.45.0 @greensecurity/javascript-sdk";
41
41
  };
42
42
  //# sourceMappingURL=config.d.ts.map
@@ -43,8 +43,8 @@ function serverURLFromOptions(options) {
43
43
  exports.SDK_METADATA = {
44
44
  language: "typescript",
45
45
  openapiDocVersion: "0.45.0",
46
- sdkVersion: "0.46.0-beta.10",
46
+ sdkVersion: "0.46.0-beta.12",
47
47
  genVersion: "2.943.0",
48
- userAgent: "speakeasy-sdk/typescript 0.46.0-beta.10 2.943.0 0.45.0 @greensecurity/javascript-sdk",
48
+ userAgent: "speakeasy-sdk/typescript 0.46.0-beta.12 2.943.0 0.45.0 @greensecurity/javascript-sdk",
49
49
  };
50
50
  //# sourceMappingURL=config.js.map
@@ -8,7 +8,7 @@
8
8
  import { readFileSync, writeFileSync } from "node:fs";
9
9
  import { resolve } from "node:path";
10
10
  import { describe, expect, test } from "vitest";
11
- import { canonicalBuildPayload, APP_WEBHOOK_EVENTS, COMPONENTS, componentsCatalogJson, CSP_DENYLIST, cspDenylistEntry, DATA_IMAGE_MAX_CHARS, DEV_SIGNATURE_ALGORITHM, DevManifestError, effectivePostInstallAction, devManifestSchema, getComponentByTag, getSurface, isBootstrapToHost, isCalendarDate, isPlatformPermission, isRouteDescriptor, isSensitivePermission, isSurfaceId, manifestJsonSchema, mergeDevManifest, permissionReviewIssues, PLATFORM_PERMISSIONS, REVIEW_RULES, SAFE_INTEGER_STRING_PATTERN, sanitizeProps, SURFACES, surfacesForPortal, tokenNeedsRefresh, validateManifest, } from "../../apps/index.js";
11
+ import { canonicalBuildPayload, APP_WEBHOOK_EVENTS, CHART_DATA_LIMITS, CHART_THEMES, COMPONENTS, componentsCatalogJson, CSP_DENYLIST, cspDenylistEntry, DATA_IMAGE_MAX_CHARS, DEV_SIGNATURE_ALGORITHM, DevManifestError, effectivePostInstallAction, devManifestSchema, getComponentByTag, getSurface, isBootstrapToHost, isCalendarDate, isChartData, isPieChartData, CHART_OTHER_LABEL, MAX_CHART_VALUE, isComboChartData, isPlatformPermission, isRouteDescriptor, isSensitivePermission, isSeriesChartData, isSurfaceId, manifestJsonSchema, MAX_CHART_SERIES, mergeDevManifest, permissionReviewIssues, PLATFORM_PERMISSIONS, REVIEW_RULES, SAFE_INTEGER_STRING_PATTERN, sanitizeProps, SURFACES, surfacesForPortal, tokenNeedsRefresh, validateManifest, } from "../../apps/index.js";
12
12
  // Resolved from the package root (vitest's cwd) rather than `import.meta.url`: Speakeasy also
13
13
  // compiles this file to CommonJS, where `import.meta` is a type error (TS1470).
14
14
  const SHARED_DIR = resolve(process.cwd(), "..", "shared", "app-platform");
@@ -46,7 +46,7 @@ describe("surfaces", () => {
46
46
  const ids = SURFACES.map((s) => s.id);
47
47
  expect(new Set(ids).size).toBe(ids.length);
48
48
  for (const s of SURFACES) {
49
- if (s.id === "settings")
49
+ if (s.portal === null)
50
50
  continue;
51
51
  expect(s.id).toMatch(/^gs\.(vendor|company|facility|system)\.[a-z_]+(\.[a-z_]+)*$/);
52
52
  expect(s.id.startsWith(`gs.${s.portal}.`)).toBe(true);
@@ -58,6 +58,10 @@ describe("surfaces", () => {
58
58
  expect(s.route.startsWith(s.portal === null ? "/[portal]/" : `/${s.portal}`)).toBe(true);
59
59
  }
60
60
  expect(getSurface("settings")?.route).toBe("/[portal]/apps/[appId]/settings");
61
+ expect(getSurface("page")?.route).toBe("/[portal]/apps/[appId]/pages/[...path]");
62
+ });
63
+ test("the only portal-less surfaces are the app's own settings page and pages", () => {
64
+ expect(SURFACES.filter((s) => s.portal === null).map((s) => s.id).sort()).toEqual(["page", "settings"]);
61
65
  });
62
66
  test("wave 1 is the vendor and company portals only", () => {
63
67
  const wave1Portals = new Set(SURFACES.filter((s) => s.wave === 1).map((s) => s.portal));
@@ -393,9 +397,17 @@ describe("components", () => {
393
397
  expect(COMPONENTS.Inline.children).toEqual(["ui-inline", "ui-link"]);
394
398
  expect(COMPONENTS.Text.children).toEqual(["ui-inline", "ui-link"]);
395
399
  });
396
- test("only ContextView and SettingsView are roots", () => {
400
+ test("only ContextView, SettingsView and PageView are roots", () => {
397
401
  const roots = Object.entries(COMPONENTS).filter(([, c]) => "root" in c).map(([name]) => name);
398
- expect(roots.sort()).toEqual(["ContextView", "SettingsView"]);
402
+ expect(roots.sort()).toEqual(["ContextView", "PageView", "SettingsView"]);
403
+ });
404
+ test("PageView takes a required title, a description and the actions and banner slots", () => {
405
+ expect(COMPONENTS.PageView.tagName).toBe("ui-page-view");
406
+ expect(COMPONENTS.PageView.slots).toEqual(["actions", "banner"]);
407
+ expect(sanitizeProps("ui-page-view", { title: "Reports", description: "All of them" }).props).toEqual({ title: "Reports", description: "All of them" });
408
+ expect(sanitizeProps("ui-page-view", { title: "t".repeat(101) }).dropped).toEqual(["title"]);
409
+ expect(sanitizeProps("ui-page-view", { title: "Reports", description: "d".repeat(301) }).dropped).toEqual(["description"]);
410
+ expect(componentsCatalogJson().find((c) => c.name === "PageView")).toMatchObject({ tagName: "ui-page-view", root: true });
399
411
  });
400
412
  test("sanitizeProps keeps declared props of the right type and drops everything else", () => {
401
413
  const result = sanitizeProps("ui-button", {
@@ -566,6 +578,278 @@ describe("components", () => {
566
578
  expect(() => JSON.stringify(json)).not.toThrow();
567
579
  });
568
580
  });
581
+ describe("charts", () => {
582
+ const CHART_TAGS = {
583
+ BarChart: "ui-bar-chart",
584
+ HorizontalBarChart: "ui-horizontal-bar-chart",
585
+ StackedBarChart: "ui-stacked-bar-chart",
586
+ LineChart: "ui-line-chart",
587
+ AreaChart: "ui-area-chart",
588
+ ComboChart: "ui-combo-chart",
589
+ PieChart: "ui-pie-chart",
590
+ };
591
+ const labels = (n) => Array.from({ length: n }, (_, i) => `L${i}`);
592
+ const datums = (n) => labels(n).map((label, i) => ({ label, value: i }));
593
+ const seriesData = (nLabels, nSeries = 2) => ({
594
+ labels: labels(nLabels),
595
+ series: Array.from({ length: nSeries }, (_, s) => ({ name: `S${s}`, values: labels(nLabels).map((_, i) => i + s) })),
596
+ });
597
+ const combo = (n) => ({
598
+ labels: labels(n),
599
+ bars: { name: "Visits", values: labels(n).map((_, i) => i) },
600
+ line: { name: "Average", values: labels(n).map((_, i) => i / 2) },
601
+ });
602
+ const BAD_VALUES = [-1, Number.NaN, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, "3", null];
603
+ const BAD_LABELS = ["", " ", "x".repeat(61), 5, null];
604
+ class Datum {
605
+ constructor(label, value) {
606
+ this.label = label;
607
+ this.value = value;
608
+ }
609
+ }
610
+ class DatumArray extends Array {
611
+ }
612
+ test("seven chart entries with the same data-only props, a click event and no children", () => {
613
+ for (const [name, tag] of Object.entries(CHART_TAGS)) {
614
+ const c = COMPONENTS[name];
615
+ expect(c.tagName, name).toBe(tag);
616
+ expect(Object.keys(c.props).sort(), name).toEqual(["data", "interactive", "theme"]);
617
+ expect(c.events, name).toEqual({ onClick: { event: "click" } });
618
+ expect(c.children, name).toEqual([]);
619
+ expect(c.text, name).toBe(false);
620
+ expect(c.slots, name).toEqual([]);
621
+ const json = componentsCatalogJson().find((j) => j.name === name);
622
+ expect(json.props["data"]).toEqual({ type: "json", required: true });
623
+ expect(json.props["theme"]).toEqual({ type: "enum", required: false, values: ["green", "grayscale", "vibrant"] });
624
+ expect(json.events).toEqual({ onClick: "click" });
625
+ }
626
+ expect(CHART_THEMES).toEqual(["green", "grayscale", "vibrant"]);
627
+ expect(MAX_CHART_SERIES).toBe(6);
628
+ });
629
+ test("sanitizeProps requires data, checks theme and drops styling props", () => {
630
+ expect(sanitizeProps("ui-bar-chart", { theme: "green" }).missing).toEqual(["data"]);
631
+ const result = sanitizeProps("ui-bar-chart", { data: datums(3), theme: "neon", interactive: true, color: "#f00", style: {} });
632
+ expect(result.props).toEqual({ data: datums(3), interactive: true });
633
+ expect(result.dropped.sort()).toEqual(["color", "style", "theme"]);
634
+ expect(result.missing).toEqual([]);
635
+ const bad = sanitizeProps("ui-line-chart", { data: seriesData(1) });
636
+ expect(bad.dropped).toEqual(["data"]);
637
+ expect(bad.missing).toEqual(["data"]);
638
+ });
639
+ describe("chart value bounds", () => {
640
+ test("accepts values up to MAX_CHART_VALUE and rejects larger ones", () => {
641
+ const bar = CHART_DATA_LIMITS.BarChart;
642
+ expect(isChartData([{ label: "a", value: MAX_CHART_VALUE }], bar)).toBe(true);
643
+ for (const value of [MAX_CHART_VALUE + 2, 1e308, Number.MAX_VALUE]) {
644
+ expect(isChartData([{ label: "a", value }], bar)).toBe(false);
645
+ }
646
+ });
647
+ test("keeps every accepted total finite", () => {
648
+ const pie = Array.from({ length: 50 }, (_, i) => ({ label: `s${i}`, value: MAX_CHART_VALUE }));
649
+ expect(isPieChartData(pie)).toBe(true);
650
+ expect(Number.isFinite(pie.reduce((sum, d) => sum + d.value, 0))).toBe(true);
651
+ const limits = CHART_DATA_LIMITS.StackedBarChart;
652
+ const series = Array.from({ length: 6 }, (_, i) => ({ name: `s${i}`, values: [MAX_CHART_VALUE] }));
653
+ expect(isSeriesChartData({ labels: ["a"], series }, limits)).toBe(true);
654
+ const huge = [{ name: "x", values: [1e308] }, { name: "y", values: [1e308] }];
655
+ expect(isSeriesChartData({ labels: ["a"], series: huge }, limits)).toBe(false);
656
+ });
657
+ });
658
+ describe("isPieChartData", () => {
659
+ const datums = (n, first) => Array.from({ length: n }, (_, i) => ({ label: i === 0 && first !== undefined ? first : `s${i}`, value: i + 1 }));
660
+ test("allows an Other label when the pie will not combine slices", () => {
661
+ expect(isPieChartData(datums(6, CHART_OTHER_LABEL))).toBe(true);
662
+ });
663
+ test("rejects a caller Other label when extra items will be combined into Other", () => {
664
+ for (const label of [CHART_OTHER_LABEL, "other", " OTHER "])
665
+ expect(isPieChartData(datums(7, label))).toBe(false);
666
+ expect(isPieChartData(datums(7, "Other documents"))).toBe(true);
667
+ });
668
+ test("keeps the generic pie limits", () => {
669
+ expect(isPieChartData(datums(50))).toBe(true);
670
+ expect(isPieChartData(datums(51))).toBe(false);
671
+ expect(isPieChartData([])).toBe(false);
672
+ });
673
+ test("is the guard the PieChart catalog entry uses", () => {
674
+ expect(sanitizeProps("ui-pie-chart", { data: datums(7, "Other") }).missing).toContain("data");
675
+ expect(sanitizeProps("ui-pie-chart", { data: datums(7) }).missing).not.toContain("data");
676
+ });
677
+ });
678
+ describe("isChartData", () => {
679
+ const bar = CHART_DATA_LIMITS.BarChart;
680
+ test("accepts a valid sample, including zero values and 60-character labels", () => {
681
+ expect(isChartData([{ label: "Mon", value: 0 }, { label: "x".repeat(60), value: 12.5 }], bar)).toBe(true);
682
+ });
683
+ test.each(BAD_VALUES)("rejects value %s", (value) => {
684
+ expect(isChartData([{ label: "a", value }], bar)).toBe(false);
685
+ });
686
+ test.each(BAD_LABELS)("rejects label %j", (label) => {
687
+ expect(isChartData([{ label, value: 1 }], bar)).toBe(false);
688
+ });
689
+ test("rejects duplicate labels", () => {
690
+ expect(isChartData([{ label: "a", value: 1 }, { label: "a", value: 2 }], bar)).toBe(false);
691
+ });
692
+ test("enforces each component's item counts", () => {
693
+ expect(isChartData([], bar)).toBe(false);
694
+ expect(isChartData(datums(31), bar)).toBe(true);
695
+ expect(isChartData(datums(32), bar)).toBe(false);
696
+ expect(isChartData(datums(25), CHART_DATA_LIMITS.HorizontalBarChart)).toBe(true);
697
+ expect(isChartData(datums(26), CHART_DATA_LIMITS.HorizontalBarChart)).toBe(false);
698
+ expect(isChartData(datums(50), CHART_DATA_LIMITS.PieChart)).toBe(true);
699
+ expect(isChartData(datums(51), CHART_DATA_LIMITS.PieChart)).toBe(false);
700
+ expect(sanitizeProps("ui-bar-chart", { data: datums(32) }).dropped).toEqual(["data"]);
701
+ expect(sanitizeProps("ui-pie-chart", { data: datums(32) }).dropped).toEqual([]);
702
+ });
703
+ test("rejects non-arrays, class instances, sparse arrays and extra keys", () => {
704
+ for (const v of [undefined, null, "a", 1, { label: "a", value: 1 }, new Map()])
705
+ expect(isChartData(v, bar)).toBe(false);
706
+ expect(isChartData([new Datum("a", 1)], bar)).toBe(false);
707
+ expect(isChartData(DatumArray.from([{ label: "a", value: 1 }]), bar)).toBe(false);
708
+ // eslint-disable-next-line no-sparse-arrays
709
+ expect(isChartData([{ label: "a", value: 1 }, , { label: "b", value: 2 }], bar)).toBe(false);
710
+ expect(isChartData([{ label: "a", value: 1, color: "red" }], bar)).toBe(false);
711
+ expect(isChartData([Object.assign(Object.create(null), { label: "a", value: 1 })], bar)).toBe(true);
712
+ });
713
+ });
714
+ describe("isSeriesChartData", () => {
715
+ const stacked = CHART_DATA_LIMITS.StackedBarChart;
716
+ const line = CHART_DATA_LIMITS.LineChart;
717
+ test("accepts a valid sample", () => {
718
+ expect(isSeriesChartData(seriesData(5, 3), stacked)).toBe(true);
719
+ expect(isSeriesChartData(seriesData(5, MAX_CHART_SERIES), line)).toBe(true);
720
+ });
721
+ test("rejects more than six series, and no series", () => {
722
+ expect(isSeriesChartData(seriesData(5, MAX_CHART_SERIES + 1), stacked)).toBe(false);
723
+ expect(isSeriesChartData(seriesData(5, MAX_CHART_SERIES + 1), line)).toBe(false);
724
+ expect(isSeriesChartData(seriesData(5, 0), stacked)).toBe(false);
725
+ });
726
+ test("rejects a series whose values length differs from the labels", () => {
727
+ const d = seriesData(4);
728
+ d.series[1].values.pop();
729
+ expect(isSeriesChartData(d, stacked)).toBe(false);
730
+ d.series[1].values.push(1, 2);
731
+ expect(isSeriesChartData(d, stacked)).toBe(false);
732
+ });
733
+ test.each(BAD_VALUES)("rejects value %s", (value) => {
734
+ const d = seriesData(3);
735
+ d.series[0].values[1] = value;
736
+ expect(isSeriesChartData(d, stacked)).toBe(false);
737
+ });
738
+ test.each(BAD_LABELS)("rejects label or series name %j", (bad) => {
739
+ const withLabel = seriesData(3);
740
+ withLabel.labels[0] = bad;
741
+ expect(isSeriesChartData(withLabel, stacked)).toBe(false);
742
+ const withName = seriesData(3);
743
+ withName.series[0].name = bad;
744
+ expect(isSeriesChartData(withName, stacked)).toBe(false);
745
+ });
746
+ test("rejects duplicate labels and duplicate series names", () => {
747
+ const dupLabel = seriesData(3);
748
+ dupLabel.labels[2] = dupLabel.labels[0];
749
+ expect(isSeriesChartData(dupLabel, stacked)).toBe(false);
750
+ const dupName = seriesData(3);
751
+ dupName.series[1].name = dupName.series[0].name;
752
+ expect(isSeriesChartData(dupName, stacked)).toBe(false);
753
+ });
754
+ test("enforces each component's label counts", () => {
755
+ expect(isSeriesChartData(seriesData(1), stacked)).toBe(true);
756
+ expect(isSeriesChartData(seriesData(31), stacked)).toBe(true);
757
+ expect(isSeriesChartData(seriesData(32), stacked)).toBe(false);
758
+ expect(isSeriesChartData(seriesData(1), line)).toBe(false);
759
+ expect(isSeriesChartData(seriesData(60), line)).toBe(true);
760
+ expect(isSeriesChartData(seriesData(61), line)).toBe(false);
761
+ expect(isSeriesChartData(seriesData(61), CHART_DATA_LIMITS.AreaChart)).toBe(false);
762
+ expect(isSeriesChartData(seriesData(1), CHART_DATA_LIMITS.AreaChart)).toBe(false);
763
+ });
764
+ test("rejects non-objects, class instances and extra keys", () => {
765
+ for (const v of [undefined, null, [], "x", datums(3)])
766
+ expect(isSeriesChartData(v, stacked)).toBe(false);
767
+ const d = seriesData(2);
768
+ expect(isSeriesChartData({ labels: d.labels, series: DatumArray.from(d.series) }, stacked)).toBe(false);
769
+ expect(isSeriesChartData({ ...d, labels: DatumArray.from(d.labels) }, stacked)).toBe(false);
770
+ expect(isSeriesChartData(Object.assign(new (class Data {
771
+ })(), d), stacked)).toBe(false);
772
+ expect(isSeriesChartData({ ...d, title: "x" }, stacked)).toBe(false);
773
+ expect(isSeriesChartData({ ...d, series: [{ ...d.series[0], color: "red" }] }, stacked)).toBe(false);
774
+ });
775
+ });
776
+ describe("isComboChartData", () => {
777
+ const limits = CHART_DATA_LIMITS.ComboChart;
778
+ test("accepts a valid sample", () => {
779
+ expect(isComboChartData(combo(1), limits)).toBe(true);
780
+ expect(isComboChartData(combo(31), limits)).toBe(true);
781
+ });
782
+ test("rejects over-cap and empty labels", () => {
783
+ expect(isComboChartData(combo(32), limits)).toBe(false);
784
+ expect(isComboChartData(combo(0), limits)).toBe(false);
785
+ });
786
+ test("rejects bars or line values whose length differs from the labels", () => {
787
+ const bars = combo(3);
788
+ bars.bars.values.pop();
789
+ expect(isComboChartData(bars, limits)).toBe(false);
790
+ const line = combo(3);
791
+ line.line.values.push(1);
792
+ expect(isComboChartData(line, limits)).toBe(false);
793
+ });
794
+ test.each(BAD_VALUES)("rejects value %s", (value) => {
795
+ for (const key of ["bars", "line"]) {
796
+ const d = combo(3);
797
+ d[key].values[0] = value;
798
+ expect(isComboChartData(d, limits)).toBe(false);
799
+ }
800
+ });
801
+ test.each(BAD_LABELS)("rejects label or series name %j", (bad) => {
802
+ const withLabel = combo(3);
803
+ withLabel.labels[1] = bad;
804
+ expect(isComboChartData(withLabel, limits)).toBe(false);
805
+ const withName = combo(3);
806
+ withName.line.name = bad;
807
+ expect(isComboChartData(withName, limits)).toBe(false);
808
+ });
809
+ test("rejects duplicate labels and a line named like the bars", () => {
810
+ const dupLabel = combo(3);
811
+ dupLabel.labels[1] = dupLabel.labels[0];
812
+ expect(isComboChartData(dupLabel, limits)).toBe(false);
813
+ const dupName = combo(3);
814
+ dupName.line.name = dupName.bars.name;
815
+ expect(isComboChartData(dupName, limits)).toBe(false);
816
+ });
817
+ test("rejects non-objects, class instances, series arrays and extra keys", () => {
818
+ for (const v of [undefined, null, [], "x", seriesData(3)])
819
+ expect(isComboChartData(v, limits)).toBe(false);
820
+ const d = combo(2);
821
+ expect(isComboChartData({ ...d, bars: [d.bars] }, limits)).toBe(false);
822
+ expect(isComboChartData({ ...d, labels: DatumArray.from(d.labels) }, limits)).toBe(false);
823
+ expect(isComboChartData(Object.assign(new (class Data {
824
+ })(), d), limits)).toBe(false);
825
+ expect(isComboChartData({ ...d, extra: 1 }, limits)).toBe(false);
826
+ });
827
+ });
828
+ test("ComponentProps types chart data and the click detail (compile-time)", () => {
829
+ const bar = {
830
+ data: [{ label: "Mon", value: 3 }],
831
+ theme: "vibrant",
832
+ interactive: true,
833
+ onClick: (e) => e.index + e.value + e.label.length,
834
+ };
835
+ const comboProps = {
836
+ data: combo(2),
837
+ onClick: (e) => e.series ?? e.label,
838
+ };
839
+ const stacked = { data: seriesData(2) };
840
+ // @ts-expect-error data is required
841
+ const noData = { theme: "green" };
842
+ // @ts-expect-error a bar chart takes ChartDatum[], not series data
843
+ const wrongShape = { data: seriesData(2) };
844
+ // @ts-expect-error themes are a closed set
845
+ const neon = { data: datums(2), theme: "neon" };
846
+ // @ts-expect-error there are no colour props
847
+ const colored = { data: seriesData(2), colors: ["#f00"] };
848
+ // @ts-expect-error onClick receives a ChartClickEvent, not a string
849
+ const wrongDetail = { data: combo(2), onClick: (s) => s.length };
850
+ expect([bar, comboProps, stacked, noData, wrongShape, neon, colored, wrongDetail]).toHaveLength(8);
851
+ });
852
+ });
569
853
  describe("protocol and helpers", () => {
570
854
  test("isBootstrapToHost accepts known envelopes only", () => {
571
855
  expect(isBootstrapToHost({ kind: "ready" })).toBe(true);
@@ -620,7 +904,7 @@ describe("protocol and helpers", () => {
620
904
  describe("bundle hygiene", () => {
621
905
  // The host renderer imports these; a value import of zod (directly or via manifest.ts or
622
906
  // devpreview.ts) would pull zod into the host app bundle. Type-only imports are erased.
623
- test.each(["surfaces.ts", "route.ts", "context.ts", "protocol.ts", "components.ts", "url.ts", "devsession.ts", "review.ts"])("%s has no value import of zod, manifest.ts or devpreview.ts", (file) => {
907
+ test.each(["surfaces.ts", "route.ts", "routes.ts", "context.ts", "protocol.ts", "components.ts", "url.ts", "devsession.ts", "review.ts"])("%s has no value import of zod, manifest.ts or devpreview.ts", (file) => {
624
908
  const source = readFileSync(resolve(process.cwd(), "src", "apps", file), "utf8");
625
909
  const valueImports = source.match(/^import (?!type )[^;]*from "[^"]+";/gm) ?? [];
626
910
  for (const line of valueImports)